Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/zink/zink_surface.c
4570 views
1
/*
2
* Copyright 2018 Collabora Ltd.
3
*
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
* copy of this software and associated documentation files (the "Software"),
6
* to deal in the Software without restriction, including without limitation
7
* on the rights to use, copy, modify, merge, publish, distribute, sub
8
* license, and/or sell copies of the Software, and to permit persons to whom
9
* the Software is furnished to do so, subject to the following conditions:
10
*
11
* The above copyright notice and this permission notice (including the next
12
* paragraph) shall be included in all copies or substantial portions of the
13
* Software.
14
*
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21
* USE OR OTHER DEALINGS IN THE SOFTWARE.
22
*/
23
24
#include "zink_context.h"
25
#include "zink_framebuffer.h"
26
#include "zink_resource.h"
27
#include "zink_screen.h"
28
#include "zink_surface.h"
29
30
#include "util/format/u_format.h"
31
#include "util/u_inlines.h"
32
#include "util/u_memory.h"
33
34
VkImageViewCreateInfo
35
create_ivci(struct zink_screen *screen,
36
struct zink_resource *res,
37
const struct pipe_surface *templ,
38
enum pipe_texture_target target)
39
{
40
VkImageViewCreateInfo ivci = {0};
41
ivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
42
ivci.image = res->obj->image;
43
44
switch (target) {
45
case PIPE_TEXTURE_1D:
46
ivci.viewType = VK_IMAGE_VIEW_TYPE_1D;
47
break;
48
49
case PIPE_TEXTURE_1D_ARRAY:
50
ivci.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
51
break;
52
53
case PIPE_TEXTURE_2D:
54
case PIPE_TEXTURE_RECT:
55
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
56
break;
57
58
case PIPE_TEXTURE_2D_ARRAY:
59
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
60
break;
61
62
case PIPE_TEXTURE_CUBE:
63
ivci.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
64
break;
65
66
case PIPE_TEXTURE_CUBE_ARRAY:
67
ivci.viewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
68
break;
69
70
case PIPE_TEXTURE_3D:
71
ivci.viewType = VK_IMAGE_VIEW_TYPE_3D;
72
break;
73
74
default:
75
unreachable("unsupported target");
76
}
77
78
ivci.format = zink_get_format(screen, templ->format);
79
assert(ivci.format != VK_FORMAT_UNDEFINED);
80
81
// TODO: format swizzles
82
ivci.components.r = VK_COMPONENT_SWIZZLE_R;
83
ivci.components.g = VK_COMPONENT_SWIZZLE_G;
84
ivci.components.b = VK_COMPONENT_SWIZZLE_B;
85
ivci.components.a = VK_COMPONENT_SWIZZLE_A;
86
87
ivci.subresourceRange.aspectMask = res->aspect;
88
ivci.subresourceRange.baseMipLevel = templ->u.tex.level;
89
ivci.subresourceRange.levelCount = 1;
90
ivci.subresourceRange.baseArrayLayer = templ->u.tex.first_layer;
91
ivci.subresourceRange.layerCount = 1 + templ->u.tex.last_layer - templ->u.tex.first_layer;
92
ivci.viewType = zink_surface_clamp_viewtype(ivci.viewType, templ->u.tex.first_layer, templ->u.tex.last_layer, res->base.b.array_size);
93
94
return ivci;
95
}
96
97
static struct zink_surface *
98
create_surface(struct pipe_context *pctx,
99
struct pipe_resource *pres,
100
const struct pipe_surface *templ,
101
VkImageViewCreateInfo *ivci)
102
{
103
struct zink_screen *screen = zink_screen(pctx->screen);
104
unsigned int level = templ->u.tex.level;
105
106
struct zink_surface *surface = CALLOC_STRUCT(zink_surface);
107
if (!surface)
108
return NULL;
109
110
pipe_resource_reference(&surface->base.texture, pres);
111
pipe_reference_init(&surface->base.reference, 1);
112
surface->base.context = pctx;
113
surface->base.format = templ->format;
114
surface->base.width = u_minify(pres->width0, level);
115
surface->base.height = u_minify(pres->height0, level);
116
surface->base.nr_samples = templ->nr_samples;
117
surface->base.u.tex.level = level;
118
surface->base.u.tex.first_layer = templ->u.tex.first_layer;
119
surface->base.u.tex.last_layer = templ->u.tex.last_layer;
120
surface->obj = zink_resource(pres)->obj;
121
util_dynarray_init(&surface->framebuffer_refs, NULL);
122
util_dynarray_init(&surface->desc_set_refs.refs, NULL);
123
124
if (vkCreateImageView(screen->dev, ivci, NULL,
125
&surface->image_view) != VK_SUCCESS) {
126
FREE(surface);
127
return NULL;
128
}
129
130
return surface;
131
}
132
133
static uint32_t
134
hash_ivci(const void *key)
135
{
136
return _mesa_hash_data((char*)key + offsetof(VkImageViewCreateInfo, flags), sizeof(VkImageViewCreateInfo) - offsetof(VkImageViewCreateInfo, flags));
137
}
138
139
struct pipe_surface *
140
zink_get_surface(struct zink_context *ctx,
141
struct pipe_resource *pres,
142
const struct pipe_surface *templ,
143
VkImageViewCreateInfo *ivci)
144
{
145
struct zink_screen *screen = zink_screen(ctx->base.screen);
146
struct zink_surface *surface = NULL;
147
uint32_t hash = hash_ivci(ivci);
148
149
simple_mtx_lock(&screen->surface_mtx);
150
struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(&screen->surface_cache, hash, ivci);
151
152
if (!entry) {
153
/* create a new surface */
154
surface = create_surface(&ctx->base, pres, templ, ivci);
155
surface->hash = hash;
156
surface->ivci = *ivci;
157
entry = _mesa_hash_table_insert_pre_hashed(&screen->surface_cache, hash, &surface->ivci, surface);
158
if (!entry) {
159
simple_mtx_unlock(&screen->surface_mtx);
160
return NULL;
161
}
162
163
surface = entry->data;
164
} else {
165
surface = entry->data;
166
p_atomic_inc(&surface->base.reference.count);
167
}
168
simple_mtx_unlock(&screen->surface_mtx);
169
170
return &surface->base;
171
}
172
173
static struct pipe_surface *
174
zink_create_surface(struct pipe_context *pctx,
175
struct pipe_resource *pres,
176
const struct pipe_surface *templ)
177
{
178
179
VkImageViewCreateInfo ivci = create_ivci(zink_screen(pctx->screen),
180
zink_resource(pres), templ, pres->target);
181
if (pres->target == PIPE_TEXTURE_3D)
182
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
183
184
return zink_get_surface(zink_context(pctx), pres, templ, &ivci);
185
}
186
187
/* framebuffers are owned by their surfaces, so each time a surface that's part of a cached fb
188
* is destroyed, it has to unref all the framebuffers it's attached to in order to avoid leaking
189
* all the framebuffers
190
*
191
* surfaces are always batch-tracked, so it is impossible for a framebuffer to be destroyed
192
* while it is in use
193
*/
194
static void
195
surface_clear_fb_refs(struct zink_screen *screen, struct pipe_surface *psurface)
196
{
197
struct zink_surface *surface = zink_surface(psurface);
198
util_dynarray_foreach(&surface->framebuffer_refs, struct zink_framebuffer*, fb_ref) {
199
struct zink_framebuffer *fb = *fb_ref;
200
for (unsigned i = 0; i < fb->state.num_attachments; i++) {
201
if (fb->surfaces[i] == psurface) {
202
simple_mtx_lock(&screen->framebuffer_mtx);
203
fb->surfaces[i] = NULL;
204
_mesa_hash_table_remove_key(&screen->framebuffer_cache, &fb->state);
205
zink_framebuffer_reference(screen, &fb, NULL);
206
simple_mtx_unlock(&screen->framebuffer_mtx);
207
break;
208
}
209
/* null surface doesn't get a ref but it will double-free
210
* if the pointer isn't unset
211
*/
212
if (fb->null_surface == psurface)
213
fb->null_surface = NULL;
214
}
215
}
216
util_dynarray_fini(&surface->framebuffer_refs);
217
}
218
219
void
220
zink_destroy_surface(struct zink_screen *screen, struct pipe_surface *psurface)
221
{
222
struct zink_surface *surface = zink_surface(psurface);
223
simple_mtx_lock(&screen->surface_mtx);
224
struct hash_entry *he = _mesa_hash_table_search_pre_hashed(&screen->surface_cache, surface->hash, &surface->ivci);
225
assert(he);
226
assert(he->data == surface);
227
_mesa_hash_table_remove(&screen->surface_cache, he);
228
simple_mtx_unlock(&screen->surface_mtx);
229
surface_clear_fb_refs(screen, psurface);
230
zink_descriptor_set_refs_clear(&surface->desc_set_refs, surface);
231
util_dynarray_fini(&surface->framebuffer_refs);
232
pipe_resource_reference(&psurface->texture, NULL);
233
if (surface->simage_view)
234
vkDestroyImageView(screen->dev, surface->simage_view, NULL);
235
vkDestroyImageView(screen->dev, surface->image_view, NULL);
236
FREE(surface);
237
}
238
239
static void
240
zink_surface_destroy(struct pipe_context *pctx,
241
struct pipe_surface *psurface)
242
{
243
zink_destroy_surface(zink_screen(pctx->screen), psurface);
244
}
245
246
bool
247
zink_rebind_surface(struct zink_context *ctx, struct pipe_surface **psurface)
248
{
249
struct zink_surface *surface = zink_surface(*psurface);
250
struct zink_screen *screen = zink_screen(ctx->base.screen);
251
if (surface->simage_view)
252
return false;
253
VkImageViewCreateInfo ivci = create_ivci(screen,
254
zink_resource((*psurface)->texture), (*psurface), surface->base.texture->target);
255
uint32_t hash = hash_ivci(&ivci);
256
257
simple_mtx_lock(&screen->surface_mtx);
258
struct hash_entry *new_entry = _mesa_hash_table_search_pre_hashed(&screen->surface_cache, hash, &ivci);
259
if (zink_batch_usage_exists(surface->batch_uses))
260
zink_batch_reference_surface(&ctx->batch, surface);
261
surface_clear_fb_refs(screen, *psurface);
262
zink_descriptor_set_refs_clear(&surface->desc_set_refs, surface);
263
if (new_entry) {
264
/* reuse existing surface; old one will be cleaned up naturally */
265
struct zink_surface *new_surface = new_entry->data;
266
simple_mtx_unlock(&screen->surface_mtx);
267
zink_batch_usage_set(&new_surface->batch_uses, ctx->batch.state);
268
zink_surface_reference(screen, (struct zink_surface**)psurface, new_surface);
269
return true;
270
}
271
struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(&screen->surface_cache, surface->hash, &surface->ivci);
272
assert(entry);
273
_mesa_hash_table_remove(&screen->surface_cache, entry);
274
VkImageView image_view;
275
if (vkCreateImageView(screen->dev, &ivci, NULL, &image_view) != VK_SUCCESS) {
276
debug_printf("zink: failed to create new imageview");
277
simple_mtx_unlock(&screen->surface_mtx);
278
return false;
279
}
280
surface->hash = hash;
281
surface->ivci = ivci;
282
entry = _mesa_hash_table_insert_pre_hashed(&screen->surface_cache, surface->hash, &surface->ivci, surface);
283
assert(entry);
284
surface->simage_view = surface->image_view;
285
surface->image_view = image_view;
286
surface->obj = zink_resource(surface->base.texture)->obj;
287
zink_batch_usage_set(&surface->batch_uses, ctx->batch.state);
288
simple_mtx_unlock(&screen->surface_mtx);
289
return true;
290
}
291
292
struct pipe_surface *
293
zink_surface_create_null(struct zink_context *ctx, enum pipe_texture_target target, unsigned width, unsigned height, unsigned samples)
294
{
295
struct pipe_surface surf_templ = {0};
296
297
struct pipe_resource *pres;
298
struct pipe_resource templ = {0};
299
templ.width0 = width;
300
templ.height0 = height;
301
templ.depth0 = 1;
302
templ.format = PIPE_FORMAT_R8_UINT;
303
templ.target = target;
304
templ.bind = PIPE_BIND_RENDER_TARGET;
305
templ.nr_samples = samples;
306
307
pres = ctx->base.screen->resource_create(ctx->base.screen, &templ);
308
if (!pres)
309
return NULL;
310
311
surf_templ.format = PIPE_FORMAT_R8_UINT;
312
surf_templ.nr_samples = samples;
313
struct pipe_surface *psurf = ctx->base.create_surface(&ctx->base, pres, &surf_templ);
314
pipe_resource_reference(&pres, NULL);
315
return psurf;
316
}
317
318
void
319
zink_context_surface_init(struct pipe_context *context)
320
{
321
context->create_surface = zink_create_surface;
322
context->surface_destroy = zink_surface_destroy;
323
}
324
325