include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / wined3d / texture.c
blob99c6a89764d8bc85335402c872dc99c06f103bc3
1 /*
2 * Copyright 2002-2005 Jason Edmeades
3 * Copyright 2002-2005 Raphael Junqueira
4 * Copyright 2005 Oliver Stieber
5 * Copyright 2007-2009, 2013 Stefan Dösinger for CodeWeavers
6 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wined3d_private.h"
24 #include "wined3d_gl.h"
25 #include "wined3d_vk.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
28 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
29 WINE_DECLARE_DEBUG_CHANNEL(winediag);
31 #define WINED3D_TEXTURE_DYNAMIC_MAP_THRESHOLD 50
33 static const uint32_t wined3d_texture_sysmem_locations = WINED3D_LOCATION_SYSMEM | WINED3D_LOCATION_BUFFER;
34 static const struct wined3d_texture_ops texture_gl_ops;
36 struct wined3d_texture_idx
38 struct wined3d_texture *texture;
39 unsigned int sub_resource_idx;
42 struct wined3d_rect_f
44 float l;
45 float t;
46 float r;
47 float b;
50 bool wined3d_texture_validate_sub_resource_idx(const struct wined3d_texture *texture, unsigned int sub_resource_idx)
52 if (sub_resource_idx < texture->level_count * texture->layer_count)
53 return true;
55 WARN("Invalid sub-resource index %u.\n", sub_resource_idx);
56 return false;
59 BOOL wined3d_texture_can_use_pbo(const struct wined3d_texture *texture, const struct wined3d_d3d_info *d3d_info)
61 if (!d3d_info->pbo || texture->resource.format->conv_byte_count || texture->resource.pin_sysmem)
62 return FALSE;
64 return TRUE;
67 static BOOL wined3d_texture_use_pbo(const struct wined3d_texture *texture, const struct wined3d_d3d_info *d3d_info)
69 if (!wined3d_texture_can_use_pbo(texture, d3d_info))
70 return FALSE;
72 /* Use a PBO for dynamic textures and read-only staging textures. */
73 return (!(texture->resource.access & WINED3D_RESOURCE_ACCESS_CPU)
74 && texture->resource.usage & WINED3DUSAGE_DYNAMIC)
75 || texture->resource.access == (WINED3D_RESOURCE_ACCESS_CPU | WINED3D_RESOURCE_ACCESS_MAP_R);
78 static BOOL wined3d_texture_use_immutable_storage(const struct wined3d_texture *texture,
79 const struct wined3d_gl_info *gl_info)
81 /* We don't expect to create texture views for textures with height-scaled formats.
82 * Besides, ARB_texture_storage doesn't allow specifying exact sizes for all levels. */
83 return gl_info->supported[ARB_TEXTURE_STORAGE]
84 && !(texture->resource.format_attrs & WINED3D_FORMAT_ATTR_HEIGHT_SCALE);
87 /* Front buffer coordinates are always full screen coordinates, but our GL
88 * drawable is limited to the window's client area. The sysmem and texture
89 * copies do have the full screen size. Note that GL has a bottom-left
90 * origin, while D3D has a top-left origin. */
91 void wined3d_texture_translate_drawable_coords(const struct wined3d_texture *texture, HWND window, RECT *rect)
93 unsigned int drawable_height;
94 POINT offset = {0, 0};
95 RECT windowsize;
97 if (!texture->swapchain)
98 return;
100 if (texture == texture->swapchain->front_buffer)
102 ScreenToClient(window, &offset);
103 OffsetRect(rect, offset.x, offset.y);
106 GetClientRect(window, &windowsize);
107 drawable_height = windowsize.bottom - windowsize.top;
109 rect->top = drawable_height - rect->top;
110 rect->bottom = drawable_height - rect->bottom;
113 GLenum wined3d_texture_get_gl_buffer(const struct wined3d_texture *texture)
115 const struct wined3d_swapchain *swapchain = texture->swapchain;
117 TRACE("texture %p.\n", texture);
119 if (!swapchain)
121 ERR("Texture %p is not part of a swapchain.\n", texture);
122 return GL_NONE;
125 if (texture == swapchain->front_buffer)
127 TRACE("Returning GL_FRONT.\n");
128 return GL_FRONT;
131 if (texture == swapchain->back_buffers[0])
133 TRACE("Returning GL_BACK.\n");
134 return GL_BACK;
137 FIXME("Higher back buffer, returning GL_BACK.\n");
138 return GL_BACK;
141 static uint32_t wined3d_resource_access_from_location(uint32_t location)
143 switch (location)
145 case WINED3D_LOCATION_DISCARDED:
146 return 0;
148 case WINED3D_LOCATION_SYSMEM:
149 return WINED3D_RESOURCE_ACCESS_CPU;
151 case WINED3D_LOCATION_BUFFER:
152 case WINED3D_LOCATION_DRAWABLE:
153 case WINED3D_LOCATION_TEXTURE_RGB:
154 case WINED3D_LOCATION_TEXTURE_SRGB:
155 case WINED3D_LOCATION_RB_MULTISAMPLE:
156 case WINED3D_LOCATION_RB_RESOLVED:
157 return WINED3D_RESOURCE_ACCESS_GPU;
159 default:
160 FIXME("Unhandled location %#x.\n", location);
161 return 0;
165 static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct wined3d_rect_f *f)
167 f->l = ((r->left * 2.0f) / w) - 1.0f;
168 f->t = ((r->top * 2.0f) / h) - 1.0f;
169 f->r = ((r->right * 2.0f) / w) - 1.0f;
170 f->b = ((r->bottom * 2.0f) / h) - 1.0f;
173 void texture2d_get_blt_info(const struct wined3d_texture_gl *texture_gl,
174 unsigned int sub_resource_idx, const RECT *rect, struct wined3d_blt_info *info)
176 struct wined3d_vec3 *coords = info->texcoords;
177 struct wined3d_rect_f f;
178 unsigned int level;
179 GLenum target;
180 GLsizei w, h;
182 level = sub_resource_idx % texture_gl->t.level_count;
183 w = wined3d_texture_get_level_width(&texture_gl->t, level);
184 h = wined3d_texture_get_level_height(&texture_gl->t, level);
185 target = wined3d_texture_gl_get_sub_resource_target(texture_gl, sub_resource_idx);
187 switch (target)
189 default:
190 FIXME("Unsupported texture target %#x.\n", target);
191 /* Fall back to GL_TEXTURE_2D */
192 case GL_TEXTURE_2D:
193 info->bind_target = GL_TEXTURE_2D;
194 coords[0].x = (float)rect->left / w;
195 coords[0].y = (float)rect->top / h;
196 coords[0].z = 0.0f;
198 coords[1].x = (float)rect->right / w;
199 coords[1].y = (float)rect->top / h;
200 coords[1].z = 0.0f;
202 coords[2].x = (float)rect->left / w;
203 coords[2].y = (float)rect->bottom / h;
204 coords[2].z = 0.0f;
206 coords[3].x = (float)rect->right / w;
207 coords[3].y = (float)rect->bottom / h;
208 coords[3].z = 0.0f;
209 break;
211 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
212 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
213 cube_coords_float(rect, w, h, &f);
215 coords[0].x = 1.0f; coords[0].y = -f.t; coords[0].z = -f.l;
216 coords[1].x = 1.0f; coords[1].y = -f.t; coords[1].z = -f.r;
217 coords[2].x = 1.0f; coords[2].y = -f.b; coords[2].z = -f.l;
218 coords[3].x = 1.0f; coords[3].y = -f.b; coords[3].z = -f.r;
219 break;
221 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
222 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
223 cube_coords_float(rect, w, h, &f);
225 coords[0].x = -1.0f; coords[0].y = -f.t; coords[0].z = f.l;
226 coords[1].x = -1.0f; coords[1].y = -f.t; coords[1].z = f.r;
227 coords[2].x = -1.0f; coords[2].y = -f.b; coords[2].z = f.l;
228 coords[3].x = -1.0f; coords[3].y = -f.b; coords[3].z = f.r;
229 break;
231 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
232 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
233 cube_coords_float(rect, w, h, &f);
235 coords[0].x = f.l; coords[0].y = 1.0f; coords[0].z = f.t;
236 coords[1].x = f.r; coords[1].y = 1.0f; coords[1].z = f.t;
237 coords[2].x = f.l; coords[2].y = 1.0f; coords[2].z = f.b;
238 coords[3].x = f.r; coords[3].y = 1.0f; coords[3].z = f.b;
239 break;
241 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
242 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
243 cube_coords_float(rect, w, h, &f);
245 coords[0].x = f.l; coords[0].y = -1.0f; coords[0].z = -f.t;
246 coords[1].x = f.r; coords[1].y = -1.0f; coords[1].z = -f.t;
247 coords[2].x = f.l; coords[2].y = -1.0f; coords[2].z = -f.b;
248 coords[3].x = f.r; coords[3].y = -1.0f; coords[3].z = -f.b;
249 break;
251 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
252 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
253 cube_coords_float(rect, w, h, &f);
255 coords[0].x = f.l; coords[0].y = -f.t; coords[0].z = 1.0f;
256 coords[1].x = f.r; coords[1].y = -f.t; coords[1].z = 1.0f;
257 coords[2].x = f.l; coords[2].y = -f.b; coords[2].z = 1.0f;
258 coords[3].x = f.r; coords[3].y = -f.b; coords[3].z = 1.0f;
259 break;
261 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
262 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
263 cube_coords_float(rect, w, h, &f);
265 coords[0].x = -f.l; coords[0].y = -f.t; coords[0].z = -1.0f;
266 coords[1].x = -f.r; coords[1].y = -f.t; coords[1].z = -1.0f;
267 coords[2].x = -f.l; coords[2].y = -f.b; coords[2].z = -1.0f;
268 coords[3].x = -f.r; coords[3].y = -f.b; coords[3].z = -1.0f;
269 break;
273 static bool fbo_blitter_supported(enum wined3d_blit_op blit_op, const struct wined3d_gl_info *gl_info,
274 const struct wined3d_resource *src_resource, DWORD src_location,
275 const struct wined3d_resource *dst_resource, DWORD dst_location)
277 const struct wined3d_format *src_format = src_resource->format;
278 const struct wined3d_format *dst_format = dst_resource->format;
279 bool src_ds, dst_ds;
281 if ((src_resource->format_attrs | dst_resource->format_attrs) & WINED3D_FORMAT_ATTR_HEIGHT_SCALE)
282 return false;
284 /* Source and/or destination need to be on the GL side. */
285 if (!(src_resource->access & dst_resource->access & WINED3D_RESOURCE_ACCESS_GPU))
286 return false;
288 if (src_resource->type != WINED3D_RTYPE_TEXTURE_2D)
289 return false;
291 /* We can't copy between depth/stencil and colour attachments. One notable
292 * way we can end up here is when copying between typeless resources with
293 * formats like R16_TYPELESS, which can end up using either a
294 * depth/stencil or a colour format on the OpenGL side, depending on the
295 * resource's bind flags. */
296 src_ds = src_format->depth_size || src_format->stencil_size;
297 dst_ds = dst_format->depth_size || dst_format->stencil_size;
298 if (src_ds != dst_ds)
299 return false;
301 switch (blit_op)
303 case WINED3D_BLIT_OP_COLOR_BLIT:
304 if (!((src_format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_FBO_ATTACHABLE)
305 || (src_resource->bind_flags & WINED3D_BIND_RENDER_TARGET)))
306 return false;
307 if (!((dst_format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_FBO_ATTACHABLE)
308 || (dst_resource->bind_flags & WINED3D_BIND_RENDER_TARGET)))
309 return false;
310 if ((src_format->id != dst_format->id || dst_location == WINED3D_LOCATION_DRAWABLE)
311 && (!is_identity_fixup(src_format->color_fixup) || !is_identity_fixup(dst_format->color_fixup)))
312 return false;
313 break;
315 case WINED3D_BLIT_OP_DEPTH_BLIT:
316 if (!(src_format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_DEPTH_STENCIL))
317 return false;
318 if (!(dst_format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_DEPTH_STENCIL))
319 return false;
320 /* Accept pure swizzle fixups for depth formats. In general we
321 * ignore the stencil component (if present) at the moment and the
322 * swizzle is not relevant with just the depth component. */
323 if (is_complex_fixup(src_format->color_fixup) || is_complex_fixup(dst_format->color_fixup)
324 || is_scaling_fixup(src_format->color_fixup) || is_scaling_fixup(dst_format->color_fixup))
325 return false;
326 break;
328 default:
329 return false;
332 return true;
335 /* Blit between surface locations. Onscreen on different swapchains is not supported.
336 * Depth / stencil is not supported. Context activation is done by the caller. */
337 static void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_context *context,
338 enum wined3d_texture_filter_type filter, struct wined3d_texture *src_texture,
339 unsigned int src_sub_resource_idx, DWORD src_location, const RECT *src_rect,
340 struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, DWORD dst_location,
341 const RECT *dst_rect, const struct wined3d_format *resolve_format)
343 struct wined3d_texture *required_texture, *restore_texture = NULL, *dst_save_texture = dst_texture;
344 unsigned int restore_idx, dst_save_sub_resource_idx = dst_sub_resource_idx;
345 struct wined3d_texture *src_staging_texture = NULL;
346 const struct wined3d_gl_info *gl_info;
347 struct wined3d_context_gl *context_gl;
348 bool resolve, scaled_resolve;
349 GLenum gl_filter;
350 GLenum buffer;
351 RECT s, d;
353 TRACE("device %p, context %p, filter %s, src_texture %p, src_sub_resource_idx %u, src_location %s, "
354 "src_rect %s, dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s, resolve format %p.\n",
355 device, context, debug_d3dtexturefiltertype(filter), src_texture, src_sub_resource_idx,
356 wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect), dst_texture,
357 dst_sub_resource_idx, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect), resolve_format);
359 resolve = wined3d_texture_gl_is_multisample_location(wined3d_texture_gl(src_texture), src_location);
360 scaled_resolve = resolve
361 && (abs(src_rect->bottom - src_rect->top) != abs(dst_rect->bottom - dst_rect->top)
362 || abs(src_rect->right - src_rect->left) != abs(dst_rect->right - dst_rect->left));
364 if (filter == WINED3D_TEXF_LINEAR)
365 gl_filter = scaled_resolve ? GL_SCALED_RESOLVE_NICEST_EXT : GL_LINEAR;
366 else
367 gl_filter = scaled_resolve ? GL_SCALED_RESOLVE_FASTEST_EXT : GL_NEAREST;
369 if (resolve)
371 GLint resolve_internal, src_internal, dst_internal;
372 enum wined3d_format_id resolve_format_id;
374 src_internal = wined3d_gl_get_internal_format(&src_texture->resource,
375 wined3d_format_gl(src_texture->resource.format), src_location == WINED3D_LOCATION_TEXTURE_SRGB);
376 dst_internal = wined3d_gl_get_internal_format(&dst_texture->resource,
377 wined3d_format_gl(dst_texture->resource.format), dst_location == WINED3D_LOCATION_TEXTURE_SRGB);
379 if (resolve_format)
381 resolve_internal = wined3d_format_gl(resolve_format)->internal;
382 resolve_format_id = resolve_format->id;
384 else if (!wined3d_format_is_typeless(src_texture->resource.format))
386 resolve_internal = src_internal;
387 resolve_format_id = src_texture->resource.format->id;
389 else
391 resolve_internal = dst_internal;
392 resolve_format_id = dst_texture->resource.format->id;
395 /* In case of typeless resolve the texture type may not match the resolve type.
396 * To handle that, allocate intermediate texture(s) to resolve from/to.
397 * A possible performance improvement would be to resolve using a shader instead. */
398 if (src_internal != resolve_internal)
400 struct wined3d_resource_desc desc;
401 unsigned src_level;
402 HRESULT hr;
404 src_level = src_sub_resource_idx % src_texture->level_count;
405 desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
406 desc.format = resolve_format_id;
407 desc.multisample_type = src_texture->resource.multisample_type;
408 desc.multisample_quality = src_texture->resource.multisample_quality;
409 desc.usage = WINED3DUSAGE_CS;
410 desc.bind_flags = 0;
411 desc.access = WINED3D_RESOURCE_ACCESS_GPU;
412 desc.width = wined3d_texture_get_level_width(src_texture, src_level);
413 desc.height = wined3d_texture_get_level_height(src_texture, src_level);
414 desc.depth = 1;
415 desc.size = 0;
417 hr = wined3d_texture_create(device, &desc, 1, 1, 0, NULL, NULL, &wined3d_null_parent_ops,
418 &src_staging_texture);
419 if (FAILED(hr))
421 ERR("Failed to create staging texture, hr %#lx.\n", hr);
422 goto done;
425 if (src_location == WINED3D_LOCATION_DRAWABLE)
426 FIXME("WINED3D_LOCATION_DRAWABLE not supported for the source of a typeless resolve.\n");
428 device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_RAW_BLIT, context,
429 src_texture, src_sub_resource_idx, src_location, src_rect,
430 src_staging_texture, 0, src_location, src_rect,
431 NULL, WINED3D_TEXF_NONE, NULL);
433 src_texture = src_staging_texture;
434 src_sub_resource_idx = 0;
437 if (dst_internal != resolve_internal)
439 struct wined3d_resource_desc desc;
440 unsigned dst_level;
441 HRESULT hr;
443 dst_level = dst_sub_resource_idx % dst_texture->level_count;
444 desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
445 desc.format = resolve_format_id;
446 desc.multisample_type = dst_texture->resource.multisample_type;
447 desc.multisample_quality = dst_texture->resource.multisample_quality;
448 desc.usage = WINED3DUSAGE_CS;
449 desc.bind_flags = 0;
450 desc.access = WINED3D_RESOURCE_ACCESS_GPU;
451 desc.width = wined3d_texture_get_level_width(dst_texture, dst_level);
452 desc.height = wined3d_texture_get_level_height(dst_texture, dst_level);
453 desc.depth = 1;
454 desc.size = 0;
456 hr = wined3d_texture_create(device, &desc, 1, 1, 0, NULL, NULL, &wined3d_null_parent_ops,
457 &dst_texture);
458 if (FAILED(hr))
460 ERR("Failed to create staging texture, hr %#lx.\n", hr);
461 goto done;
464 wined3d_texture_load_location(dst_texture, 0, context, dst_location);
465 dst_sub_resource_idx = 0;
469 /* Make sure the locations are up-to-date. Loading the destination
470 * surface isn't required if the entire surface is overwritten. (And is
471 * in fact harmful if we're being called by surface_load_location() with
472 * the purpose of loading the destination surface.) */
473 wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, src_location);
474 if (!wined3d_texture_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, dst_rect))
475 wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location);
476 else
477 wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location);
479 /* Acquire a context for the front-buffer, even though we may be blitting
480 * to/from a back-buffer. Since context_acquire() doesn't take the
481 * resource location into account, it may consider the back-buffer to be
482 * offscreen. */
483 if (src_location == WINED3D_LOCATION_DRAWABLE)
484 required_texture = src_texture->swapchain->front_buffer;
485 else if (dst_location == WINED3D_LOCATION_DRAWABLE)
486 required_texture = dst_texture->swapchain->front_buffer;
487 else
488 required_texture = NULL;
490 restore_texture = context->current_rt.texture;
491 restore_idx = context->current_rt.sub_resource_idx;
492 if (restore_texture != required_texture)
493 context = context_acquire(device, required_texture, 0);
494 else
495 restore_texture = NULL;
497 context_gl = wined3d_context_gl(context);
498 if (!context_gl->valid)
500 context_release(context);
501 WARN("Invalid context, skipping blit.\n");
502 restore_texture = NULL;
503 goto done;
506 gl_info = context_gl->gl_info;
508 if (src_location == WINED3D_LOCATION_DRAWABLE)
510 TRACE("Source texture %p is onscreen.\n", src_texture);
511 buffer = wined3d_texture_get_gl_buffer(src_texture);
512 s = *src_rect;
513 wined3d_texture_translate_drawable_coords(src_texture, context_gl->window, &s);
514 src_rect = &s;
516 else
518 TRACE("Source texture %p is offscreen.\n", src_texture);
519 buffer = GL_COLOR_ATTACHMENT0;
522 wined3d_context_gl_apply_fbo_state_explicit(context_gl, GL_READ_FRAMEBUFFER,
523 &src_texture->resource, src_sub_resource_idx, NULL, 0, src_location);
524 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
525 checkGLcall("glReadBuffer()");
526 wined3d_context_gl_check_fbo_status(context_gl, GL_READ_FRAMEBUFFER);
528 context_gl_apply_texture_draw_state(context_gl, dst_texture, dst_sub_resource_idx, dst_location);
530 if (dst_location == WINED3D_LOCATION_DRAWABLE)
532 d = *dst_rect;
533 wined3d_texture_translate_drawable_coords(dst_texture, context_gl->window, &d);
534 dst_rect = &d;
537 gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
538 context_invalidate_state(context, STATE_BLEND);
540 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
541 context_invalidate_state(context, STATE_RASTERIZER);
543 gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
544 dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, GL_COLOR_BUFFER_BIT, gl_filter);
545 checkGLcall("glBlitFramebuffer()");
547 if (dst_location == WINED3D_LOCATION_DRAWABLE && dst_texture->swapchain->front_buffer == dst_texture)
548 gl_info->gl_ops.gl.p_glFlush();
550 if (dst_texture != dst_save_texture)
552 if (dst_location == WINED3D_LOCATION_DRAWABLE)
553 FIXME("WINED3D_LOCATION_DRAWABLE not supported for the destination of a typeless resolve.\n");
555 device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_RAW_BLIT, context,
556 dst_texture, 0, dst_location, dst_rect,
557 dst_save_texture, dst_save_sub_resource_idx, dst_location, dst_rect,
558 NULL, WINED3D_TEXF_NONE, NULL);
561 done:
562 if (dst_texture != dst_save_texture)
563 wined3d_texture_decref(dst_texture);
565 if (src_staging_texture)
566 wined3d_texture_decref(src_staging_texture);
568 if (restore_texture)
569 context_restore(context, restore_texture, restore_idx);
572 static void texture2d_depth_blt_fbo(const struct wined3d_device *device, struct wined3d_context *context,
573 struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, DWORD src_location,
574 const RECT *src_rect, struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
575 DWORD dst_location, const RECT *dst_rect)
577 struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
578 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
579 GLbitfield src_mask, dst_mask;
580 GLbitfield gl_mask;
582 TRACE("device %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_rect %s, "
583 "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s.\n", device,
584 src_texture, src_sub_resource_idx, wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect),
585 dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect));
587 src_mask = 0;
588 if (src_texture->resource.format->depth_size)
589 src_mask |= GL_DEPTH_BUFFER_BIT;
590 if (src_texture->resource.format->stencil_size)
591 src_mask |= GL_STENCIL_BUFFER_BIT;
593 dst_mask = 0;
594 if (dst_texture->resource.format->depth_size)
595 dst_mask |= GL_DEPTH_BUFFER_BIT;
596 if (dst_texture->resource.format->stencil_size)
597 dst_mask |= GL_STENCIL_BUFFER_BIT;
599 if (src_mask != dst_mask)
601 ERR("Incompatible formats %s and %s.\n",
602 debug_d3dformat(src_texture->resource.format->id),
603 debug_d3dformat(dst_texture->resource.format->id));
604 return;
607 if (!src_mask)
609 ERR("Not a depth / stencil format: %s.\n",
610 debug_d3dformat(src_texture->resource.format->id));
611 return;
613 gl_mask = src_mask;
615 /* Make sure the locations are up-to-date. Loading the destination
616 * surface isn't required if the entire surface is overwritten. */
617 wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, src_location);
618 if (!wined3d_texture_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, dst_rect))
619 wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location);
620 else
621 wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location);
623 wined3d_context_gl_apply_fbo_state_explicit(context_gl, GL_READ_FRAMEBUFFER, NULL, 0,
624 &src_texture->resource, src_sub_resource_idx, src_location);
625 wined3d_context_gl_check_fbo_status(context_gl, GL_READ_FRAMEBUFFER);
627 context_gl_apply_texture_draw_state(context_gl, dst_texture, dst_sub_resource_idx, dst_location);
629 if (gl_mask & GL_DEPTH_BUFFER_BIT)
631 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
632 context_invalidate_state(context, STATE_DEPTH_STENCIL);
634 if (gl_mask & GL_STENCIL_BUFFER_BIT)
636 if (gl_info->supported[EXT_STENCIL_TWO_SIDE])
637 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
638 gl_info->gl_ops.gl.p_glStencilMask(~0U);
639 context_invalidate_state(context, STATE_DEPTH_STENCIL);
642 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
643 context_invalidate_state(context, STATE_RASTERIZER);
645 gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
646 dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST);
647 checkGLcall("glBlitFramebuffer()");
650 static void wined3d_texture_evict_sysmem(struct wined3d_texture *texture)
652 struct wined3d_texture_sub_resource *sub_resource;
653 unsigned int i, sub_count;
655 if ((texture->flags & WINED3D_TEXTURE_CONVERTED)
656 || texture->resource.pin_sysmem
657 || texture->download_count > WINED3D_TEXTURE_DYNAMIC_MAP_THRESHOLD)
659 TRACE("Not evicting system memory for texture %p.\n", texture);
660 return;
663 TRACE("Evicting system memory for texture %p.\n", texture);
665 sub_count = texture->level_count * texture->layer_count;
666 for (i = 0; i < sub_count; ++i)
668 sub_resource = &texture->sub_resources[i];
669 if (sub_resource->locations == WINED3D_LOCATION_SYSMEM)
670 ERR("WINED3D_LOCATION_SYSMEM is the only location for sub-resource %u of texture %p.\n",
671 i, texture);
672 sub_resource->locations &= ~WINED3D_LOCATION_SYSMEM;
674 wined3d_resource_free_sysmem(&texture->resource);
677 void wined3d_texture_validate_location(struct wined3d_texture *texture,
678 unsigned int sub_resource_idx, uint32_t location)
680 struct wined3d_texture_sub_resource *sub_resource;
681 DWORD previous_locations;
683 TRACE("texture %p, sub_resource_idx %u, location %s.\n",
684 texture, sub_resource_idx, wined3d_debug_location(location));
686 sub_resource = &texture->sub_resources[sub_resource_idx];
687 previous_locations = sub_resource->locations;
688 sub_resource->locations |= location;
689 if (previous_locations == WINED3D_LOCATION_SYSMEM && location != WINED3D_LOCATION_SYSMEM
690 && !--texture->sysmem_count)
691 wined3d_texture_evict_sysmem(texture);
693 TRACE("New locations flags are %s.\n", wined3d_debug_location(sub_resource->locations));
696 static void wined3d_texture_set_dirty(struct wined3d_texture *texture)
698 texture->flags &= ~(WINED3D_TEXTURE_RGB_VALID | WINED3D_TEXTURE_SRGB_VALID);
701 void wined3d_texture_invalidate_location(struct wined3d_texture *texture,
702 unsigned int sub_resource_idx, uint32_t location)
704 struct wined3d_texture_sub_resource *sub_resource;
705 DWORD previous_locations;
707 TRACE("texture %p, sub_resource_idx %u, location %s.\n",
708 texture, sub_resource_idx, wined3d_debug_location(location));
710 if (location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
711 wined3d_texture_set_dirty(texture);
713 sub_resource = &texture->sub_resources[sub_resource_idx];
714 previous_locations = sub_resource->locations;
715 sub_resource->locations &= ~location;
716 if (previous_locations != WINED3D_LOCATION_SYSMEM && sub_resource->locations == WINED3D_LOCATION_SYSMEM)
717 ++texture->sysmem_count;
719 TRACE("New locations flags are %s.\n", wined3d_debug_location(sub_resource->locations));
721 if (!sub_resource->locations)
722 ERR("Sub-resource %u of texture %p does not have any up to date location.\n",
723 sub_resource_idx, texture);
726 void wined3d_texture_get_bo_address(const struct wined3d_texture *texture,
727 unsigned int sub_resource_idx, struct wined3d_bo_address *data, uint32_t location)
729 struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx];
731 if (location == WINED3D_LOCATION_BUFFER)
733 data->addr = NULL;
734 data->buffer_object = sub_resource->bo;
736 else
738 assert(location == WINED3D_LOCATION_SYSMEM);
739 if (sub_resource->user_memory)
741 data->addr = sub_resource->user_memory;
743 else
745 data->addr = texture->resource.heap_memory;
746 data->addr += sub_resource->offset;
748 data->buffer_object = 0;
752 void wined3d_texture_clear_dirty_regions(struct wined3d_texture *texture)
754 unsigned int i;
756 TRACE("texture %p\n", texture);
758 if (!texture->dirty_regions)
759 return;
761 for (i = 0; i < texture->layer_count; ++i)
763 texture->dirty_regions[i].box_count = 0;
767 /* Context activation is done by the caller. Context may be NULL in
768 * WINED3D_NO3D mode. */
769 BOOL wined3d_texture_load_location(struct wined3d_texture *texture,
770 unsigned int sub_resource_idx, struct wined3d_context *context, uint32_t location)
772 DWORD current = texture->sub_resources[sub_resource_idx].locations;
773 BOOL ret;
775 TRACE("texture %p, sub_resource_idx %u, context %p, location %s.\n",
776 texture, sub_resource_idx, context, wined3d_debug_location(location));
778 TRACE("Current resource location %s.\n", wined3d_debug_location(current));
780 if (current & location)
782 TRACE("Location %s is already up to date.\n", wined3d_debug_location(location));
783 return TRUE;
786 if (WARN_ON(d3d))
788 uint32_t required_access = wined3d_resource_access_from_location(location);
789 if ((texture->resource.access & required_access) != required_access)
790 WARN("Operation requires %#x access, but texture only has %#x.\n",
791 required_access, texture->resource.access);
794 if (current & WINED3D_LOCATION_DISCARDED)
796 TRACE("Sub-resource previously discarded, nothing to do.\n");
797 if (!wined3d_texture_prepare_location(texture, sub_resource_idx, context, location))
798 return FALSE;
799 wined3d_texture_validate_location(texture, sub_resource_idx, location);
800 wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
801 return TRUE;
804 if (!current)
806 ERR("Sub-resource %u of texture %p does not have any up to date location.\n",
807 sub_resource_idx, texture);
808 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
809 return wined3d_texture_load_location(texture, sub_resource_idx, context, location);
812 if ((location & wined3d_texture_sysmem_locations)
813 && (current & (wined3d_texture_sysmem_locations | WINED3D_LOCATION_CLEARED)))
815 struct wined3d_bo_address source, destination;
816 struct wined3d_range range;
818 if (!wined3d_texture_prepare_location(texture, sub_resource_idx, context, location))
819 return FALSE;
820 wined3d_texture_get_bo_address(texture, sub_resource_idx, &destination, location);
821 range.offset = 0;
822 range.size = texture->sub_resources[sub_resource_idx].size;
823 if (current & WINED3D_LOCATION_CLEARED)
825 unsigned int level_idx = sub_resource_idx % texture->level_count;
826 struct wined3d_map_desc map;
827 struct wined3d_box box;
828 struct wined3d_color c;
830 if (texture->resource.format->caps[WINED3D_GL_RES_TYPE_TEX_2D]
831 & WINED3D_FORMAT_CAP_DEPTH_STENCIL)
833 c.r = texture->sub_resources[sub_resource_idx].clear_value.depth;
834 c.g = texture->sub_resources[sub_resource_idx].clear_value.stencil;
835 c.b = c.a = 0.0f;
837 else
839 c = texture->sub_resources[sub_resource_idx].clear_value.colour;
842 wined3d_texture_get_pitch(texture, level_idx, &map.row_pitch, &map.slice_pitch);
843 if (destination.buffer_object)
844 map.data = wined3d_context_map_bo_address(context, &destination, range.size,
845 WINED3D_MAP_WRITE | WINED3D_MAP_DISCARD);
846 else
847 map.data = destination.addr;
849 wined3d_texture_get_level_box(texture, level_idx, &box);
850 wined3d_resource_memory_colour_fill(&texture->resource, &map, &c, &box, true);
852 if (destination.buffer_object)
853 wined3d_context_unmap_bo_address(context, &destination, 1, &range);
855 else
857 wined3d_texture_get_bo_address(texture, sub_resource_idx,
858 &source, (current & wined3d_texture_sysmem_locations));
859 wined3d_context_copy_bo_address(context, &destination, &source, 1, &range,
860 WINED3D_MAP_WRITE | WINED3D_MAP_DISCARD);
862 ret = TRUE;
864 else
866 ret = texture->texture_ops->texture_load_location(texture, sub_resource_idx, context, location);
869 if (ret)
870 wined3d_texture_validate_location(texture, sub_resource_idx, location);
872 return ret;
875 static void wined3d_texture_get_memory(struct wined3d_texture *texture, unsigned int sub_resource_idx,
876 struct wined3d_context *context, struct wined3d_bo_address *data)
878 struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx];
879 DWORD locations = sub_resource->locations;
881 TRACE("texture %p, context %p, sub_resource_idx %u, data %p, locations %s.\n",
882 texture, context, sub_resource_idx, data, wined3d_debug_location(locations));
884 if (locations & (WINED3D_LOCATION_DISCARDED | WINED3D_LOCATION_CLEARED))
886 locations = (wined3d_texture_use_pbo(texture, context->d3d_info) ? WINED3D_LOCATION_BUFFER : WINED3D_LOCATION_SYSMEM);
887 if (!wined3d_texture_load_location(texture, sub_resource_idx, context, locations))
889 data->buffer_object = 0;
890 data->addr = NULL;
891 return;
894 if (locations & WINED3D_LOCATION_BUFFER)
896 wined3d_texture_get_bo_address(texture, sub_resource_idx, data, WINED3D_LOCATION_BUFFER);
897 return;
900 if (locations & WINED3D_LOCATION_SYSMEM)
902 wined3d_texture_get_bo_address(texture, sub_resource_idx, data, WINED3D_LOCATION_SYSMEM);
903 return;
906 ERR("Unexpected locations %s.\n", wined3d_debug_location(locations));
907 data->addr = NULL;
908 data->buffer_object = 0;
911 /* Context activation is done by the caller. */
912 static void wined3d_texture_remove_buffer_object(struct wined3d_texture *texture,
913 unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl)
915 struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx];
916 struct wined3d_bo_gl *bo_gl = wined3d_bo_gl(sub_resource->bo);
918 TRACE("texture %p, sub_resource_idx %u, context_gl %p.\n", texture, sub_resource_idx, context_gl);
920 wined3d_context_gl_destroy_bo(context_gl, bo_gl);
921 wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_BUFFER);
922 sub_resource->bo = NULL;
923 free(bo_gl);
926 static void wined3d_texture_unload_location(struct wined3d_texture *texture,
927 struct wined3d_context *context, unsigned int location)
929 texture->texture_ops->texture_unload_location(texture, context, location);
932 static void wined3d_texture_update_map_binding(struct wined3d_texture *texture)
934 unsigned int sub_count = texture->level_count * texture->layer_count;
935 struct wined3d_device *device = texture->resource.device;
936 DWORD map_binding = texture->update_map_binding;
937 struct wined3d_context *context;
938 unsigned int i;
940 context = context_acquire(device, NULL, 0);
942 for (i = 0; i < sub_count; ++i)
944 if (texture->sub_resources[i].locations == texture->resource.map_binding
945 && !wined3d_texture_load_location(texture, i, context, map_binding))
946 ERR("Failed to load location %s.\n", wined3d_debug_location(map_binding));
949 if (texture->resource.map_binding == WINED3D_LOCATION_BUFFER)
950 wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_BUFFER);
952 context_release(context);
954 texture->resource.map_binding = map_binding;
955 texture->update_map_binding = 0;
958 static void wined3d_texture_set_map_binding(struct wined3d_texture *texture, DWORD map_binding)
960 texture->update_map_binding = map_binding;
961 if (!texture->resource.map_count)
962 wined3d_texture_update_map_binding(texture);
965 /* A GL context is provided by the caller */
966 static void gltexture_delete(struct wined3d_device *device, const struct wined3d_gl_info *gl_info,
967 struct gl_texture *tex)
969 context_gl_resource_released(device, tex->name, FALSE);
970 gl_info->gl_ops.gl.p_glDeleteTextures(1, &tex->name);
971 tex->name = 0;
974 /* Context activation is done by the caller. */
975 /* The caller is responsible for binding the correct texture. */
976 static void wined3d_texture_gl_allocate_mutable_storage(struct wined3d_texture_gl *texture_gl,
977 GLenum gl_internal_format, const struct wined3d_format_gl *format,
978 const struct wined3d_gl_info *gl_info)
980 unsigned int level, level_count, layer, layer_count;
981 GLsizei width, height, depth;
982 GLenum target;
984 level_count = texture_gl->t.level_count;
985 if (texture_gl->target == GL_TEXTURE_1D_ARRAY || texture_gl->target == GL_TEXTURE_2D_ARRAY)
986 layer_count = 1;
987 else
988 layer_count = texture_gl->t.layer_count;
990 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
991 checkGLcall("glBindBuffer");
993 for (layer = 0; layer < layer_count; ++layer)
995 target = wined3d_texture_gl_get_sub_resource_target(texture_gl, layer * level_count);
997 for (level = 0; level < level_count; ++level)
999 width = wined3d_texture_get_level_width(&texture_gl->t, level);
1000 height = wined3d_texture_get_level_height(&texture_gl->t, level);
1001 if (texture_gl->t.resource.format_attrs & WINED3D_FORMAT_ATTR_HEIGHT_SCALE)
1003 height *= format->f.height_scale.numerator;
1004 height /= format->f.height_scale.denominator;
1007 TRACE("texture_gl %p, layer %u, level %u, target %#x, width %u, height %u.\n",
1008 texture_gl, layer, level, target, width, height);
1010 if (target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY)
1012 depth = wined3d_texture_get_level_depth(&texture_gl->t, level);
1013 GL_EXTCALL(glTexImage3D(target, level, gl_internal_format, width, height,
1014 target == GL_TEXTURE_2D_ARRAY ? texture_gl->t.layer_count : depth, 0,
1015 format->format, format->type, NULL));
1016 checkGLcall("glTexImage3D");
1018 else if (target == GL_TEXTURE_1D)
1020 gl_info->gl_ops.gl.p_glTexImage1D(target, level, gl_internal_format,
1021 width, 0, format->format, format->type, NULL);
1023 else
1025 gl_info->gl_ops.gl.p_glTexImage2D(target, level, gl_internal_format, width,
1026 target == GL_TEXTURE_1D_ARRAY ? texture_gl->t.layer_count : height, 0,
1027 format->format, format->type, NULL);
1028 checkGLcall("glTexImage2D");
1034 /* Context activation is done by the caller. */
1035 /* The caller is responsible for binding the correct texture. */
1036 static void wined3d_texture_gl_allocate_immutable_storage(struct wined3d_texture_gl *texture_gl,
1037 GLenum gl_internal_format, const struct wined3d_gl_info *gl_info)
1039 unsigned int samples = wined3d_resource_get_sample_count(&texture_gl->t.resource);
1040 GLboolean standard_pattern = texture_gl->t.resource.multisample_type != WINED3D_MULTISAMPLE_NON_MASKABLE
1041 && texture_gl->t.resource.multisample_quality == WINED3D_STANDARD_MULTISAMPLE_PATTERN;
1042 GLsizei height = wined3d_texture_get_level_height(&texture_gl->t, 0);
1043 GLsizei width = wined3d_texture_get_level_width(&texture_gl->t, 0);
1045 switch (texture_gl->target)
1047 case GL_TEXTURE_3D:
1048 GL_EXTCALL(glTexStorage3D(texture_gl->target, texture_gl->t.level_count,
1049 gl_internal_format, width, height, wined3d_texture_get_level_depth(&texture_gl->t, 0)));
1050 break;
1051 case GL_TEXTURE_2D_ARRAY:
1052 GL_EXTCALL(glTexStorage3D(texture_gl->target, texture_gl->t.level_count,
1053 gl_internal_format, width, height, texture_gl->t.layer_count));
1054 break;
1055 case GL_TEXTURE_2D_MULTISAMPLE:
1056 GL_EXTCALL(glTexStorage2DMultisample(texture_gl->target, samples,
1057 gl_internal_format, width, height, standard_pattern));
1058 break;
1059 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
1060 GL_EXTCALL(glTexStorage3DMultisample(texture_gl->target, samples,
1061 gl_internal_format, width, height, texture_gl->t.layer_count, standard_pattern));
1062 break;
1063 case GL_TEXTURE_1D_ARRAY:
1064 GL_EXTCALL(glTexStorage2D(texture_gl->target, texture_gl->t.level_count,
1065 gl_internal_format, width, texture_gl->t.layer_count));
1066 break;
1067 case GL_TEXTURE_1D:
1068 GL_EXTCALL(glTexStorage1D(texture_gl->target, texture_gl->t.level_count, gl_internal_format, width));
1069 break;
1070 default:
1071 GL_EXTCALL(glTexStorage2D(texture_gl->target, texture_gl->t.level_count,
1072 gl_internal_format, width, height));
1073 break;
1076 checkGLcall("allocate immutable storage");
1079 static void wined3d_texture_dirty_region_add(struct wined3d_texture *texture,
1080 unsigned int layer, const struct wined3d_box *box)
1082 struct wined3d_dirty_regions *regions;
1083 unsigned int count;
1085 if (!texture->dirty_regions)
1086 return;
1088 regions = &texture->dirty_regions[layer];
1089 count = regions->box_count + 1;
1090 if (count >= WINED3D_MAX_DIRTY_REGION_COUNT || !box
1091 || (!box->left && !box->top && !box->front
1092 && box->right == texture->resource.width
1093 && box->bottom == texture->resource.height
1094 && box->back == texture->resource.depth))
1096 regions->box_count = WINED3D_MAX_DIRTY_REGION_COUNT;
1097 return;
1100 if (!wined3d_array_reserve((void **)&regions->boxes, &regions->boxes_size, count, sizeof(*regions->boxes)))
1102 ERR("Failed to grow boxes array, marking entire texture dirty.\n");
1103 regions->box_count = WINED3D_MAX_DIRTY_REGION_COUNT;
1104 return;
1107 regions->boxes[regions->box_count++] = *box;
1110 void wined3d_texture_sub_resources_destroyed(struct wined3d_texture *texture)
1112 unsigned int sub_count = texture->level_count * texture->layer_count;
1113 struct wined3d_texture_sub_resource *sub_resource;
1114 unsigned int i;
1116 for (i = 0; i < sub_count; ++i)
1118 sub_resource = &texture->sub_resources[i];
1119 if (sub_resource->parent)
1121 TRACE("sub-resource %u.\n", i);
1122 sub_resource->parent_ops->wined3d_object_destroyed(sub_resource->parent);
1123 sub_resource->parent = NULL;
1128 static void wined3d_texture_create_dc(void *object)
1130 const struct wined3d_texture_idx *idx = object;
1131 struct wined3d_context *context = NULL;
1132 unsigned int sub_resource_idx, level;
1133 const struct wined3d_format *format;
1134 unsigned int row_pitch, slice_pitch;
1135 struct wined3d_texture *texture;
1136 struct wined3d_dc_info *dc_info;
1137 struct wined3d_bo_address data;
1138 D3DKMT_CREATEDCFROMMEMORY desc;
1139 struct wined3d_device *device;
1140 NTSTATUS status;
1142 TRACE("texture %p, sub_resource_idx %u.\n", idx->texture, idx->sub_resource_idx);
1144 texture = idx->texture;
1145 sub_resource_idx = idx->sub_resource_idx;
1146 level = sub_resource_idx % texture->level_count;
1147 device = texture->resource.device;
1149 format = texture->resource.format;
1150 if (!format->ddi_format)
1152 WARN("Cannot create a DC for format %s.\n", debug_d3dformat(format->id));
1153 return;
1156 if (!texture->dc_info)
1158 unsigned int sub_count = texture->level_count * texture->layer_count;
1160 if (!(texture->dc_info = calloc(sub_count, sizeof(*texture->dc_info))))
1162 ERR("Failed to allocate DC info.\n");
1163 return;
1167 if (!(texture->sub_resources[sub_resource_idx].locations & texture->resource.map_binding))
1169 context = context_acquire(device, NULL, 0);
1170 wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding);
1173 if (texture->dirty_regions)
1174 wined3d_texture_dirty_region_add(texture, sub_resource_idx / texture->level_count, NULL);
1176 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~texture->resource.map_binding);
1177 wined3d_texture_get_pitch(texture, level, &row_pitch, &slice_pitch);
1178 wined3d_texture_get_bo_address(texture, sub_resource_idx, &data, texture->resource.map_binding);
1179 if (data.buffer_object)
1181 if (!context)
1182 context = context_acquire(device, NULL, 0);
1183 desc.pMemory = wined3d_context_map_bo_address(context, &data,
1184 texture->sub_resources[sub_resource_idx].size, WINED3D_MAP_READ | WINED3D_MAP_WRITE);
1186 else
1188 desc.pMemory = data.addr;
1191 if (context)
1192 context_release(context);
1194 desc.Format = format->ddi_format;
1195 desc.Width = wined3d_texture_get_level_width(texture, level);
1196 desc.Height = wined3d_texture_get_level_height(texture, level);
1197 desc.Pitch = row_pitch;
1198 desc.hDeviceDc = CreateCompatibleDC(NULL);
1199 desc.pColorTable = NULL;
1201 status = D3DKMTCreateDCFromMemory(&desc);
1202 DeleteDC(desc.hDeviceDc);
1203 if (status)
1205 WARN("Failed to create DC, status %#lx.\n", status);
1206 return;
1209 dc_info = &texture->dc_info[sub_resource_idx];
1210 dc_info->dc = desc.hDc;
1211 dc_info->bitmap = desc.hBitmap;
1213 TRACE("Created DC %p, bitmap %p for texture %p, %u.\n", dc_info->dc, dc_info->bitmap, texture, sub_resource_idx);
1216 static void wined3d_texture_destroy_dc(void *object)
1218 const struct wined3d_texture_idx *idx = object;
1219 D3DKMT_DESTROYDCFROMMEMORY destroy_desc;
1220 struct wined3d_context *context;
1221 struct wined3d_texture *texture;
1222 struct wined3d_dc_info *dc_info;
1223 struct wined3d_bo_address data;
1224 unsigned int sub_resource_idx;
1225 struct wined3d_device *device;
1226 struct wined3d_range range;
1227 NTSTATUS status;
1229 TRACE("texture %p, sub_resource_idx %u.\n", idx->texture, idx->sub_resource_idx);
1231 texture = idx->texture;
1232 sub_resource_idx = idx->sub_resource_idx;
1233 device = texture->resource.device;
1234 dc_info = &texture->dc_info[sub_resource_idx];
1236 if (!dc_info->dc)
1238 ERR("Sub-resource {%p, %u} has no DC.\n", texture, sub_resource_idx);
1239 return;
1242 TRACE("dc %p, bitmap %p.\n", dc_info->dc, dc_info->bitmap);
1244 destroy_desc.hDc = dc_info->dc;
1245 destroy_desc.hBitmap = dc_info->bitmap;
1246 if ((status = D3DKMTDestroyDCFromMemory(&destroy_desc)))
1247 ERR("Failed to destroy dc, status %#lx.\n", status);
1248 dc_info->dc = NULL;
1249 dc_info->bitmap = NULL;
1251 wined3d_texture_get_bo_address(texture, sub_resource_idx, &data, texture->resource.map_binding);
1252 if (data.buffer_object)
1254 context = context_acquire(device, NULL, 0);
1255 range.offset = 0;
1256 range.size = texture->sub_resources[sub_resource_idx].size;
1257 wined3d_context_unmap_bo_address(context, &data, 1, &range);
1258 context_release(context);
1262 void wined3d_texture_set_swapchain(struct wined3d_texture *texture, struct wined3d_swapchain *swapchain)
1264 texture->swapchain = swapchain;
1265 wined3d_resource_update_draw_binding(&texture->resource);
1268 void wined3d_gl_texture_swizzle_from_color_fixup(GLint swizzle[4], struct color_fixup_desc fixup)
1270 static const GLenum swizzle_source[] =
1272 GL_ZERO, /* CHANNEL_SOURCE_ZERO */
1273 GL_ONE, /* CHANNEL_SOURCE_ONE */
1274 GL_RED, /* CHANNEL_SOURCE_X */
1275 GL_GREEN, /* CHANNEL_SOURCE_Y */
1276 GL_BLUE, /* CHANNEL_SOURCE_Z */
1277 GL_ALPHA, /* CHANNEL_SOURCE_W */
1280 swizzle[0] = swizzle_source[fixup.x_source];
1281 swizzle[1] = swizzle_source[fixup.y_source];
1282 swizzle[2] = swizzle_source[fixup.z_source];
1283 swizzle[3] = swizzle_source[fixup.w_source];
1286 /* Context activation is done by the caller. */
1287 GLuint wined3d_texture_gl_prepare_gl_texture(struct wined3d_texture_gl *texture_gl,
1288 struct wined3d_context_gl *context_gl, BOOL srgb)
1290 const struct wined3d_format *format = texture_gl->t.resource.format;
1291 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
1292 const struct color_fixup_desc fixup = format->color_fixup;
1293 struct gl_texture *gl_tex;
1294 GLenum target;
1296 TRACE("texture_gl %p, context_gl %p, srgb %#x.\n", texture_gl, context_gl, srgb);
1298 if (!needs_separate_srgb_gl_texture(&context_gl->c, &texture_gl->t))
1299 srgb = FALSE;
1301 /* sRGB mode cache for preload() calls outside drawprim. */
1302 if (srgb)
1303 texture_gl->t.flags |= WINED3D_TEXTURE_IS_SRGB;
1304 else
1305 texture_gl->t.flags &= ~WINED3D_TEXTURE_IS_SRGB;
1307 gl_tex = wined3d_texture_gl_get_gl_texture(texture_gl, srgb);
1308 target = texture_gl->target;
1310 if (gl_tex->name)
1311 return gl_tex->name;
1313 gl_info->gl_ops.gl.p_glGenTextures(1, &gl_tex->name);
1314 checkGLcall("glGenTextures");
1315 TRACE("Generated texture %d.\n", gl_tex->name);
1317 if (!gl_tex->name)
1319 ERR("Failed to generate a texture name.\n");
1320 return 0;
1323 /* Initialise the state of the texture object to the OpenGL defaults, not
1324 * the wined3d defaults. */
1325 gl_tex->sampler_desc.address_u = WINED3D_TADDRESS_WRAP;
1326 gl_tex->sampler_desc.address_v = WINED3D_TADDRESS_WRAP;
1327 gl_tex->sampler_desc.address_w = WINED3D_TADDRESS_WRAP;
1328 memset(gl_tex->sampler_desc.border_color, 0, sizeof(gl_tex->sampler_desc.border_color));
1329 gl_tex->sampler_desc.mag_filter = WINED3D_TEXF_LINEAR;
1330 gl_tex->sampler_desc.min_filter = WINED3D_TEXF_POINT; /* GL_NEAREST_MIPMAP_LINEAR */
1331 gl_tex->sampler_desc.mip_filter = WINED3D_TEXF_LINEAR; /* GL_NEAREST_MIPMAP_LINEAR */
1332 gl_tex->sampler_desc.lod_bias = 0.0f;
1333 gl_tex->sampler_desc.min_lod = -1000.0f;
1334 gl_tex->sampler_desc.max_lod = 1000.0f;
1335 gl_tex->sampler_desc.max_anisotropy = 1;
1336 gl_tex->sampler_desc.compare = FALSE;
1337 gl_tex->sampler_desc.comparison_func = WINED3D_CMP_LESSEQUAL;
1338 if (gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
1339 gl_tex->sampler_desc.srgb_decode = TRUE;
1340 else
1341 gl_tex->sampler_desc.srgb_decode = srgb;
1342 gl_tex->sampler_desc.mip_base_level = 0;
1343 wined3d_texture_set_dirty(&texture_gl->t);
1345 wined3d_context_gl_bind_texture(context_gl, target, gl_tex->name);
1347 /* For a new texture we have to set the texture levels after binding the
1348 * texture. */
1349 TRACE("Setting GL_TEXTURE_MAX_LEVEL to %u.\n", texture_gl->t.level_count - 1);
1350 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture_gl->t.level_count - 1);
1351 checkGLcall("glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture->level_count)");
1353 if (target == GL_TEXTURE_CUBE_MAP_ARB)
1355 /* Cubemaps are always set to clamp, regardless of the sampler state. */
1356 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1357 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1358 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
1361 if (texture_gl->t.flags & WINED3D_TEXTURE_COND_NP2 && target != GL_TEXTURE_2D_MULTISAMPLE
1362 && target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
1364 /* Conditional non power of two textures use a different clamping
1365 * default. If we're using the GL_WINE_normalized_texrect partial
1366 * driver emulation, we're dealing with a GL_TEXTURE_2D texture which
1367 * has the address mode set to repeat - something that prevents us
1368 * from hitting the accelerated codepath. Thus manually set the GL
1369 * state. The same applies to filtering. Even if the texture has only
1370 * one mip level, the default LINEAR_MIPMAP_LINEAR filter causes a SW
1371 * fallback on macos. */
1372 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1373 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1374 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1375 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1376 checkGLcall("glTexParameteri");
1377 gl_tex->sampler_desc.address_u = WINED3D_TADDRESS_CLAMP;
1378 gl_tex->sampler_desc.address_v = WINED3D_TADDRESS_CLAMP;
1379 gl_tex->sampler_desc.mag_filter = WINED3D_TEXF_POINT;
1380 gl_tex->sampler_desc.min_filter = WINED3D_TEXF_POINT;
1381 gl_tex->sampler_desc.mip_filter = WINED3D_TEXF_NONE;
1384 if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT] && gl_info->supported[ARB_DEPTH_TEXTURE])
1386 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);
1387 checkGLcall("glTexParameteri(GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY)");
1390 if (!is_identity_fixup(fixup) && can_use_texture_swizzle(context_gl->c.d3d_info, format))
1392 GLint swizzle[4];
1394 wined3d_gl_texture_swizzle_from_color_fixup(swizzle, fixup);
1395 gl_info->gl_ops.gl.p_glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
1396 checkGLcall("set format swizzle");
1399 return gl_tex->name;
1402 /* Context activation is done by the caller. */
1403 void wined3d_texture_gl_bind_and_dirtify(struct wined3d_texture_gl *texture_gl,
1404 struct wined3d_context_gl *context_gl, BOOL srgb)
1406 /* FIXME: Ideally we'd only do this when touching a binding that's used by
1407 * a shader. */
1408 context_invalidate_compute_state(&context_gl->c, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
1409 context_invalidate_state(&context_gl->c, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
1411 wined3d_texture_gl_bind(texture_gl, context_gl, srgb);
1414 void wined3d_texture_gl_bind(struct wined3d_texture_gl *texture_gl,
1415 struct wined3d_context_gl *context_gl, BOOL srgb)
1417 wined3d_context_gl_bind_texture(context_gl, texture_gl->target,
1418 wined3d_texture_gl_prepare_gl_texture(texture_gl, context_gl, srgb));
1421 /* Context activation is done by the caller (state handler). */
1422 /* This function relies on the correct texture being bound and loaded. */
1423 void wined3d_texture_gl_apply_sampler_desc(struct wined3d_texture_gl *texture_gl,
1424 const struct wined3d_sampler_desc *sampler_desc, const struct wined3d_context_gl *context_gl)
1426 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
1427 GLenum target = texture_gl->target;
1428 struct gl_texture *gl_tex;
1429 DWORD state;
1431 TRACE("texture_gl %p, sampler_desc %p, context_gl %p.\n", texture_gl, sampler_desc, context_gl);
1433 gl_tex = wined3d_texture_gl_get_gl_texture(texture_gl, texture_gl->t.flags & WINED3D_TEXTURE_IS_SRGB);
1435 state = sampler_desc->address_u;
1436 if (state != gl_tex->sampler_desc.address_u)
1438 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S,
1439 gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]);
1440 gl_tex->sampler_desc.address_u = state;
1443 state = sampler_desc->address_v;
1444 if (state != gl_tex->sampler_desc.address_v)
1446 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T,
1447 gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]);
1448 gl_tex->sampler_desc.address_v = state;
1451 state = sampler_desc->address_w;
1452 if (state != gl_tex->sampler_desc.address_w)
1454 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_R,
1455 gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]);
1456 gl_tex->sampler_desc.address_w = state;
1459 if (memcmp(gl_tex->sampler_desc.border_color, sampler_desc->border_color,
1460 sizeof(gl_tex->sampler_desc.border_color)))
1462 gl_info->gl_ops.gl.p_glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, &sampler_desc->border_color[0]);
1463 memcpy(gl_tex->sampler_desc.border_color, sampler_desc->border_color,
1464 sizeof(gl_tex->sampler_desc.border_color));
1467 state = sampler_desc->mag_filter;
1468 if (state != gl_tex->sampler_desc.mag_filter)
1470 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(state));
1471 gl_tex->sampler_desc.mag_filter = state;
1474 if (sampler_desc->min_filter != gl_tex->sampler_desc.min_filter
1475 || sampler_desc->mip_filter != gl_tex->sampler_desc.mip_filter)
1477 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MIN_FILTER,
1478 wined3d_gl_min_mip_filter(sampler_desc->min_filter, sampler_desc->mip_filter));
1479 gl_tex->sampler_desc.min_filter = sampler_desc->min_filter;
1480 gl_tex->sampler_desc.mip_filter = sampler_desc->mip_filter;
1483 state = sampler_desc->max_anisotropy;
1484 if (state != gl_tex->sampler_desc.max_anisotropy)
1486 if (gl_info->supported[ARB_TEXTURE_FILTER_ANISOTROPIC])
1487 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY, state);
1488 else
1489 WARN("Anisotropic filtering not supported.\n");
1490 gl_tex->sampler_desc.max_anisotropy = state;
1493 if (!sampler_desc->srgb_decode != !gl_tex->sampler_desc.srgb_decode
1494 && (context_gl->c.d3d_info->wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL)
1495 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
1497 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_SRGB_DECODE_EXT,
1498 sampler_desc->srgb_decode ? GL_DECODE_EXT : GL_SKIP_DECODE_EXT);
1499 gl_tex->sampler_desc.srgb_decode = sampler_desc->srgb_decode;
1502 if (!sampler_desc->compare != !gl_tex->sampler_desc.compare)
1504 if (sampler_desc->compare)
1505 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
1506 else
1507 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
1508 gl_tex->sampler_desc.compare = sampler_desc->compare;
1511 checkGLcall("Texture parameter application");
1513 if (gl_info->supported[EXT_TEXTURE_LOD_BIAS])
1515 gl_info->gl_ops.gl.p_glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
1516 GL_TEXTURE_LOD_BIAS_EXT, sampler_desc->lod_bias);
1517 checkGLcall("glTexEnvf(GL_TEXTURE_LOD_BIAS_EXT, ...)");
1521 ULONG CDECL wined3d_texture_incref(struct wined3d_texture *texture)
1523 unsigned int refcount;
1525 TRACE("texture %p, swapchain %p.\n", texture, texture->swapchain);
1527 refcount = InterlockedIncrement(&texture->resource.ref);
1528 TRACE("%p increasing refcount to %u.\n", texture, refcount);
1530 return refcount;
1533 static void wined3d_texture_destroy_object(void *object)
1535 struct wined3d_texture *texture = object;
1536 struct wined3d_resource *resource;
1537 struct wined3d_dc_info *dc_info;
1538 unsigned int sub_count;
1539 unsigned int i;
1541 TRACE("texture %p.\n", texture);
1543 resource = &texture->resource;
1544 sub_count = texture->level_count * texture->layer_count;
1546 if ((dc_info = texture->dc_info))
1548 for (i = 0; i < sub_count; ++i)
1550 if (dc_info[i].dc)
1552 struct wined3d_texture_idx texture_idx = {texture, i};
1554 wined3d_texture_destroy_dc(&texture_idx);
1557 free(dc_info);
1560 if (texture->overlay_info)
1562 for (i = 0; i < sub_count; ++i)
1564 struct wined3d_overlay_info *info = &texture->overlay_info[i];
1565 struct wined3d_overlay_info *overlay, *cur;
1567 list_remove(&info->entry);
1568 LIST_FOR_EACH_ENTRY_SAFE(overlay, cur, &info->overlays, struct wined3d_overlay_info, entry)
1570 list_remove(&overlay->entry);
1573 free(texture->overlay_info);
1576 if (texture->dirty_regions)
1578 for (i = 0; i < texture->layer_count; ++i)
1580 free(texture->dirty_regions[i].boxes);
1582 free(texture->dirty_regions);
1585 /* Discard the contents of resources with CPU access, to avoid downloading
1586 * them to SYSMEM on unload. */
1587 if (resource->access & WINED3D_RESOURCE_ACCESS_CPU)
1589 for (i = 0; i < sub_count; ++i)
1591 wined3d_texture_validate_location(texture, i, WINED3D_LOCATION_DISCARDED);
1592 wined3d_texture_invalidate_location(texture, i, ~WINED3D_LOCATION_DISCARDED);
1595 resource->resource_ops->resource_unload(resource);
1598 void wined3d_texture_cleanup(struct wined3d_texture *texture)
1600 wined3d_cs_destroy_object(texture->resource.device->cs, wined3d_texture_destroy_object, texture);
1601 resource_cleanup(&texture->resource);
1604 static void wined3d_texture_cleanup_sync(struct wined3d_texture *texture)
1606 wined3d_texture_sub_resources_destroyed(texture);
1607 wined3d_texture_cleanup(texture);
1608 wined3d_resource_wait_idle(&texture->resource);
1611 ULONG CDECL wined3d_texture_decref(struct wined3d_texture *texture)
1613 unsigned int i, sub_resource_count, refcount;
1615 TRACE("texture %p, swapchain %p.\n", texture, texture->swapchain);
1617 refcount = InterlockedDecrement(&texture->resource.ref);
1618 TRACE("%p decreasing refcount to %u.\n", texture, refcount);
1620 if (!refcount)
1622 bool in_cs_thread = GetCurrentThreadId() == texture->resource.device->cs->thread_id;
1624 if (texture->identity_srv)
1626 assert(!in_cs_thread);
1627 wined3d_shader_resource_view_destroy(texture->identity_srv);
1630 /* This is called from the CS thread to destroy temporary textures. */
1631 if (!in_cs_thread)
1632 wined3d_mutex_lock();
1633 /* Wait for the texture to become idle if it's using user memory,
1634 * since the application is allowed to free that memory once the
1635 * texture is destroyed. Note that this implies that
1636 * the destroy handler can't access that memory either. */
1637 sub_resource_count = texture->layer_count * texture->level_count;
1638 for (i = 0; i < sub_resource_count; ++i)
1640 if (texture->sub_resources[i].user_memory)
1642 wined3d_resource_wait_idle(&texture->resource);
1643 break;
1646 texture->resource.device->adapter->adapter_ops->adapter_destroy_texture(texture);
1647 if (!in_cs_thread)
1648 wined3d_mutex_unlock();
1651 return refcount;
1654 struct wined3d_resource * CDECL wined3d_texture_get_resource(struct wined3d_texture *texture)
1656 TRACE("texture %p.\n", texture);
1658 return &texture->resource;
1661 /* Context activation is done by the caller */
1662 void wined3d_texture_load(struct wined3d_texture *texture,
1663 struct wined3d_context *context, BOOL srgb)
1665 UINT sub_count = texture->level_count * texture->layer_count;
1666 DWORD flag;
1667 UINT i;
1669 TRACE("texture %p, context %p, srgb %#x.\n", texture, context, srgb);
1671 if (!needs_separate_srgb_gl_texture(context, texture))
1672 srgb = FALSE;
1674 if (srgb)
1675 flag = WINED3D_TEXTURE_SRGB_VALID;
1676 else
1677 flag = WINED3D_TEXTURE_RGB_VALID;
1679 if (texture->flags & flag)
1681 TRACE("Texture %p not dirty, nothing to do.\n", texture);
1682 return;
1685 /* Reload the surfaces if the texture is marked dirty. */
1686 for (i = 0; i < sub_count; ++i)
1688 if (!wined3d_texture_load_location(texture, i, context,
1689 srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB))
1690 ERR("Failed to load location (srgb %#x).\n", srgb);
1692 texture->flags |= flag;
1695 void * CDECL wined3d_texture_get_parent(const struct wined3d_texture *texture)
1697 TRACE("texture %p.\n", texture);
1699 return texture->resource.parent;
1702 void CDECL wined3d_texture_get_pitch(const struct wined3d_texture *texture,
1703 unsigned int level, unsigned int *row_pitch, unsigned int *slice_pitch)
1705 const struct wined3d_resource *resource = &texture->resource;
1706 unsigned int width = wined3d_texture_get_level_width(texture, level);
1707 unsigned int height = wined3d_texture_get_level_height(texture, level);
1709 if (texture->row_pitch)
1711 *row_pitch = texture->row_pitch;
1712 *slice_pitch = texture->slice_pitch;
1713 return;
1716 wined3d_format_calculate_pitch(resource->format, resource->device->surface_alignment,
1717 width, height, row_pitch, slice_pitch);
1720 unsigned int CDECL wined3d_texture_get_lod(const struct wined3d_texture *texture)
1722 TRACE("texture %p, returning %u.\n", texture, texture->lod);
1724 return texture->lod;
1727 unsigned int CDECL wined3d_texture_set_lod(struct wined3d_texture *texture, unsigned int lod)
1729 struct wined3d_resource *resource;
1730 unsigned int old = texture->lod;
1732 TRACE("texture %p, returning %u.\n", texture, texture->lod);
1734 /* The d3d9:texture test shows that SetLOD is ignored on non-managed
1735 * textures. The call always returns 0, and GetLOD always returns 0. */
1736 resource = &texture->resource;
1737 if (!(resource->usage & WINED3DUSAGE_MANAGED))
1739 TRACE("Ignoring LOD on texture with resource access %s.\n",
1740 wined3d_debug_resource_access(resource->access));
1741 return 0;
1744 if (lod >= texture->level_count)
1745 lod = texture->level_count - 1;
1747 texture->lod = lod;
1748 return old;
1751 UINT CDECL wined3d_texture_get_level_count(const struct wined3d_texture *texture)
1753 TRACE("texture %p, returning %u.\n", texture, texture->level_count);
1755 return texture->level_count;
1758 HRESULT CDECL wined3d_texture_set_color_key(struct wined3d_texture *texture,
1759 uint32_t flags, const struct wined3d_color_key *color_key)
1761 struct wined3d_device *device = texture->resource.device;
1762 static const DWORD all_flags = WINED3D_CKEY_DST_BLT | WINED3D_CKEY_DST_OVERLAY
1763 | WINED3D_CKEY_SRC_BLT | WINED3D_CKEY_SRC_OVERLAY;
1765 TRACE("texture %p, flags %#x, color_key %p.\n", texture, flags, color_key);
1767 if (flags & ~all_flags)
1769 WARN("Invalid flags passed, returning WINED3DERR_INVALIDCALL.\n");
1770 return WINED3DERR_INVALIDCALL;
1773 if ((flags & WINED3D_CKEY_SRC_BLT) && color_key)
1774 texture->src_blt_color_key = *color_key;
1776 wined3d_cs_emit_set_color_key(device->cs, texture, flags, color_key);
1778 return WINED3D_OK;
1781 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1782 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1783 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1784 /* Context activation is done by the caller. */
1785 void wined3d_texture_gl_set_compatible_renderbuffer(struct wined3d_texture_gl *texture_gl,
1786 struct wined3d_context_gl *context_gl, unsigned int level, const struct wined3d_rendertarget_info *rt)
1788 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
1789 struct wined3d_renderbuffer_entry *entry;
1790 unsigned int src_width, src_height;
1791 unsigned int width, height;
1792 GLuint renderbuffer = 0;
1794 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT])
1795 return;
1797 if (rt && rt->resource->format->id != WINED3DFMT_NULL)
1799 struct wined3d_texture *rt_texture;
1800 unsigned int rt_level;
1802 if (rt->resource->type == WINED3D_RTYPE_BUFFER)
1804 FIXME("Unsupported resource type %s.\n", debug_d3dresourcetype(rt->resource->type));
1805 return;
1807 rt_texture = wined3d_texture_from_resource(rt->resource);
1808 rt_level = rt->sub_resource_idx % rt_texture->level_count;
1810 width = wined3d_texture_get_level_width(rt_texture, rt_level);
1811 height = wined3d_texture_get_level_height(rt_texture, rt_level);
1813 else
1815 width = wined3d_texture_get_level_width(&texture_gl->t, level);
1816 height = wined3d_texture_get_level_height(&texture_gl->t, level);
1819 src_width = wined3d_texture_get_level_width(&texture_gl->t, level);
1820 src_height = wined3d_texture_get_level_height(&texture_gl->t, level);
1822 /* A depth stencil smaller than the render target is not valid */
1823 if (width > src_width || height > src_height)
1824 return;
1826 /* Remove any renderbuffer set if the sizes match */
1827 if (width == src_width && height == src_height)
1829 texture_gl->current_renderbuffer = NULL;
1830 return;
1833 /* Look if we've already got a renderbuffer of the correct dimensions */
1834 LIST_FOR_EACH_ENTRY(entry, &texture_gl->renderbuffers, struct wined3d_renderbuffer_entry, entry)
1836 if (entry->width == width && entry->height == height)
1838 renderbuffer = entry->id;
1839 texture_gl->current_renderbuffer = entry;
1840 break;
1844 if (!renderbuffer)
1846 const struct wined3d_format_gl *format_gl;
1848 format_gl = wined3d_format_gl(texture_gl->t.resource.format);
1849 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
1850 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1851 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, format_gl->internal, width, height);
1853 entry = malloc(sizeof(*entry));
1854 entry->width = width;
1855 entry->height = height;
1856 entry->id = renderbuffer;
1857 list_add_head(&texture_gl->renderbuffers, &entry->entry);
1859 texture_gl->current_renderbuffer = entry;
1862 checkGLcall("set compatible renderbuffer");
1865 HRESULT CDECL wined3d_texture_update_desc(struct wined3d_texture *texture,
1866 unsigned int sub_resource_idx, void *mem, unsigned int pitch)
1868 unsigned int current_row_pitch, current_slice_pitch, width, height;
1869 struct wined3d_texture_sub_resource *sub_resource;
1870 unsigned int i, level, sub_resource_count;
1871 const struct wined3d_format *format;
1872 struct wined3d_device *device;
1873 unsigned int slice_pitch;
1874 bool update_memory_only;
1875 bool create_dib = false;
1877 TRACE("texture %p, sub_resource_idx %u, mem %p, pitch %u.\n", texture, sub_resource_idx, mem, pitch);
1879 device = texture->resource.device;
1880 format = texture->resource.format;
1881 level = sub_resource_idx % texture->level_count;
1882 sub_resource_count = texture->level_count * texture->layer_count;
1884 width = wined3d_texture_get_level_width(texture, level);
1885 height = wined3d_texture_get_level_height(texture, level);
1886 if (pitch)
1887 slice_pitch = height * pitch;
1888 else
1889 wined3d_format_calculate_pitch(format, 1, width, height, &pitch, &slice_pitch);
1891 wined3d_texture_get_pitch(texture, level, &current_row_pitch, &current_slice_pitch);
1892 update_memory_only = (pitch == current_row_pitch && slice_pitch == current_slice_pitch);
1894 if (sub_resource_count > 1 && !update_memory_only)
1896 FIXME("Texture has multiple sub-resources, not supported.\n");
1897 return WINED3DERR_INVALIDCALL;
1900 if (texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
1902 WARN("Not supported on %s.\n", debug_d3dresourcetype(texture->resource.type));
1903 return WINED3DERR_INVALIDCALL;
1906 if (texture->resource.map_count)
1908 WARN("Texture is mapped.\n");
1909 return WINED3DERR_INVALIDCALL;
1912 /* We have no way of supporting a pitch that is not a multiple of the pixel
1913 * byte width short of uploading the texture row-by-row.
1914 * Fortunately that's not an issue since D3D9Ex doesn't allow a custom pitch
1915 * for user-memory textures (it always expects packed data) while DirectDraw
1916 * requires a 4-byte aligned pitch and doesn't support texture formats
1917 * larger than 4 bytes per pixel nor any format using 3 bytes per pixel.
1918 * This check is here to verify that the assumption holds. */
1919 if (pitch % format->byte_count)
1921 WARN("Pitch unsupported, not a multiple of the texture format byte width.\n");
1922 return WINED3DERR_INVALIDCALL;
1925 if (device->d3d_initialized)
1926 wined3d_cs_emit_unload_resource(device->cs, &texture->resource);
1927 wined3d_resource_wait_idle(&texture->resource);
1929 if (texture->dc_info && texture->dc_info[0].dc)
1931 struct wined3d_texture_idx texture_idx = {texture, sub_resource_idx};
1933 wined3d_cs_destroy_object(device->cs, wined3d_texture_destroy_dc, &texture_idx);
1934 wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
1935 create_dib = true;
1938 texture->sub_resources[sub_resource_idx].user_memory = mem;
1940 if (update_memory_only)
1942 for (i = 0; i < sub_resource_count; ++i)
1943 if (!texture->sub_resources[i].user_memory)
1944 break;
1946 if (i == sub_resource_count)
1947 wined3d_resource_free_sysmem(&texture->resource);
1949 else
1951 wined3d_resource_free_sysmem(&texture->resource);
1953 sub_resource = &texture->sub_resources[sub_resource_idx];
1955 texture->row_pitch = pitch;
1956 texture->slice_pitch = slice_pitch;
1958 if (!(texture->resource.access & WINED3D_RESOURCE_ACCESS_CPU)
1959 && texture->resource.usage & WINED3DUSAGE_VIDMEM_ACCOUNTING)
1960 adapter_adjust_memory(device->adapter, (INT64)texture->slice_pitch - texture->resource.size);
1961 texture->resource.size = texture->slice_pitch;
1962 sub_resource->size = texture->slice_pitch;
1963 sub_resource->locations = WINED3D_LOCATION_DISCARDED;
1966 if (!mem && !wined3d_resource_prepare_sysmem(&texture->resource))
1967 ERR("Failed to allocate resource memory.\n");
1969 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_SYSMEM);
1970 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~WINED3D_LOCATION_SYSMEM);
1972 if (create_dib)
1974 struct wined3d_texture_idx texture_idx = {texture, sub_resource_idx};
1976 wined3d_cs_init_object(device->cs, wined3d_texture_create_dc, &texture_idx);
1977 wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
1980 return WINED3D_OK;
1983 /* Context activation is done by the caller. */
1984 static void wined3d_texture_gl_prepare_buffer_object(struct wined3d_texture_gl *texture_gl,
1985 unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl)
1987 struct wined3d_texture_sub_resource *sub_resource;
1988 struct wined3d_bo_gl *bo;
1990 sub_resource = &texture_gl->t.sub_resources[sub_resource_idx];
1992 if (sub_resource->bo)
1993 return;
1995 if (!(bo = malloc(sizeof(*bo))))
1996 return;
1998 if (!wined3d_device_gl_create_bo(wined3d_device_gl(texture_gl->t.resource.device),
1999 context_gl, sub_resource->size, GL_PIXEL_UNPACK_BUFFER, GL_STREAM_DRAW, true,
2000 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_CLIENT_STORAGE_BIT, bo))
2002 free(bo);
2003 return;
2006 TRACE("Created buffer object %u for texture %p, sub-resource %u.\n", bo->id, texture_gl, sub_resource_idx);
2007 sub_resource->bo = &bo->b;
2010 static void wined3d_texture_force_reload(struct wined3d_texture *texture)
2012 unsigned int sub_count = texture->level_count * texture->layer_count;
2013 unsigned int i;
2015 texture->flags &= ~(WINED3D_TEXTURE_RGB_ALLOCATED | WINED3D_TEXTURE_SRGB_ALLOCATED
2016 | WINED3D_TEXTURE_CONVERTED);
2017 texture->async.flags &= ~WINED3D_TEXTURE_ASYNC_COLOR_KEY;
2018 for (i = 0; i < sub_count; ++i)
2020 wined3d_texture_invalidate_location(texture, i,
2021 WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB);
2025 /* Context activation is done by the caller. */
2026 void wined3d_texture_gl_prepare_texture(struct wined3d_texture_gl *texture_gl,
2027 struct wined3d_context_gl *context_gl, BOOL srgb)
2029 DWORD alloc_flag = srgb ? WINED3D_TEXTURE_SRGB_ALLOCATED : WINED3D_TEXTURE_RGB_ALLOCATED;
2030 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
2031 struct wined3d_resource *resource = &texture_gl->t.resource;
2032 const struct wined3d_device *device = resource->device;
2033 const struct wined3d_format *format = resource->format;
2034 const struct wined3d_color_key_conversion *conversion;
2035 const struct wined3d_format_gl *format_gl;
2036 GLenum internal;
2038 TRACE("texture_gl %p, context_gl %p, srgb %d, format %s.\n",
2039 texture_gl, context_gl, srgb, debug_d3dformat(format->id));
2041 if (texture_gl->t.flags & alloc_flag)
2042 return;
2044 if (resource->format_caps & WINED3D_FORMAT_CAP_DECOMPRESS)
2046 TRACE("WINED3D_FORMAT_CAP_DECOMPRESS set.\n");
2047 texture_gl->t.flags |= WINED3D_TEXTURE_CONVERTED;
2048 format = wined3d_resource_get_decompress_format(resource);
2050 else if (format->conv_byte_count)
2052 texture_gl->t.flags |= WINED3D_TEXTURE_CONVERTED;
2054 else if ((conversion = wined3d_format_get_color_key_conversion(&texture_gl->t, TRUE)))
2056 texture_gl->t.flags |= WINED3D_TEXTURE_CONVERTED;
2057 format = wined3d_get_format(device->adapter, conversion->dst_format, resource->bind_flags);
2058 TRACE("Using format %s for color key conversion.\n", debug_d3dformat(format->id));
2060 format_gl = wined3d_format_gl(format);
2062 wined3d_texture_gl_bind_and_dirtify(texture_gl, context_gl, srgb);
2064 internal = wined3d_gl_get_internal_format(resource, format_gl, srgb);
2065 if (!internal)
2066 FIXME("No GL internal format for format %s.\n", debug_d3dformat(format->id));
2068 TRACE("internal %#x, format %#x, type %#x.\n", internal, format_gl->format, format_gl->type);
2070 if (wined3d_texture_use_immutable_storage(&texture_gl->t, gl_info))
2071 wined3d_texture_gl_allocate_immutable_storage(texture_gl, internal, gl_info);
2072 else
2073 wined3d_texture_gl_allocate_mutable_storage(texture_gl, internal, format_gl, gl_info);
2074 texture_gl->t.flags |= alloc_flag;
2077 static void wined3d_texture_gl_prepare_rb(struct wined3d_texture_gl *texture_gl,
2078 const struct wined3d_gl_info *gl_info, BOOL multisample)
2080 const struct wined3d_format_gl *format_gl;
2082 format_gl = wined3d_format_gl(texture_gl->t.resource.format);
2083 if (multisample)
2085 DWORD samples;
2087 if (texture_gl->rb_multisample)
2088 return;
2090 samples = wined3d_resource_get_sample_count(&texture_gl->t.resource);
2092 gl_info->fbo_ops.glGenRenderbuffers(1, &texture_gl->rb_multisample);
2093 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, texture_gl->rb_multisample);
2094 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
2095 format_gl->internal, texture_gl->t.resource.width, texture_gl->t.resource.height);
2096 checkGLcall("glRenderbufferStorageMultisample()");
2097 TRACE("Created multisample rb %u.\n", texture_gl->rb_multisample);
2099 else
2101 if (texture_gl->rb_resolved)
2102 return;
2104 gl_info->fbo_ops.glGenRenderbuffers(1, &texture_gl->rb_resolved);
2105 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, texture_gl->rb_resolved);
2106 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, format_gl->internal,
2107 texture_gl->t.resource.width, texture_gl->t.resource.height);
2108 checkGLcall("glRenderbufferStorage()");
2109 TRACE("Created resolved rb %u.\n", texture_gl->rb_resolved);
2113 BOOL wined3d_texture_prepare_location(struct wined3d_texture *texture,
2114 unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location)
2116 return texture->texture_ops->texture_prepare_location(texture, sub_resource_idx, context, location);
2119 static struct wined3d_texture_sub_resource *wined3d_texture_get_sub_resource(struct wined3d_texture *texture,
2120 unsigned int sub_resource_idx)
2122 TRACE("texture %p, sub_resource_idx %u.\n", texture, sub_resource_idx);
2124 if (!wined3d_texture_validate_sub_resource_idx(texture, sub_resource_idx))
2125 return NULL;
2126 return &texture->sub_resources[sub_resource_idx];
2129 HRESULT CDECL wined3d_texture_add_dirty_region(struct wined3d_texture *texture,
2130 UINT layer, const struct wined3d_box *dirty_region)
2132 TRACE("texture %p, layer %u, dirty_region %s.\n", texture, layer, debug_box(dirty_region));
2134 if (layer >= texture->layer_count)
2136 WARN("Invalid layer %u specified.\n", layer);
2137 return WINED3DERR_INVALIDCALL;
2140 if (dirty_region && FAILED(wined3d_resource_check_box_dimensions(&texture->resource, 0, dirty_region)))
2142 WARN("Invalid dirty_region %s specified.\n", debug_box(dirty_region));
2143 return WINED3DERR_INVALIDCALL;
2146 wined3d_texture_dirty_region_add(texture, layer, dirty_region);
2147 wined3d_cs_emit_add_dirty_texture_region(texture->resource.device->cs, texture, layer);
2149 return WINED3D_OK;
2152 static void wined3d_texture_gl_upload_bo(const struct wined3d_format *src_format, GLenum target,
2153 unsigned int level, unsigned int src_row_pitch, unsigned int src_slice_pitch,
2154 unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, unsigned int update_w,
2155 unsigned int update_h, unsigned int update_d, const BYTE *addr, BOOL srgb,
2156 struct wined3d_texture *dst_texture, const struct wined3d_gl_info *gl_info)
2158 const struct wined3d_format_gl *format_gl = wined3d_format_gl(src_format);
2160 if (src_format->attrs & WINED3D_FORMAT_ATTR_COMPRESSED)
2162 GLenum internal = wined3d_gl_get_internal_format(&dst_texture->resource, format_gl, srgb);
2163 unsigned int dst_row_pitch, dst_slice_pitch;
2165 wined3d_format_calculate_pitch(src_format, 1, update_w, update_h, &dst_row_pitch, &dst_slice_pitch);
2167 TRACE("Uploading compressed data, target %#x, level %u, x %u, y %u, z %u, "
2168 "w %u, h %u, d %u, format %#x, image_size %#x, addr %p.\n",
2169 target, level, dst_x, dst_y, dst_z, update_w, update_h,
2170 update_d, internal, dst_slice_pitch, addr);
2172 if (target == GL_TEXTURE_1D)
2174 GL_EXTCALL(glCompressedTexSubImage1D(target, level, dst_x,
2175 update_w, internal, dst_row_pitch, addr));
2177 else
2179 unsigned int row, y, slice, slice_count = 1, row_count = 1;
2181 /* glCompressedTexSubImage2D() ignores pixel store state, so we
2182 * can't use the unpack row length like for glTexSubImage2D. */
2183 if (dst_row_pitch != src_row_pitch)
2185 row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
2186 update_h = src_format->block_height;
2187 wined3d_format_calculate_pitch(src_format, 1, update_w, update_h,
2188 &dst_row_pitch, &dst_slice_pitch);
2191 if (dst_slice_pitch != src_slice_pitch)
2193 slice_count = update_d;
2194 update_d = 1;
2197 for (slice = 0; slice < slice_count; ++slice)
2199 for (row = 0, y = dst_y; row < row_count; ++row)
2201 const BYTE *upload_addr = &addr[slice * src_slice_pitch + row * src_row_pitch];
2203 if (target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_3D)
2205 GL_EXTCALL(glCompressedTexSubImage3D(target, level, dst_x, y, dst_z + slice, update_w,
2206 update_h, update_d, internal, update_d * dst_slice_pitch, upload_addr));
2208 else
2210 GL_EXTCALL(glCompressedTexSubImage2D(target, level, dst_x, y, update_w,
2211 update_h, internal, dst_slice_pitch, upload_addr));
2214 y += src_format->block_height;
2218 checkGLcall("Upload compressed texture data");
2220 else
2222 unsigned int y, y_count, z, z_count;
2223 bool unpacking_rows = false;
2225 TRACE("Uploading data, target %#x, level %u, x %u, y %u, z %u, "
2226 "w %u, h %u, d %u, format %#x, type %#x, addr %p.\n",
2227 target, level, dst_x, dst_y, dst_z, update_w, update_h,
2228 update_d, format_gl->format, format_gl->type, addr);
2230 if (src_row_pitch && !(src_row_pitch % src_format->byte_count))
2232 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_row_pitch / src_format->byte_count);
2233 y_count = 1;
2234 unpacking_rows = true;
2236 else
2238 y_count = update_h;
2239 update_h = 1;
2242 if (src_slice_pitch && unpacking_rows && !(src_slice_pitch % src_row_pitch))
2244 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, src_slice_pitch / src_row_pitch);
2245 z_count = 1;
2247 else if (src_slice_pitch && !unpacking_rows && !(src_slice_pitch % (update_w * src_format->byte_count)))
2249 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_IMAGE_HEIGHT,
2250 src_slice_pitch / (update_w * src_format->byte_count));
2251 z_count = 1;
2253 else
2255 z_count = update_d;
2256 update_d = 1;
2259 for (z = 0; z < z_count; ++z)
2261 for (y = 0; y < y_count; ++y)
2263 const BYTE *upload_addr = &addr[z * src_slice_pitch + y * src_row_pitch];
2264 if (target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_3D)
2266 GL_EXTCALL(glTexSubImage3D(target, level, dst_x, dst_y + y, dst_z + z, update_w,
2267 update_h, update_d, format_gl->format, format_gl->type, upload_addr));
2269 else if (target == GL_TEXTURE_1D)
2271 gl_info->gl_ops.gl.p_glTexSubImage1D(target, level, dst_x,
2272 update_w, format_gl->format, format_gl->type, upload_addr);
2274 else
2276 gl_info->gl_ops.gl.p_glTexSubImage2D(target, level, dst_x, dst_y + y,
2277 update_w, update_h, format_gl->format, format_gl->type, upload_addr);
2281 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
2282 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
2283 checkGLcall("Upload texture data");
2287 static const struct d3dfmt_alpha_fixup
2289 enum wined3d_format_id format_id, conv_format_id;
2291 formats_src_alpha_fixup[] =
2293 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM},
2294 {WINED3DFMT_B5G5R5X1_UNORM, WINED3DFMT_B5G5R5A1_UNORM},
2295 {WINED3DFMT_B4G4R4X4_UNORM, WINED3DFMT_B4G4R4A4_UNORM},
2298 static enum wined3d_format_id wined3d_get_alpha_fixup_format(enum wined3d_format_id format_id,
2299 const struct wined3d_format *dst_format)
2301 unsigned int i;
2303 if (!(dst_format->attrs & WINED3D_FORMAT_ATTR_COMPRESSED) && !dst_format->alpha_size)
2304 return WINED3DFMT_UNKNOWN;
2306 for (i = 0; i < ARRAY_SIZE(formats_src_alpha_fixup); ++i)
2308 if (formats_src_alpha_fixup[i].format_id == format_id)
2309 return formats_src_alpha_fixup[i].conv_format_id;
2312 return WINED3DFMT_UNKNOWN;
2315 static void wined3d_fixup_alpha(const struct wined3d_format *format, const uint8_t *src,
2316 unsigned int src_row_pitch, uint8_t *dst, unsigned int dst_row_pitch,
2317 unsigned int width, unsigned int height)
2319 unsigned int byte_count, alpha_mask;
2320 unsigned int x, y;
2322 byte_count = format->byte_count;
2323 alpha_mask = wined3d_mask_from_size(format->alpha_size) << format->alpha_offset;
2325 switch (byte_count)
2327 case 2:
2328 for (y = 0; y < height; ++y)
2330 const uint16_t *src_row = (const uint16_t *)&src[y * src_row_pitch];
2331 uint16_t *dst_row = (uint16_t *)&dst[y * dst_row_pitch];
2333 for (x = 0; x < width; ++x)
2335 dst_row[x] = src_row[x] | alpha_mask;
2338 break;
2340 case 4:
2341 for (y = 0; y < height; ++y)
2343 const uint32_t *src_row = (const uint32_t *)&src[y * src_row_pitch];
2344 uint32_t *dst_row = (uint32_t *)&dst[y * dst_row_pitch];
2346 for (x = 0; x < width; ++x)
2348 dst_row[x] = src_row[x] | alpha_mask;
2351 break;
2353 default:
2354 ERR("Unsupported byte count %u.\n", byte_count);
2355 break;
2359 static void wined3d_texture_gl_upload_data(struct wined3d_context *context,
2360 const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *src_format,
2361 const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch,
2362 struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, unsigned int dst_location,
2363 unsigned int dst_x, unsigned int dst_y, unsigned int dst_z)
2365 struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
2366 enum wined3d_format_id alpha_fixup_format_id = WINED3DFMT_UNKNOWN;
2367 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
2368 unsigned int update_w = src_box->right - src_box->left;
2369 unsigned int update_h = src_box->bottom - src_box->top;
2370 unsigned int update_d = src_box->back - src_box->front;
2371 struct wined3d_bo_address bo;
2372 unsigned int level;
2373 BOOL srgb = FALSE;
2374 BOOL decompress;
2375 GLenum target;
2377 TRACE("context %p, src_bo_addr %s, src_format %s, src_box %s, src_row_pitch %u, src_slice_pitch %u, "
2378 "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_x %u, dst_y %u, dst_z %u.\n",
2379 context, debug_const_bo_address(src_bo_addr), debug_d3dformat(src_format->id), debug_box(src_box),
2380 src_row_pitch, src_slice_pitch, dst_texture, dst_sub_resource_idx,
2381 wined3d_debug_location(dst_location), dst_x, dst_y, dst_z);
2383 if (dst_location == WINED3D_LOCATION_TEXTURE_SRGB)
2385 srgb = TRUE;
2387 else if (dst_location != WINED3D_LOCATION_TEXTURE_RGB)
2389 FIXME("Unhandled location %s.\n", wined3d_debug_location(dst_location));
2390 return;
2393 wined3d_texture_gl_bind_and_dirtify(wined3d_texture_gl(dst_texture), wined3d_context_gl(context), srgb);
2395 if (dst_texture->sub_resources[dst_sub_resource_idx].map_count)
2397 WARN("Uploading a texture that is currently mapped, pinning sysmem.\n");
2398 dst_texture->resource.pin_sysmem = 1;
2401 if (src_format->attrs & WINED3D_FORMAT_ATTR_HEIGHT_SCALE)
2403 update_h *= src_format->height_scale.numerator;
2404 update_h /= src_format->height_scale.denominator;
2407 target = wined3d_texture_gl_get_sub_resource_target(wined3d_texture_gl(dst_texture), dst_sub_resource_idx);
2408 level = dst_sub_resource_idx % dst_texture->level_count;
2410 switch (target)
2412 case GL_TEXTURE_1D_ARRAY:
2413 dst_y = dst_sub_resource_idx / dst_texture->level_count;
2414 update_h = 1;
2415 break;
2416 case GL_TEXTURE_2D_ARRAY:
2417 dst_z = dst_sub_resource_idx / dst_texture->level_count;
2418 update_d = 1;
2419 break;
2420 case GL_TEXTURE_2D_MULTISAMPLE:
2421 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
2422 FIXME("Not supported for multisample textures.\n");
2423 return;
2426 bo.buffer_object = src_bo_addr->buffer_object;
2427 bo.addr = (BYTE *)src_bo_addr->addr + src_box->front * src_slice_pitch;
2428 if (dst_texture->resource.format_attrs & WINED3D_FORMAT_ATTR_BLOCKS)
2430 bo.addr += (src_box->top / src_format->block_height) * src_row_pitch;
2431 bo.addr += (src_box->left / src_format->block_width) * src_format->block_byte_count;
2433 else
2435 bo.addr += src_box->top * src_row_pitch;
2436 bo.addr += src_box->left * src_format->byte_count;
2439 decompress = (dst_texture->resource.format_caps & WINED3D_FORMAT_CAP_DECOMPRESS)
2440 || (src_format->decompress && src_format->id != dst_texture->resource.format->id);
2442 if (src_format->upload || decompress
2443 || (alpha_fixup_format_id = wined3d_get_alpha_fixup_format(src_format->id,
2444 dst_texture->resource.format)) != WINED3DFMT_UNKNOWN)
2446 const struct wined3d_format *compressed_format = src_format;
2447 unsigned int dst_row_pitch, dst_slice_pitch;
2448 struct wined3d_format_gl f;
2449 void *converted_mem;
2450 unsigned int z;
2451 BYTE *src_mem;
2453 if (decompress)
2455 src_format = wined3d_resource_get_decompress_format(&dst_texture->resource);
2457 else if (alpha_fixup_format_id != WINED3DFMT_UNKNOWN)
2459 src_format = wined3d_get_format(context->device->adapter, alpha_fixup_format_id, 0);
2460 assert(!!src_format);
2462 else
2464 if (dst_texture->resource.format_attrs & WINED3D_FORMAT_ATTR_BLOCKS)
2465 ERR("Converting a block-based format.\n");
2467 f = *wined3d_format_gl(src_format);
2468 f.f.byte_count = src_format->conv_byte_count;
2469 src_format = &f.f;
2472 wined3d_format_calculate_pitch(src_format, 1, update_w, update_h, &dst_row_pitch, &dst_slice_pitch);
2474 if (!(converted_mem = malloc(dst_slice_pitch)))
2476 ERR("Failed to allocate upload buffer.\n");
2477 return;
2480 src_mem = wined3d_context_gl_map_bo_address(context_gl, &bo, src_slice_pitch * update_d, WINED3D_MAP_READ);
2482 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
2483 checkGLcall("glBindBuffer");
2485 for (z = 0; z < update_d; ++z, src_mem += src_slice_pitch)
2487 if (decompress)
2488 compressed_format->decompress(src_mem, converted_mem, src_row_pitch, src_slice_pitch,
2489 dst_row_pitch, dst_slice_pitch, update_w, update_h, 1);
2490 else if (alpha_fixup_format_id != WINED3DFMT_UNKNOWN)
2491 wined3d_fixup_alpha(src_format, src_mem, src_row_pitch, converted_mem, dst_row_pitch,
2492 update_w, update_h);
2493 else
2494 src_format->upload(src_mem, converted_mem, src_row_pitch, src_slice_pitch,
2495 dst_row_pitch, dst_slice_pitch, update_w, update_h, 1);
2497 wined3d_texture_gl_upload_bo(src_format, target, level, dst_row_pitch, dst_slice_pitch, dst_x,
2498 dst_y, dst_z + z, update_w, update_h, 1, converted_mem, srgb, dst_texture, gl_info);
2501 wined3d_context_gl_unmap_bo_address(context_gl, &bo, 0, NULL);
2502 free(converted_mem);
2504 else
2506 const uint8_t *offset = bo.addr;
2508 if (bo.buffer_object)
2510 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, wined3d_bo_gl(bo.buffer_object)->id));
2511 checkGLcall("glBindBuffer");
2512 offset += bo.buffer_object->buffer_offset;
2514 else
2516 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
2517 checkGLcall("glBindBuffer");
2520 wined3d_texture_gl_upload_bo(src_format, target, level, src_row_pitch, src_slice_pitch, dst_x,
2521 dst_y, dst_z, update_w, update_h, update_d, offset, srgb, dst_texture, gl_info);
2523 if (bo.buffer_object)
2525 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
2526 wined3d_context_gl_reference_bo(context_gl, wined3d_bo_gl(bo.buffer_object));
2527 checkGLcall("glBindBuffer");
2531 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
2533 struct wined3d_device *device = dst_texture->resource.device;
2534 unsigned int i;
2536 for (i = 0; i < device->context_count; ++i)
2538 wined3d_context_gl_texture_update(wined3d_context_gl(device->contexts[i]), wined3d_texture_gl(dst_texture));
2543 static void wined3d_texture_gl_download_data_slow_path(struct wined3d_texture_gl *texture_gl,
2544 unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl, const struct wined3d_bo_address *data)
2546 struct wined3d_bo_gl *bo = wined3d_bo_gl(data->buffer_object);
2547 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
2548 struct wined3d_texture_sub_resource *sub_resource;
2549 unsigned int dst_row_pitch, dst_slice_pitch;
2550 unsigned int src_row_pitch, src_slice_pitch;
2551 const struct wined3d_format_gl *format_gl;
2552 BYTE *temporary_mem = NULL;
2553 unsigned int level;
2554 GLenum target;
2555 void *mem;
2557 format_gl = wined3d_format_gl(texture_gl->t.resource.format);
2559 /* Only support read back of converted P8 textures. */
2560 if (texture_gl->t.flags & WINED3D_TEXTURE_CONVERTED && format_gl->f.id != WINED3DFMT_P8_UINT
2561 && !format_gl->f.download)
2563 ERR("Trying to read back converted texture %p, %u with format %s.\n",
2564 texture_gl, sub_resource_idx, debug_d3dformat(format_gl->f.id));
2565 return;
2568 sub_resource = &texture_gl->t.sub_resources[sub_resource_idx];
2569 target = wined3d_texture_gl_get_sub_resource_target(texture_gl, sub_resource_idx);
2570 level = sub_resource_idx % texture_gl->t.level_count;
2572 if (target == GL_TEXTURE_1D_ARRAY || target == GL_TEXTURE_2D_ARRAY)
2574 if (format_gl->f.download)
2576 FIXME("Reading back converted array texture %p is not supported.\n", texture_gl);
2577 return;
2580 WARN_(d3d_perf)("Downloading all miplevel layers to get the data for a single sub-resource.\n");
2582 if (!(temporary_mem = calloc(texture_gl->t.layer_count, sub_resource->size)))
2584 ERR("Out of memory.\n");
2585 return;
2589 if (format_gl->f.download)
2591 struct wined3d_format f;
2593 if (bo)
2594 ERR("Converted texture %p uses PBO unexpectedly.\n", texture_gl);
2596 WARN_(d3d_perf)("Downloading converted texture %p, %u with format %s.\n",
2597 texture_gl, sub_resource_idx, debug_d3dformat(format_gl->f.id));
2599 f = format_gl->f;
2600 f.byte_count = format_gl->f.conv_byte_count;
2601 wined3d_texture_get_pitch(&texture_gl->t, level, &dst_row_pitch, &dst_slice_pitch);
2602 wined3d_format_calculate_pitch(&f, texture_gl->t.resource.device->surface_alignment,
2603 wined3d_texture_get_level_width(&texture_gl->t, level),
2604 wined3d_texture_get_level_height(&texture_gl->t, level),
2605 &src_row_pitch, &src_slice_pitch);
2607 if (!(temporary_mem = malloc(src_slice_pitch)))
2609 ERR("Failed to allocate memory.\n");
2610 return;
2614 if (temporary_mem)
2616 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
2617 checkGLcall("glBindBuffer");
2618 mem = temporary_mem;
2620 else if (bo)
2622 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, bo->id));
2623 checkGLcall("glBindBuffer");
2624 mem = (uint8_t *)data->addr + bo->b.buffer_offset;
2626 else
2628 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
2629 checkGLcall("glBindBuffer");
2630 mem = data->addr;
2633 if (texture_gl->t.resource.format_attrs & WINED3D_FORMAT_ATTR_COMPRESSED)
2635 TRACE("Downloading compressed texture %p, %u, level %u, format %#x, type %#x, data %p.\n",
2636 texture_gl, sub_resource_idx, level, format_gl->format, format_gl->type, mem);
2638 GL_EXTCALL(glGetCompressedTexImage(target, level, mem));
2639 checkGLcall("glGetCompressedTexImage");
2641 else
2643 TRACE("Downloading texture %p, %u, level %u, format %#x, type %#x, data %p.\n",
2644 texture_gl, sub_resource_idx, level, format_gl->format, format_gl->type, mem);
2646 gl_info->gl_ops.gl.p_glGetTexImage(target, level, format_gl->format, format_gl->type, mem);
2647 checkGLcall("glGetTexImage");
2650 if (format_gl->f.download)
2652 format_gl->f.download(mem, data->addr, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch,
2653 wined3d_texture_get_level_width(&texture_gl->t, level),
2654 wined3d_texture_get_level_height(&texture_gl->t, level), 1);
2656 else if (temporary_mem)
2658 unsigned int layer = sub_resource_idx / texture_gl->t.level_count;
2659 void *src_data = temporary_mem + layer * sub_resource->size;
2660 if (bo)
2662 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, bo->id));
2663 checkGLcall("glBindBuffer");
2664 GL_EXTCALL(glBufferSubData(GL_PIXEL_PACK_BUFFER,
2665 (GLintptr)data->addr + bo->b.buffer_offset, sub_resource->size, src_data));
2666 checkGLcall("glBufferSubData");
2668 else
2670 memcpy(data->addr, src_data, sub_resource->size);
2674 if (bo)
2676 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
2677 wined3d_context_gl_reference_bo(context_gl, bo);
2678 checkGLcall("glBindBuffer");
2681 free(temporary_mem);
2684 static void wined3d_texture_gl_download_data(struct wined3d_context *context,
2685 struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, unsigned int src_location,
2686 const struct wined3d_box *src_box, const struct wined3d_bo_address *dst_bo_addr,
2687 const struct wined3d_format *dst_format, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z,
2688 unsigned int dst_row_pitch, unsigned int dst_slice_pitch)
2690 struct wined3d_texture_gl *src_texture_gl = wined3d_texture_gl(src_texture);
2691 struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
2692 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
2693 unsigned int src_level, src_width, src_height, src_depth;
2694 unsigned int src_row_pitch, src_slice_pitch;
2695 const struct wined3d_format_gl *format_gl;
2696 uint8_t *offset = dst_bo_addr->addr;
2697 struct wined3d_bo *dst_bo;
2698 BOOL srgb = FALSE;
2699 GLenum target;
2701 TRACE("context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_box %s, dst_bo_addr %s, "
2702 "dst_format %s, dst_x %u, dst_y %u, dst_z %u, dst_row_pitch %u, dst_slice_pitch %u.\n",
2703 context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location),
2704 debug_box(src_box), debug_bo_address(dst_bo_addr), debug_d3dformat(dst_format->id),
2705 dst_x, dst_y, dst_z, dst_row_pitch, dst_slice_pitch);
2707 if (src_location == WINED3D_LOCATION_TEXTURE_SRGB)
2709 srgb = TRUE;
2711 else if (src_location != WINED3D_LOCATION_TEXTURE_RGB)
2713 FIXME("Unhandled location %s.\n", wined3d_debug_location(src_location));
2714 return;
2717 src_level = src_sub_resource_idx % src_texture->level_count;
2718 src_width = wined3d_texture_get_level_width(src_texture, src_level);
2719 src_height = wined3d_texture_get_level_height(src_texture, src_level);
2720 src_depth = wined3d_texture_get_level_depth(src_texture, src_level);
2721 if (src_box->left || src_box->top || src_box->right != src_width || src_box->bottom != src_height
2722 || src_box->front || src_box->back != src_depth)
2724 FIXME("Unhandled source box %s.\n", debug_box(src_box));
2725 return;
2728 if (dst_x || dst_y || dst_z)
2730 FIXME("Unhandled destination (%u, %u, %u).\n", dst_x, dst_y, dst_z);
2731 return;
2734 if (dst_format->id != src_texture->resource.format->id)
2736 FIXME("Unhandled format conversion (%s -> %s).\n",
2737 debug_d3dformat(src_texture->resource.format->id),
2738 debug_d3dformat(dst_format->id));
2739 return;
2742 wined3d_texture_get_pitch(src_texture, src_level, &src_row_pitch, &src_slice_pitch);
2743 if (src_row_pitch != dst_row_pitch || src_slice_pitch != dst_slice_pitch)
2745 FIXME("Unhandled destination pitches %u/%u (source pitches %u/%u).\n",
2746 dst_row_pitch, dst_slice_pitch, src_row_pitch, src_slice_pitch);
2747 return;
2750 wined3d_texture_gl_bind_and_dirtify(src_texture_gl, context_gl, srgb);
2752 format_gl = wined3d_format_gl(src_texture->resource.format);
2753 target = wined3d_texture_gl_get_sub_resource_target(src_texture_gl, src_sub_resource_idx);
2755 if ((src_texture->resource.type == WINED3D_RTYPE_TEXTURE_2D
2756 && (target == GL_TEXTURE_2D_ARRAY || format_gl->f.conv_byte_count
2757 || (src_texture->flags & WINED3D_TEXTURE_CONVERTED)))
2758 || target == GL_TEXTURE_1D_ARRAY)
2760 wined3d_texture_gl_download_data_slow_path(src_texture_gl, src_sub_resource_idx, context_gl, dst_bo_addr);
2761 return;
2764 if (format_gl->f.conv_byte_count)
2766 FIXME("Attempting to download a converted texture, type %s format %s.\n",
2767 debug_d3dresourcetype(src_texture->resource.type),
2768 debug_d3dformat(format_gl->f.id));
2769 return;
2772 if ((dst_bo = dst_bo_addr->buffer_object))
2774 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, wined3d_bo_gl(dst_bo)->id));
2775 checkGLcall("glBindBuffer");
2776 offset += dst_bo->buffer_offset;
2778 else
2780 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
2781 checkGLcall("glBindBuffer");
2784 if (src_texture->resource.format_attrs & WINED3D_FORMAT_ATTR_COMPRESSED)
2786 TRACE("Downloading compressed texture %p, %u, level %u, format %#x, type %#x, data %p.\n",
2787 src_texture, src_sub_resource_idx, src_level, format_gl->format, format_gl->type, offset);
2789 GL_EXTCALL(glGetCompressedTexImage(target, src_level, offset));
2790 checkGLcall("glGetCompressedTexImage");
2792 else
2794 TRACE("Downloading texture %p, %u, level %u, format %#x, type %#x, data %p.\n",
2795 src_texture, src_sub_resource_idx, src_level, format_gl->format, format_gl->type, offset);
2797 gl_info->gl_ops.gl.p_glGetTexImage(target, src_level, format_gl->format, format_gl->type, offset);
2798 checkGLcall("glGetTexImage");
2801 if (dst_bo)
2803 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
2804 wined3d_context_gl_reference_bo(context_gl, wined3d_bo_gl(dst_bo));
2805 checkGLcall("glBindBuffer");
2809 /* Context activation is done by the caller. */
2810 static BOOL wined3d_texture_gl_load_sysmem(struct wined3d_texture_gl *texture_gl,
2811 unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl, DWORD dst_location)
2813 struct wined3d_texture_sub_resource *sub_resource;
2815 sub_resource = &texture_gl->t.sub_resources[sub_resource_idx];
2817 /* We cannot download data from multisample textures directly. */
2818 if (wined3d_texture_gl_is_multisample_location(texture_gl, WINED3D_LOCATION_TEXTURE_RGB)
2819 || sub_resource->locations & WINED3D_LOCATION_RB_MULTISAMPLE)
2820 wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, &context_gl->c, WINED3D_LOCATION_RB_RESOLVED);
2822 if (sub_resource->locations & WINED3D_LOCATION_RB_RESOLVED)
2824 texture2d_read_from_framebuffer(&texture_gl->t, sub_resource_idx, &context_gl->c,
2825 WINED3D_LOCATION_RB_RESOLVED, dst_location);
2826 return TRUE;
2829 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
2831 unsigned int row_pitch, slice_pitch, level;
2832 struct wined3d_bo_address data;
2833 struct wined3d_box src_box;
2834 unsigned int src_location;
2836 level = sub_resource_idx % texture_gl->t.level_count;
2837 wined3d_texture_get_bo_address(&texture_gl->t, sub_resource_idx, &data, dst_location);
2838 src_location = sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB
2839 ? WINED3D_LOCATION_TEXTURE_RGB : WINED3D_LOCATION_TEXTURE_SRGB;
2840 wined3d_texture_get_level_box(&texture_gl->t, level, &src_box);
2841 wined3d_texture_get_pitch(&texture_gl->t, level, &row_pitch, &slice_pitch);
2842 wined3d_texture_gl_download_data(&context_gl->c, &texture_gl->t, sub_resource_idx, src_location,
2843 &src_box, &data, texture_gl->t.resource.format, 0, 0, 0, row_pitch, slice_pitch);
2845 ++texture_gl->t.download_count;
2846 return TRUE;
2849 if (sub_resource->locations & WINED3D_LOCATION_DRAWABLE)
2851 texture2d_read_from_framebuffer(&texture_gl->t, sub_resource_idx, &context_gl->c,
2852 texture_gl->t.resource.draw_binding, dst_location);
2853 return TRUE;
2856 FIXME("Can't load texture %p, %u with location flags %s into sysmem.\n",
2857 texture_gl, sub_resource_idx, wined3d_debug_location(sub_resource->locations));
2859 return FALSE;
2862 static BOOL wined3d_texture_load_drawable(struct wined3d_texture *texture,
2863 unsigned int sub_resource_idx, struct wined3d_context *context)
2865 struct wined3d_device *device;
2866 unsigned int level;
2867 RECT r;
2869 if (texture->resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL)
2871 DWORD current = texture->sub_resources[sub_resource_idx].locations;
2872 FIXME("Unimplemented copy from %s for depth/stencil buffers.\n",
2873 wined3d_debug_location(current));
2874 return FALSE;
2877 if (wined3d_resource_is_offscreen(&texture->resource))
2879 ERR("Trying to load offscreen texture into WINED3D_LOCATION_DRAWABLE.\n");
2880 return FALSE;
2883 device = texture->resource.device;
2884 level = sub_resource_idx % texture->level_count;
2885 SetRect(&r, 0, 0, wined3d_texture_get_level_width(texture, level),
2886 wined3d_texture_get_level_height(texture, level));
2887 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
2888 device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_COLOR_BLIT, context,
2889 texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &r,
2890 texture, sub_resource_idx, WINED3D_LOCATION_DRAWABLE, &r,
2891 NULL, WINED3D_TEXF_POINT, NULL);
2893 return TRUE;
2896 static BOOL wined3d_texture_load_renderbuffer(struct wined3d_texture *texture,
2897 unsigned int sub_resource_idx, struct wined3d_context *context, DWORD dst_location)
2899 unsigned int level = sub_resource_idx % texture->level_count;
2900 const RECT rect = {0, 0,
2901 wined3d_texture_get_level_width(texture, level),
2902 wined3d_texture_get_level_height(texture, level)};
2903 struct wined3d_texture_sub_resource *sub_resource;
2904 DWORD src_location, locations;
2906 sub_resource = &texture->sub_resources[sub_resource_idx];
2907 locations = sub_resource->locations;
2908 if (texture->resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL)
2910 FIXME("Unimplemented copy from %s for depth/stencil buffers.\n",
2911 wined3d_debug_location(locations));
2912 return FALSE;
2915 if (locations & WINED3D_LOCATION_RB_MULTISAMPLE)
2916 src_location = WINED3D_LOCATION_RB_MULTISAMPLE;
2917 else if (locations & WINED3D_LOCATION_RB_RESOLVED)
2918 src_location = WINED3D_LOCATION_RB_RESOLVED;
2919 else if (locations & WINED3D_LOCATION_TEXTURE_SRGB)
2920 src_location = WINED3D_LOCATION_TEXTURE_SRGB;
2921 else if (locations & WINED3D_LOCATION_TEXTURE_RGB)
2922 src_location = WINED3D_LOCATION_TEXTURE_RGB;
2923 else if (locations & WINED3D_LOCATION_DRAWABLE)
2924 src_location = WINED3D_LOCATION_DRAWABLE;
2925 else /* texture2d_blt_fbo() will load the source location if necessary. */
2926 src_location = WINED3D_LOCATION_TEXTURE_RGB;
2928 texture2d_blt_fbo(texture->resource.device, context, WINED3D_TEXF_POINT, texture,
2929 sub_resource_idx, src_location, &rect, texture, sub_resource_idx, dst_location, &rect, NULL);
2931 return TRUE;
2934 static BOOL wined3d_texture_gl_load_texture(struct wined3d_texture_gl *texture_gl,
2935 unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl, BOOL srgb)
2937 unsigned int width, height, level, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch;
2938 struct wined3d_device *device = texture_gl->t.resource.device;
2939 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
2940 const struct wined3d_color_key_conversion *conversion;
2941 struct wined3d_texture_sub_resource *sub_resource;
2942 const struct wined3d_format *format;
2943 struct wined3d_bo_address data;
2944 BYTE *src_mem, *dst_mem = NULL;
2945 struct wined3d_box src_box;
2946 DWORD dst_location;
2947 BOOL depth;
2949 depth = texture_gl->t.resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL;
2950 sub_resource = &texture_gl->t.sub_resources[sub_resource_idx];
2951 level = sub_resource_idx % texture_gl->t.level_count;
2952 wined3d_texture_get_level_box(&texture_gl->t, level, &src_box);
2954 if (!depth && sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB)
2955 && (texture_gl->t.resource.format_caps & WINED3D_FORMAT_CAP_FBO_ATTACHABLE_SRGB)
2956 && fbo_blitter_supported(WINED3D_BLIT_OP_COLOR_BLIT, gl_info,
2957 &texture_gl->t.resource, WINED3D_LOCATION_TEXTURE_RGB,
2958 &texture_gl->t.resource, WINED3D_LOCATION_TEXTURE_SRGB))
2960 RECT src_rect;
2962 SetRect(&src_rect, src_box.left, src_box.top, src_box.right, src_box.bottom);
2963 if (srgb)
2964 texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT,
2965 &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect,
2966 &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect, NULL);
2967 else
2968 texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT,
2969 &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect,
2970 &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect, NULL);
2972 return TRUE;
2975 if (!depth && sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED)
2976 && (!srgb || (texture_gl->t.resource.format_caps & WINED3D_FORMAT_CAP_FBO_ATTACHABLE_SRGB)))
2978 DWORD src_location = sub_resource->locations & WINED3D_LOCATION_RB_RESOLVED ?
2979 WINED3D_LOCATION_RB_RESOLVED : WINED3D_LOCATION_RB_MULTISAMPLE;
2980 RECT src_rect;
2982 SetRect(&src_rect, src_box.left, src_box.top, src_box.right, src_box.bottom);
2983 dst_location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
2984 if (fbo_blitter_supported(WINED3D_BLIT_OP_COLOR_BLIT, gl_info,
2985 &texture_gl->t.resource, src_location, &texture_gl->t.resource, dst_location))
2986 texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT, &texture_gl->t, sub_resource_idx,
2987 src_location, &src_rect, &texture_gl->t, sub_resource_idx, dst_location, &src_rect, NULL);
2989 return TRUE;
2992 /* Upload from system memory */
2994 if (srgb)
2996 dst_location = WINED3D_LOCATION_TEXTURE_SRGB;
2997 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | texture_gl->t.resource.map_binding))
2998 == WINED3D_LOCATION_TEXTURE_RGB)
3000 FIXME_(d3d_perf)("Downloading RGB texture %p, %u to reload it as sRGB.\n", texture_gl, sub_resource_idx);
3001 wined3d_texture_load_location(&texture_gl->t, sub_resource_idx,
3002 &context_gl->c, texture_gl->t.resource.map_binding);
3005 else
3007 dst_location = WINED3D_LOCATION_TEXTURE_RGB;
3008 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | texture_gl->t.resource.map_binding))
3009 == WINED3D_LOCATION_TEXTURE_SRGB)
3011 FIXME_(d3d_perf)("Downloading sRGB texture %p, %u to reload it as RGB.\n", texture_gl, sub_resource_idx);
3012 wined3d_texture_load_location(&texture_gl->t, sub_resource_idx,
3013 &context_gl->c, texture_gl->t.resource.map_binding);
3017 if (!(sub_resource->locations & wined3d_texture_sysmem_locations))
3019 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
3020 /* Lets hope we get it from somewhere... */
3021 wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, &context_gl->c, WINED3D_LOCATION_SYSMEM);
3024 wined3d_texture_get_pitch(&texture_gl->t, level, &src_row_pitch, &src_slice_pitch);
3026 format = texture_gl->t.resource.format;
3027 if ((conversion = wined3d_format_get_color_key_conversion(&texture_gl->t, TRUE)))
3028 format = wined3d_get_format(device->adapter, conversion->dst_format, texture_gl->t.resource.bind_flags);
3030 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
3031 * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
3032 * getting called. */
3033 if (conversion && sub_resource->bo)
3035 TRACE("Removing the pbo attached to texture %p, %u.\n", texture_gl, sub_resource_idx);
3037 wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, &context_gl->c, WINED3D_LOCATION_SYSMEM);
3038 wined3d_texture_set_map_binding(&texture_gl->t, WINED3D_LOCATION_SYSMEM);
3041 wined3d_texture_get_memory(&texture_gl->t, sub_resource_idx, &context_gl->c, &data);
3042 if (conversion)
3044 width = src_box.right - src_box.left;
3045 height = src_box.bottom - src_box.top;
3046 wined3d_format_calculate_pitch(format, device->surface_alignment,
3047 width, height, &dst_row_pitch, &dst_slice_pitch);
3049 src_mem = wined3d_context_gl_map_bo_address(context_gl, &data, src_slice_pitch, WINED3D_MAP_READ);
3050 if (!(dst_mem = malloc(dst_slice_pitch)))
3052 ERR("Out of memory (%u).\n", dst_slice_pitch);
3053 return FALSE;
3055 conversion->convert(src_mem, src_row_pitch, dst_mem, dst_row_pitch,
3056 width, height, &texture_gl->t.async.gl_color_key);
3057 src_row_pitch = dst_row_pitch;
3058 src_slice_pitch = dst_slice_pitch;
3059 wined3d_context_gl_unmap_bo_address(context_gl, &data, 0, NULL);
3061 data.buffer_object = 0;
3062 data.addr = dst_mem;
3065 wined3d_texture_gl_upload_data(&context_gl->c, wined3d_const_bo_address(&data), format, &src_box,
3066 src_row_pitch, src_slice_pitch, &texture_gl->t, sub_resource_idx, dst_location, 0, 0, 0);
3068 free(dst_mem);
3070 return TRUE;
3073 static BOOL wined3d_texture_gl_prepare_location(struct wined3d_texture *texture,
3074 unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location)
3076 struct wined3d_texture_gl *texture_gl = wined3d_texture_gl(texture);
3077 struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
3079 switch (location)
3081 case WINED3D_LOCATION_SYSMEM:
3082 return texture->sub_resources[sub_resource_idx].user_memory ? TRUE
3083 : wined3d_resource_prepare_sysmem(&texture->resource);
3085 case WINED3D_LOCATION_BUFFER:
3086 wined3d_texture_gl_prepare_buffer_object(texture_gl, sub_resource_idx, context_gl);
3087 return TRUE;
3089 case WINED3D_LOCATION_TEXTURE_RGB:
3090 wined3d_texture_gl_prepare_texture(texture_gl, context_gl, FALSE);
3091 return TRUE;
3093 case WINED3D_LOCATION_TEXTURE_SRGB:
3094 wined3d_texture_gl_prepare_texture(texture_gl, context_gl, TRUE);
3095 return TRUE;
3097 case WINED3D_LOCATION_DRAWABLE:
3098 if (!texture->swapchain)
3099 ERR("Texture %p does not have a drawable.\n", texture);
3100 return TRUE;
3102 case WINED3D_LOCATION_RB_MULTISAMPLE:
3103 wined3d_texture_gl_prepare_rb(texture_gl, context_gl->gl_info, TRUE);
3104 return TRUE;
3106 case WINED3D_LOCATION_RB_RESOLVED:
3107 wined3d_texture_gl_prepare_rb(texture_gl, context_gl->gl_info, FALSE);
3108 return TRUE;
3110 default:
3111 ERR("Invalid location %s.\n", wined3d_debug_location(location));
3112 return FALSE;
3116 static bool use_ffp_clear(const struct wined3d_texture *texture, unsigned int location)
3118 if (location == WINED3D_LOCATION_DRAWABLE)
3119 return true;
3121 if (location == WINED3D_LOCATION_TEXTURE_RGB
3122 && !(texture->resource.format_caps & WINED3D_FORMAT_CAP_FBO_ATTACHABLE))
3123 return false;
3124 if (location == WINED3D_LOCATION_TEXTURE_SRGB
3125 && !(texture->resource.format_caps & WINED3D_FORMAT_CAP_FBO_ATTACHABLE_SRGB))
3126 return false;
3128 return location & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED
3129 | WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB);
3132 static bool wined3d_texture_gl_clear(struct wined3d_texture *texture,
3133 unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl, unsigned int location)
3135 struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx];
3136 const struct wined3d_format *format = texture->resource.format;
3137 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
3138 struct wined3d_bo_address addr;
3140 /* The code that delays clears is Vulkan-specific, so here we should only
3141 * encounter WINED3D_LOCATION_CLEARED on newly created resources and thus
3142 * a zero clear value. */
3143 if (!format->depth_size && !format->stencil_size)
3145 if (sub_resource->clear_value.colour.r || sub_resource->clear_value.colour.g
3146 || sub_resource->clear_value.colour.b || sub_resource->clear_value.colour.a)
3148 ERR("Unexpected color clear value r=%08e, g=%08e, b=%08e, a=%08e.\n",
3149 sub_resource->clear_value.colour.r, sub_resource->clear_value.colour.g,
3150 sub_resource->clear_value.colour.b, sub_resource->clear_value.colour.a);
3153 else
3155 if (format->depth_size && sub_resource->clear_value.depth)
3156 ERR("Unexpected depth clear value %08e.\n", sub_resource->clear_value.depth);
3157 if (format->stencil_size && sub_resource->clear_value.stencil)
3158 ERR("Unexpected stencil clear value %x.\n", sub_resource->clear_value.stencil);
3161 if (use_ffp_clear(texture, location))
3163 GLbitfield clear_mask = 0;
3165 context_gl_apply_texture_draw_state(context_gl, texture, sub_resource_idx, location);
3167 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
3168 context_invalidate_state(&context_gl->c, STATE_RASTERIZER);
3170 if (format->depth_size)
3172 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
3173 context_invalidate_state(&context_gl->c, STATE_DEPTH_STENCIL);
3175 if (gl_info->supported[ARB_ES2_COMPATIBILITY])
3176 GL_EXTCALL(glClearDepthf(0.0f));
3177 else
3178 gl_info->gl_ops.gl.p_glClearDepth(0.0);
3179 clear_mask |= GL_DEPTH_BUFFER_BIT;
3182 if (format->stencil_size)
3184 if (gl_info->supported[EXT_STENCIL_TWO_SIDE])
3185 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3186 gl_info->gl_ops.gl.p_glStencilMask(~0u);
3187 context_invalidate_state(&context_gl->c, STATE_DEPTH_STENCIL);
3188 gl_info->gl_ops.gl.p_glClearStencil(0);
3189 clear_mask |= GL_STENCIL_BUFFER_BIT;
3192 if (!format->depth_size && !format->stencil_size)
3194 gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
3195 context_invalidate_state(&context_gl->c, STATE_BLEND);
3196 gl_info->gl_ops.gl.p_glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
3197 clear_mask |= GL_COLOR_BUFFER_BIT;
3200 gl_info->gl_ops.gl.p_glClear(clear_mask);
3201 checkGLcall("clear texture");
3203 wined3d_texture_validate_location(texture, sub_resource_idx, location);
3204 return true;
3207 if (!wined3d_texture_prepare_location(texture, sub_resource_idx, &context_gl->c, WINED3D_LOCATION_SYSMEM))
3208 return false;
3209 wined3d_texture_get_bo_address(texture, sub_resource_idx, &addr, WINED3D_LOCATION_SYSMEM);
3210 memset(addr.addr, 0, sub_resource->size);
3211 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_SYSMEM);
3212 return true;
3215 /* Context activation is done by the caller. */
3216 static BOOL wined3d_texture_gl_load_location(struct wined3d_texture *texture,
3217 unsigned int sub_resource_idx, struct wined3d_context *context, uint32_t location)
3219 struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx];
3220 struct wined3d_texture_gl *texture_gl = wined3d_texture_gl(texture);
3221 struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
3223 TRACE("texture %p, sub_resource_idx %u, context %p, location %s.\n",
3224 texture, sub_resource_idx, context, wined3d_debug_location(location));
3226 if (!wined3d_texture_gl_prepare_location(texture, sub_resource_idx, context, location))
3227 return FALSE;
3229 if (sub_resource->locations & WINED3D_LOCATION_CLEARED)
3231 if (!wined3d_texture_gl_clear(texture, sub_resource_idx, context_gl, location))
3232 return FALSE;
3234 if (sub_resource->locations & location)
3235 return TRUE;
3238 switch (location)
3240 case WINED3D_LOCATION_SYSMEM:
3241 case WINED3D_LOCATION_BUFFER:
3242 return wined3d_texture_gl_load_sysmem(texture_gl, sub_resource_idx, context_gl, location);
3244 case WINED3D_LOCATION_DRAWABLE:
3245 return wined3d_texture_load_drawable(texture, sub_resource_idx, context);
3247 case WINED3D_LOCATION_RB_RESOLVED:
3248 case WINED3D_LOCATION_RB_MULTISAMPLE:
3249 return wined3d_texture_load_renderbuffer(texture, sub_resource_idx, context, location);
3251 case WINED3D_LOCATION_TEXTURE_RGB:
3252 case WINED3D_LOCATION_TEXTURE_SRGB:
3253 return wined3d_texture_gl_load_texture(texture_gl, sub_resource_idx,
3254 context_gl, location == WINED3D_LOCATION_TEXTURE_SRGB);
3256 default:
3257 FIXME("Unhandled %s load from %s.\n", wined3d_debug_location(location),
3258 wined3d_debug_location(texture->sub_resources[sub_resource_idx].locations));
3259 return FALSE;
3263 static void wined3d_texture_gl_unload_location(struct wined3d_texture *texture,
3264 struct wined3d_context *context, unsigned int location)
3266 struct wined3d_texture_gl *texture_gl = wined3d_texture_gl(texture);
3267 struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
3268 struct wined3d_renderbuffer_entry *entry, *entry2;
3269 unsigned int i, sub_count;
3271 TRACE("texture %p, context %p, location %s.\n", texture, context, wined3d_debug_location(location));
3273 switch (location)
3275 case WINED3D_LOCATION_BUFFER:
3276 sub_count = texture->level_count * texture->layer_count;
3277 for (i = 0; i < sub_count; ++i)
3279 if (texture_gl->t.sub_resources[i].bo)
3280 wined3d_texture_remove_buffer_object(&texture_gl->t, i, context_gl);
3282 break;
3284 case WINED3D_LOCATION_TEXTURE_RGB:
3285 if (texture_gl->texture_rgb.name)
3286 gltexture_delete(texture_gl->t.resource.device, context_gl->gl_info, &texture_gl->texture_rgb);
3287 break;
3289 case WINED3D_LOCATION_TEXTURE_SRGB:
3290 if (texture_gl->texture_srgb.name)
3291 gltexture_delete(texture_gl->t.resource.device, context_gl->gl_info, &texture_gl->texture_srgb);
3292 break;
3294 case WINED3D_LOCATION_RB_MULTISAMPLE:
3295 if (texture_gl->rb_multisample)
3297 TRACE("Deleting multisample renderbuffer %u.\n", texture_gl->rb_multisample);
3298 context_gl_resource_released(texture_gl->t.resource.device, texture_gl->rb_multisample, TRUE);
3299 context_gl->gl_info->fbo_ops.glDeleteRenderbuffers(1, &texture_gl->rb_multisample);
3300 texture_gl->rb_multisample = 0;
3302 break;
3304 case WINED3D_LOCATION_RB_RESOLVED:
3305 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &texture_gl->renderbuffers,
3306 struct wined3d_renderbuffer_entry, entry)
3308 context_gl_resource_released(texture_gl->t.resource.device, entry->id, TRUE);
3309 context_gl->gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
3310 list_remove(&entry->entry);
3311 free(entry);
3313 list_init(&texture_gl->renderbuffers);
3314 texture_gl->current_renderbuffer = NULL;
3316 if (texture_gl->rb_resolved)
3318 TRACE("Deleting resolved renderbuffer %u.\n", texture_gl->rb_resolved);
3319 context_gl_resource_released(texture_gl->t.resource.device, texture_gl->rb_resolved, TRUE);
3320 context_gl->gl_info->fbo_ops.glDeleteRenderbuffers(1, &texture_gl->rb_resolved);
3321 texture_gl->rb_resolved = 0;
3323 break;
3325 default:
3326 ERR("Unhandled location %s.\n", wined3d_debug_location(location));
3327 break;
3331 static const struct wined3d_texture_ops texture_gl_ops =
3333 wined3d_texture_gl_prepare_location,
3334 wined3d_texture_gl_load_location,
3335 wined3d_texture_gl_unload_location,
3336 wined3d_texture_gl_upload_data,
3337 wined3d_texture_gl_download_data,
3340 struct wined3d_texture * __cdecl wined3d_texture_from_resource(struct wined3d_resource *resource)
3342 return texture_from_resource(resource);
3345 static ULONG texture_resource_incref(struct wined3d_resource *resource)
3347 return wined3d_texture_incref(texture_from_resource(resource));
3350 static ULONG texture_resource_decref(struct wined3d_resource *resource)
3352 return wined3d_texture_decref(texture_from_resource(resource));
3355 static void texture_resource_preload(struct wined3d_resource *resource)
3357 struct wined3d_texture *texture = texture_from_resource(resource);
3358 struct wined3d_context *context;
3360 context = context_acquire(resource->device, NULL, 0);
3361 wined3d_texture_load(texture, context, texture->flags & WINED3D_TEXTURE_IS_SRGB);
3362 context_release(context);
3365 static void texture_resource_unload(struct wined3d_resource *resource)
3367 struct wined3d_texture *texture = texture_from_resource(resource);
3368 struct wined3d_device *device = resource->device;
3369 unsigned int location = resource->map_binding;
3370 struct wined3d_context *context;
3371 unsigned int sub_count, i;
3373 TRACE("resource %p.\n", resource);
3375 /* D3D is not initialised, so no GPU locations should currently exist.
3376 * Moreover, we may not be able to acquire a valid context. */
3377 if (!device->d3d_initialized)
3378 return;
3380 context = context_acquire(device, NULL, 0);
3382 if (location == WINED3D_LOCATION_BUFFER)
3383 location = WINED3D_LOCATION_SYSMEM;
3385 sub_count = texture->level_count * texture->layer_count;
3386 for (i = 0; i < sub_count; ++i)
3388 if (resource->access & WINED3D_RESOURCE_ACCESS_CPU
3389 && wined3d_texture_load_location(texture, i, context, location))
3391 wined3d_texture_invalidate_location(texture, i, ~location);
3393 else
3395 if (resource->access & WINED3D_RESOURCE_ACCESS_CPU)
3396 ERR("Discarding %s %p sub-resource %u with resource access %s.\n",
3397 debug_d3dresourcetype(resource->type), resource, i,
3398 wined3d_debug_resource_access(resource->access));
3399 wined3d_texture_validate_location(texture, i, WINED3D_LOCATION_DISCARDED);
3400 wined3d_texture_invalidate_location(texture, i, ~WINED3D_LOCATION_DISCARDED);
3404 wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_BUFFER);
3405 wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_TEXTURE_RGB);
3406 wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_TEXTURE_SRGB);
3407 wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_RB_MULTISAMPLE);
3408 wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_RB_RESOLVED);
3410 context_release(context);
3412 wined3d_texture_force_reload(texture);
3414 if (texture->resource.bind_count && (texture->resource.bind_flags & WINED3D_BIND_SHADER_RESOURCE))
3415 device_invalidate_state(device, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
3417 wined3d_texture_set_dirty(texture);
3419 resource_unload(&texture->resource);
3422 static HRESULT texture_resource_sub_resource_get_desc(struct wined3d_resource *resource,
3423 unsigned int sub_resource_idx, struct wined3d_sub_resource_desc *desc)
3425 const struct wined3d_texture *texture = texture_from_resource(resource);
3427 return wined3d_texture_get_sub_resource_desc(texture, sub_resource_idx, desc);
3430 static void texture_resource_sub_resource_get_map_pitch(struct wined3d_resource *resource,
3431 unsigned int sub_resource_idx, unsigned int *row_pitch, unsigned int *slice_pitch)
3433 const struct wined3d_texture *texture = texture_from_resource(resource);
3434 unsigned int level = sub_resource_idx % texture->level_count;
3436 if (resource->format_attrs & WINED3D_FORMAT_ATTR_BROKEN_PITCH)
3438 *row_pitch = wined3d_texture_get_level_width(texture, level) * resource->format->byte_count;
3439 *slice_pitch = wined3d_texture_get_level_height(texture, level) * (*row_pitch);
3441 else
3443 wined3d_texture_get_pitch(texture, level, row_pitch, slice_pitch);
3447 static HRESULT texture_resource_sub_resource_map(struct wined3d_resource *resource, unsigned int sub_resource_idx,
3448 void **map_ptr, const struct wined3d_box *box, uint32_t flags)
3450 struct wined3d_texture_sub_resource *sub_resource;
3451 struct wined3d_device *device = resource->device;
3452 struct wined3d_context *context;
3453 struct wined3d_texture *texture;
3454 struct wined3d_bo_address data;
3455 unsigned int texture_level;
3456 BYTE *base_memory;
3457 BOOL ret = TRUE;
3459 TRACE("resource %p, sub_resource_idx %u, map_ptr %p, box %s, flags %#x.\n",
3460 resource, sub_resource_idx, map_ptr, debug_box(box), flags);
3462 texture = texture_from_resource(resource);
3463 sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx);
3465 texture_level = sub_resource_idx % texture->level_count;
3467 if (texture->flags & WINED3D_TEXTURE_DC_IN_USE)
3469 WARN("DC is in use.\n");
3470 return WINED3DERR_INVALIDCALL;
3473 if (sub_resource->map_count)
3475 WARN("Sub-resource is already mapped.\n");
3476 return WINED3DERR_INVALIDCALL;
3479 context = context_acquire(device, NULL, 0);
3481 if (flags & WINED3D_MAP_DISCARD)
3483 TRACE("WINED3D_MAP_DISCARD flag passed, marking %s as up to date.\n",
3484 wined3d_debug_location(resource->map_binding));
3485 if ((ret = wined3d_texture_prepare_location(texture, sub_resource_idx, context, resource->map_binding)))
3486 wined3d_texture_validate_location(texture, sub_resource_idx, resource->map_binding);
3488 else
3490 if (resource->usage & WINED3DUSAGE_DYNAMIC)
3491 WARN_(d3d_perf)("Mapping a dynamic texture without WINED3D_MAP_DISCARD.\n");
3492 if (!texture_level)
3494 unsigned int i;
3496 for (i = 0; i < texture->level_count; ++i)
3498 if (!(ret = wined3d_texture_load_location(texture, sub_resource_idx + i, context, resource->map_binding)))
3499 break;
3502 else
3504 ret = wined3d_texture_load_location(texture, sub_resource_idx, context, resource->map_binding);
3508 if (!ret)
3510 ERR("Failed to prepare location.\n");
3511 context_release(context);
3512 return E_OUTOFMEMORY;
3515 /* We only record dirty regions for the top-most level. */
3516 if (texture->dirty_regions && flags & WINED3D_MAP_WRITE
3517 && !(flags & WINED3D_MAP_NO_DIRTY_UPDATE) && !texture_level)
3518 wined3d_texture_dirty_region_add(texture, sub_resource_idx / texture->level_count, box);
3520 if (flags & WINED3D_MAP_WRITE)
3522 if (!texture_level)
3524 unsigned int i;
3526 for (i = 0; i < texture->level_count; ++i)
3527 wined3d_texture_invalidate_location(texture, sub_resource_idx + i, ~resource->map_binding);
3529 else
3531 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~resource->map_binding);
3535 wined3d_texture_get_bo_address(texture, sub_resource_idx, &data, resource->map_binding);
3536 base_memory = wined3d_context_map_bo_address(context, &data, sub_resource->size, flags);
3537 sub_resource->map_flags = flags;
3538 TRACE("Base memory pointer %p.\n", base_memory);
3540 context_release(context);
3542 *map_ptr = resource_offset_map_pointer(resource, sub_resource_idx, base_memory, box);
3544 if (texture->swapchain && texture->swapchain->front_buffer == texture)
3546 RECT *r = &texture->swapchain->front_buffer_update;
3548 SetRect(r, box->left, box->top, box->right, box->bottom);
3549 TRACE("Mapped front buffer %s.\n", wine_dbgstr_rect(r));
3552 ++resource->map_count;
3553 ++sub_resource->map_count;
3555 TRACE("Returning memory %p.\n", *map_ptr);
3557 return WINED3D_OK;
3560 static HRESULT texture_resource_sub_resource_unmap(struct wined3d_resource *resource, unsigned int sub_resource_idx)
3562 struct wined3d_texture_sub_resource *sub_resource;
3563 struct wined3d_device *device = resource->device;
3564 struct wined3d_context *context;
3565 struct wined3d_texture *texture;
3566 struct wined3d_bo_address data;
3567 struct wined3d_range range;
3569 TRACE("resource %p, sub_resource_idx %u.\n", resource, sub_resource_idx);
3571 texture = texture_from_resource(resource);
3572 if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx)))
3573 return E_INVALIDARG;
3575 if (!sub_resource->map_count)
3577 WARN("Trying to unmap unmapped sub-resource.\n");
3578 if (texture->flags & WINED3D_TEXTURE_DC_IN_USE)
3579 return WINED3D_OK;
3580 return WINEDDERR_NOTLOCKED;
3583 context = context_acquire(device, NULL, 0);
3585 wined3d_texture_get_bo_address(texture, sub_resource_idx, &data, texture->resource.map_binding);
3586 range.offset = 0;
3587 range.size = sub_resource->size;
3588 wined3d_context_unmap_bo_address(context, &data, !!(sub_resource->map_flags & WINED3D_MAP_WRITE), &range);
3590 context_release(context);
3592 if (texture->swapchain && texture->swapchain->front_buffer == texture)
3594 if (!(sub_resource->locations & (WINED3D_LOCATION_DRAWABLE | WINED3D_LOCATION_TEXTURE_RGB)))
3595 texture->swapchain->swapchain_ops->swapchain_frontbuffer_updated(texture->swapchain);
3598 --sub_resource->map_count;
3599 if (!--resource->map_count && texture->update_map_binding)
3600 wined3d_texture_update_map_binding(texture);
3602 return WINED3D_OK;
3605 static const struct wined3d_resource_ops texture_resource_ops =
3607 texture_resource_incref,
3608 texture_resource_decref,
3609 texture_resource_preload,
3610 texture_resource_unload,
3611 texture_resource_sub_resource_get_desc,
3612 texture_resource_sub_resource_get_map_pitch,
3613 texture_resource_sub_resource_map,
3614 texture_resource_sub_resource_unmap,
3617 static HRESULT wined3d_texture_init(struct wined3d_texture *texture, const struct wined3d_resource_desc *desc,
3618 unsigned int layer_count, unsigned int level_count, uint32_t flags, struct wined3d_device *device,
3619 void *parent, const struct wined3d_parent_ops *parent_ops, void *sub_resources,
3620 const struct wined3d_texture_ops *texture_ops)
3622 const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info;
3623 struct wined3d_device_parent *device_parent = device->device_parent;
3624 unsigned int sub_count, i, j, size, offset = 0;
3625 const struct wined3d_format *format;
3626 HRESULT hr;
3628 TRACE("texture %p, resource_type %s, format %s, multisample_type %#x, multisample_quality %#x, "
3629 "usage %s, bind_flags %s, access %s, width %u, height %u, depth %u, layer_count %u, level_count %u, "
3630 "flags %#x, device %p, parent %p, parent_ops %p, sub_resources %p, texture_ops %p.\n",
3631 texture, debug_d3dresourcetype(desc->resource_type), debug_d3dformat(desc->format), desc->multisample_type,
3632 desc->multisample_quality, debug_d3dusage(desc->usage), wined3d_debug_bind_flags(desc->bind_flags),
3633 wined3d_debug_resource_access(desc->access), desc->width, desc->height, desc->depth,
3634 layer_count, level_count, flags, device, parent, parent_ops, sub_resources, texture_ops);
3636 if (!desc->width || !desc->height || !desc->depth)
3637 return WINED3DERR_INVALIDCALL;
3639 if (desc->resource_type == WINED3D_RTYPE_TEXTURE_3D && layer_count != 1)
3641 ERR("Invalid layer count for volume texture.\n");
3642 return E_INVALIDARG;
3645 texture->sub_resources = sub_resources;
3647 /* TODO: It should only be possible to create textures for formats
3648 * that are reported as supported. */
3649 if (WINED3DFMT_UNKNOWN >= desc->format)
3651 WARN("Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n");
3652 return WINED3DERR_INVALIDCALL;
3654 format = wined3d_get_format(device->adapter, desc->format, desc->bind_flags);
3656 if ((desc->usage & WINED3DUSAGE_DYNAMIC) && (desc->usage & (WINED3DUSAGE_MANAGED | WINED3DUSAGE_SCRATCH)))
3658 WARN("Attempted to create a dynamic texture with usage %s.\n", debug_d3dusage(desc->usage));
3659 return WINED3DERR_INVALIDCALL;
3662 if (((desc->width & (desc->width - 1)) || (desc->height & (desc->height - 1)) || (desc->depth & (desc->depth - 1)))
3663 && !d3d_info->unconditional_npot)
3665 /* level_count == 0 returns an error as well. */
3666 if (level_count != 1 || layer_count != 1 || desc->resource_type == WINED3D_RTYPE_TEXTURE_3D)
3668 if (!(desc->usage & WINED3DUSAGE_SCRATCH))
3670 WARN("Attempted to create a mipmapped/cube/array/volume NPOT "
3671 "texture without unconditional NPOT support.\n");
3672 return WINED3DERR_INVALIDCALL;
3675 WARN("Creating a scratch mipmapped/cube/array NPOT texture despite lack of HW support.\n");
3677 texture->flags |= WINED3D_TEXTURE_COND_NP2;
3680 if ((desc->width > d3d_info->limits.texture_size || desc->height > d3d_info->limits.texture_size)
3681 && (desc->bind_flags & WINED3D_BIND_SHADER_RESOURCE))
3683 /* One of four options:
3684 * 1: Scale the texture. (Any texture ops would require the texture to
3685 * be scaled which is potentially slow.)
3686 * 2: Set the texture to the maximum size (bad idea).
3687 * 3: WARN and return WINED3DERR_NOTAVAILABLE.
3688 * 4: Create the surface, but allow it to be used only for DirectDraw
3689 * Blts. Some apps (e.g. Swat 3) create textures with a height of
3690 * 16 and a width > 3000 and blt 16x16 letter areas from them to
3691 * the render target. */
3692 if (desc->access & WINED3D_RESOURCE_ACCESS_GPU)
3694 WARN("Dimensions (%ux%u) exceed the maximum texture size.\n", desc->width, desc->height);
3695 return WINED3DERR_NOTAVAILABLE;
3698 /* We should never use this surface in combination with OpenGL. */
3699 TRACE("Creating an oversized (%ux%u) surface.\n", desc->width, desc->height);
3702 for (i = 0; i < layer_count; ++i)
3704 for (j = 0; j < level_count; ++j)
3706 unsigned int idx = i * level_count + j;
3708 size = wined3d_format_calculate_size(format, device->surface_alignment,
3709 max(1, desc->width >> j), max(1, desc->height >> j), max(1, desc->depth >> j));
3710 texture->sub_resources[idx].offset = offset;
3711 texture->sub_resources[idx].size = size;
3712 offset += size;
3714 offset = (offset + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1);
3717 if (!offset)
3718 return WINED3DERR_INVALIDCALL;
3720 /* Ensure the last mip-level is at least large enough to hold a single
3721 * compressed block. It is questionable how useful these mip-levels are to
3722 * the application with "broken pitch" formats, but we want to avoid
3723 * memory corruption when loading textures into WINED3D_LOCATION_SYSMEM. */
3724 if (format->attrs & WINED3D_FORMAT_ATTR_BROKEN_PITCH)
3726 unsigned int min_size;
3728 min_size = texture->sub_resources[level_count * layer_count - 1].offset + format->block_byte_count;
3729 min_size = (min_size + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1);
3730 if (min_size > offset)
3731 offset = min_size;
3734 if (FAILED(hr = resource_init(&texture->resource, device, desc->resource_type, format,
3735 desc->multisample_type, desc->multisample_quality, desc->usage, desc->bind_flags, desc->access,
3736 desc->width, desc->height, desc->depth, offset, parent, parent_ops, &texture_resource_ops)))
3738 static unsigned int once;
3740 /* DXTn 3D textures are not supported. Do not write the ERR for them. */
3741 if ((desc->format == WINED3DFMT_DXT1 || desc->format == WINED3DFMT_DXT2 || desc->format == WINED3DFMT_DXT3
3742 || desc->format == WINED3DFMT_DXT4 || desc->format == WINED3DFMT_DXT5)
3743 && !(format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_TEXTURE)
3744 && desc->resource_type != WINED3D_RTYPE_TEXTURE_3D && !once++)
3745 ERR_(winediag)("The application tried to create a DXTn texture, but the driver does not support them.\n");
3747 WARN("Failed to initialize resource, returning %#lx\n", hr);
3748 return hr;
3750 wined3d_resource_update_draw_binding(&texture->resource);
3752 texture->texture_ops = texture_ops;
3754 texture->layer_count = layer_count;
3755 texture->level_count = level_count;
3756 texture->lod = 0;
3757 texture->flags |= WINED3D_TEXTURE_DOWNLOADABLE;
3758 if (flags & WINED3D_TEXTURE_CREATE_GET_DC_LENIENT)
3760 texture->flags |= WINED3D_TEXTURE_GET_DC_LENIENT;
3761 texture->resource.pin_sysmem = 1;
3763 if (flags & (WINED3D_TEXTURE_CREATE_GET_DC | WINED3D_TEXTURE_CREATE_GET_DC_LENIENT))
3764 texture->flags |= WINED3D_TEXTURE_GET_DC;
3765 if (flags & WINED3D_TEXTURE_CREATE_DISCARD)
3766 texture->flags |= WINED3D_TEXTURE_DISCARD;
3767 if (flags & WINED3D_TEXTURE_CREATE_GENERATE_MIPMAPS)
3769 if (!(texture->resource.format_caps & WINED3D_FORMAT_CAP_GEN_MIPMAP))
3770 WARN("Format doesn't support mipmaps generation, "
3771 "ignoring WINED3D_TEXTURE_CREATE_GENERATE_MIPMAPS flag.\n");
3772 else
3773 texture->flags |= WINED3D_TEXTURE_GENERATE_MIPMAPS;
3776 if (flags & WINED3D_TEXTURE_CREATE_RECORD_DIRTY_REGIONS)
3778 if (!(texture->dirty_regions = calloc(texture->layer_count, sizeof(*texture->dirty_regions))))
3780 wined3d_texture_cleanup_sync(texture);
3781 return E_OUTOFMEMORY;
3783 for (i = 0; i < texture->layer_count; ++i)
3784 wined3d_texture_dirty_region_add(texture, i, NULL);
3787 if (wined3d_texture_use_pbo(texture, d3d_info))
3788 texture->resource.map_binding = WINED3D_LOCATION_BUFFER;
3790 sub_count = level_count * layer_count;
3791 if (sub_count / layer_count != level_count)
3793 wined3d_texture_cleanup_sync(texture);
3794 return E_OUTOFMEMORY;
3797 if (desc->usage & WINED3DUSAGE_OVERLAY)
3799 if (!(texture->overlay_info = calloc(sub_count, sizeof(*texture->overlay_info))))
3801 wined3d_texture_cleanup_sync(texture);
3802 return E_OUTOFMEMORY;
3805 for (i = 0; i < sub_count; ++i)
3807 list_init(&texture->overlay_info[i].entry);
3808 list_init(&texture->overlay_info[i].overlays);
3812 /* Generate all sub-resources. */
3813 for (i = 0; i < sub_count; ++i)
3815 struct wined3d_texture_sub_resource *sub_resource;
3817 sub_resource = &texture->sub_resources[i];
3818 sub_resource->locations = WINED3D_LOCATION_CLEARED;
3820 if (FAILED(hr = device_parent->ops->texture_sub_resource_created(device_parent,
3821 desc->resource_type, texture, i, &sub_resource->parent, &sub_resource->parent_ops)))
3823 WARN("Failed to create sub-resource parent, hr %#lx.\n", hr);
3824 sub_resource->parent = NULL;
3825 wined3d_texture_cleanup_sync(texture);
3826 return hr;
3829 TRACE("parent %p, parent_ops %p.\n", sub_resource->parent, sub_resource->parent_ops);
3831 TRACE("Created sub-resource %u (level %u, layer %u).\n",
3832 i, i % texture->level_count, i / texture->level_count);
3834 if (desc->usage & WINED3DUSAGE_OWNDC)
3836 struct wined3d_texture_idx texture_idx = {texture, i};
3838 wined3d_cs_init_object(device->cs, wined3d_texture_create_dc, &texture_idx);
3839 wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
3840 if (!texture->dc_info || !texture->dc_info[i].dc)
3842 wined3d_texture_cleanup_sync(texture);
3843 return WINED3DERR_INVALIDCALL;
3848 return WINED3D_OK;
3851 HRESULT CDECL wined3d_device_context_blt(struct wined3d_device_context *context,
3852 struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, const RECT *dst_rect,
3853 struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, const RECT *src_rect,
3854 unsigned int flags, const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
3856 struct wined3d_box src_box = {src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1};
3857 struct wined3d_box dst_box = {dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, 0, 1};
3858 HRESULT hr;
3860 TRACE("context %p, dst_texture %p, dst_sub_resource_idx %u, dst_rect %s, src_texture %p, "
3861 "src_sub_resource_idx %u, src_rect %s, flags %#x, fx %p, filter %s.\n",
3862 context, dst_texture, dst_sub_resource_idx, wine_dbgstr_rect(dst_rect), src_texture,
3863 src_sub_resource_idx, wine_dbgstr_rect(src_rect), flags, fx, debug_d3dtexturefiltertype(filter));
3865 if (!wined3d_texture_validate_sub_resource_idx(dst_texture, dst_sub_resource_idx)
3866 || dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
3867 return WINED3DERR_INVALIDCALL;
3869 if (!wined3d_texture_validate_sub_resource_idx(src_texture, src_sub_resource_idx)
3870 || src_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
3871 return WINED3DERR_INVALIDCALL;
3873 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
3874 && filter != WINED3D_TEXF_LINEAR)
3875 return WINED3DERR_INVALIDCALL;
3877 if (FAILED(hr = wined3d_resource_check_box_dimensions(&dst_texture->resource, dst_sub_resource_idx, &dst_box)))
3878 return hr;
3880 if (FAILED(hr = wined3d_resource_check_box_dimensions(&src_texture->resource, src_sub_resource_idx, &src_box)))
3881 return hr;
3883 if (dst_texture->sub_resources[dst_sub_resource_idx].map_count
3884 || src_texture->sub_resources[src_sub_resource_idx].map_count)
3886 WARN("Sub-resource is busy, returning WINEDDERR_SURFACEBUSY.\n");
3887 return WINEDDERR_SURFACEBUSY;
3890 if (!src_texture->resource.format->depth_size != !dst_texture->resource.format->depth_size
3891 || !src_texture->resource.format->stencil_size != !dst_texture->resource.format->stencil_size)
3893 WARN("Rejecting depth/stencil blit between incompatible formats.\n");
3894 return WINED3DERR_INVALIDCALL;
3897 if (dst_texture->resource.device != src_texture->resource.device)
3899 FIXME("Rejecting cross-device blit.\n");
3900 return E_NOTIMPL;
3903 wined3d_device_context_emit_blt_sub_resource(context, &dst_texture->resource, dst_sub_resource_idx,
3904 &dst_box, &src_texture->resource, src_sub_resource_idx, &src_box, flags, fx, filter);
3906 if (dst_texture->dirty_regions)
3907 wined3d_texture_add_dirty_region(dst_texture, dst_sub_resource_idx, &dst_box);
3909 return WINED3D_OK;
3912 HRESULT CDECL wined3d_texture_get_overlay_position(const struct wined3d_texture *texture,
3913 unsigned int sub_resource_idx, LONG *x, LONG *y)
3915 struct wined3d_overlay_info *overlay;
3917 TRACE("texture %p, sub_resource_idx %u, x %p, y %p.\n", texture, sub_resource_idx, x, y);
3919 if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY)
3920 || !wined3d_texture_validate_sub_resource_idx(texture, sub_resource_idx))
3921 return WINEDDERR_NOTAOVERLAYSURFACE;
3923 overlay = &texture->overlay_info[sub_resource_idx];
3924 if (!overlay->dst_texture)
3926 TRACE("Overlay not visible.\n");
3927 *x = 0;
3928 *y = 0;
3929 return WINEDDERR_OVERLAYNOTVISIBLE;
3932 *x = overlay->dst_rect.left;
3933 *y = overlay->dst_rect.top;
3935 TRACE("Returning position %ld, %ld.\n", *x, *y);
3937 return WINED3D_OK;
3940 HRESULT CDECL wined3d_texture_set_overlay_position(struct wined3d_texture *texture,
3941 unsigned int sub_resource_idx, LONG x, LONG y)
3943 struct wined3d_overlay_info *overlay;
3944 LONG w, h;
3946 TRACE("texture %p, sub_resource_idx %u, x %ld, y %ld.\n", texture, sub_resource_idx, x, y);
3948 if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY)
3949 || !wined3d_texture_validate_sub_resource_idx(texture, sub_resource_idx))
3950 return WINEDDERR_NOTAOVERLAYSURFACE;
3952 overlay = &texture->overlay_info[sub_resource_idx];
3953 w = overlay->dst_rect.right - overlay->dst_rect.left;
3954 h = overlay->dst_rect.bottom - overlay->dst_rect.top;
3955 SetRect(&overlay->dst_rect, x, y, x + w, y + h);
3957 return WINED3D_OK;
3960 HRESULT CDECL wined3d_texture_update_overlay(struct wined3d_texture *texture, unsigned int sub_resource_idx,
3961 const RECT *src_rect, struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3962 const RECT *dst_rect, uint32_t flags)
3964 struct wined3d_overlay_info *overlay;
3965 unsigned int level, dst_level;
3967 TRACE("texture %p, sub_resource_idx %u, src_rect %s, dst_texture %p, "
3968 "dst_sub_resource_idx %u, dst_rect %s, flags %#x.\n",
3969 texture, sub_resource_idx, wine_dbgstr_rect(src_rect), dst_texture,
3970 dst_sub_resource_idx, wine_dbgstr_rect(dst_rect), flags);
3972 if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY) || texture->resource.type != WINED3D_RTYPE_TEXTURE_2D
3973 || !wined3d_texture_validate_sub_resource_idx(texture, sub_resource_idx))
3974 return WINEDDERR_NOTAOVERLAYSURFACE;
3976 if (!dst_texture || dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D
3977 || !wined3d_texture_validate_sub_resource_idx(dst_texture, dst_sub_resource_idx))
3978 return WINED3DERR_INVALIDCALL;
3980 overlay = &texture->overlay_info[sub_resource_idx];
3982 level = sub_resource_idx % texture->level_count;
3983 if (src_rect)
3984 overlay->src_rect = *src_rect;
3985 else
3986 SetRect(&overlay->src_rect, 0, 0,
3987 wined3d_texture_get_level_width(texture, level),
3988 wined3d_texture_get_level_height(texture, level));
3990 dst_level = dst_sub_resource_idx % dst_texture->level_count;
3991 if (dst_rect)
3992 overlay->dst_rect = *dst_rect;
3993 else
3994 SetRect(&overlay->dst_rect, 0, 0,
3995 wined3d_texture_get_level_width(dst_texture, dst_level),
3996 wined3d_texture_get_level_height(dst_texture, dst_level));
3998 if (overlay->dst_texture && (overlay->dst_texture != dst_texture
3999 || overlay->dst_sub_resource_idx != dst_sub_resource_idx || flags & WINEDDOVER_HIDE))
4001 overlay->dst_texture = NULL;
4002 list_remove(&overlay->entry);
4005 if (flags & WINEDDOVER_SHOW)
4007 if (overlay->dst_texture != dst_texture || overlay->dst_sub_resource_idx != dst_sub_resource_idx)
4009 overlay->dst_texture = dst_texture;
4010 overlay->dst_sub_resource_idx = dst_sub_resource_idx;
4011 list_add_tail(&texture->overlay_info[dst_sub_resource_idx].overlays, &overlay->entry);
4014 else if (flags & WINEDDOVER_HIDE)
4016 /* Tests show that the rectangles are erased on hide. */
4017 SetRectEmpty(&overlay->src_rect);
4018 SetRectEmpty(&overlay->dst_rect);
4019 overlay->dst_texture = NULL;
4022 return WINED3D_OK;
4025 struct wined3d_swapchain * CDECL wined3d_texture_get_swapchain(struct wined3d_texture *texture)
4027 return texture->swapchain;
4030 void * CDECL wined3d_texture_get_sub_resource_parent(struct wined3d_texture *texture, unsigned int sub_resource_idx)
4032 TRACE("texture %p, sub_resource_idx %u.\n", texture, sub_resource_idx);
4034 if (!wined3d_texture_validate_sub_resource_idx(texture, sub_resource_idx))
4035 return NULL;
4037 return texture->sub_resources[sub_resource_idx].parent;
4040 void CDECL wined3d_texture_set_sub_resource_parent(struct wined3d_texture *texture,
4041 unsigned int sub_resource_idx, void *parent, const struct wined3d_parent_ops *parent_ops)
4043 TRACE("texture %p, sub_resource_idx %u, parent %p.\n", texture, sub_resource_idx, parent);
4045 if (!wined3d_texture_validate_sub_resource_idx(texture, sub_resource_idx))
4046 return;
4048 texture->sub_resources[sub_resource_idx].parent = parent;
4049 texture->sub_resources[sub_resource_idx].parent_ops = parent_ops;
4052 HRESULT CDECL wined3d_texture_get_sub_resource_desc(const struct wined3d_texture *texture,
4053 unsigned int sub_resource_idx, struct wined3d_sub_resource_desc *desc)
4055 const struct wined3d_resource *resource;
4056 unsigned int level_idx;
4058 TRACE("texture %p, sub_resource_idx %u, desc %p.\n", texture, sub_resource_idx, desc);
4060 if (!wined3d_texture_validate_sub_resource_idx(texture, sub_resource_idx))
4061 return WINED3DERR_INVALIDCALL;
4063 resource = &texture->resource;
4064 desc->format = resource->format->id;
4065 desc->multisample_type = resource->multisample_type;
4066 desc->multisample_quality = resource->multisample_quality;
4067 desc->usage = resource->usage;
4068 desc->bind_flags = resource->bind_flags;
4069 desc->access = resource->access;
4071 level_idx = sub_resource_idx % texture->level_count;
4072 desc->width = wined3d_texture_get_level_width(texture, level_idx);
4073 desc->height = wined3d_texture_get_level_height(texture, level_idx);
4074 desc->depth = wined3d_texture_get_level_depth(texture, level_idx);
4075 desc->size = texture->sub_resources[sub_resource_idx].size;
4077 return WINED3D_OK;
4080 HRESULT wined3d_texture_gl_init(struct wined3d_texture_gl *texture_gl, struct wined3d_device *device,
4081 const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count,
4082 uint32_t flags, void *parent, const struct wined3d_parent_ops *parent_ops)
4084 const struct wined3d_gl_info *gl_info = &wined3d_adapter_gl(device->adapter)->gl_info;
4085 HRESULT hr;
4087 TRACE("texture_gl %p, device %p, desc %p, layer_count %u, "
4088 "level_count %u, flags %#x, parent %p, parent_ops %p.\n",
4089 texture_gl, device, desc, layer_count,
4090 level_count, flags, parent, parent_ops);
4092 if (!(desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP) && layer_count > 1
4093 && !gl_info->supported[EXT_TEXTURE_ARRAY])
4095 WARN("OpenGL implementation does not support array textures.\n");
4096 return WINED3DERR_INVALIDCALL;
4099 switch (desc->resource_type)
4101 case WINED3D_RTYPE_TEXTURE_1D:
4102 if (layer_count > 1)
4103 texture_gl->target = GL_TEXTURE_1D_ARRAY;
4104 else
4105 texture_gl->target = GL_TEXTURE_1D;
4106 break;
4108 case WINED3D_RTYPE_TEXTURE_2D:
4109 if (desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP)
4111 texture_gl->target = GL_TEXTURE_CUBE_MAP_ARB;
4113 else if (desc->multisample_type && gl_info->supported[ARB_TEXTURE_MULTISAMPLE])
4115 if (layer_count > 1)
4116 texture_gl->target = GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
4117 else
4118 texture_gl->target = GL_TEXTURE_2D_MULTISAMPLE;
4120 else
4122 if (layer_count > 1)
4123 texture_gl->target = GL_TEXTURE_2D_ARRAY;
4124 else
4125 texture_gl->target = GL_TEXTURE_2D;
4127 break;
4129 case WINED3D_RTYPE_TEXTURE_3D:
4130 if (!gl_info->supported[EXT_TEXTURE3D])
4132 WARN("OpenGL implementation does not support 3D textures.\n");
4133 return WINED3DERR_INVALIDCALL;
4135 texture_gl->target = GL_TEXTURE_3D;
4136 break;
4138 default:
4139 ERR("Invalid resource type %s.\n", debug_d3dresourcetype(desc->resource_type));
4140 return WINED3DERR_INVALIDCALL;
4143 list_init(&texture_gl->renderbuffers);
4145 if (FAILED(hr = wined3d_texture_init(&texture_gl->t, desc, layer_count, level_count,
4146 flags, device, parent, parent_ops, &texture_gl[1], &texture_gl_ops)))
4147 return hr;
4149 if (texture_gl->target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY || texture_gl->target == GL_TEXTURE_2D_MULTISAMPLE)
4150 texture_gl->t.flags &= ~WINED3D_TEXTURE_DOWNLOADABLE;
4152 return WINED3D_OK;
4155 HRESULT CDECL wined3d_texture_create(struct wined3d_device *device, const struct wined3d_resource_desc *desc,
4156 UINT layer_count, UINT level_count, uint32_t flags, const struct wined3d_sub_resource_data *data,
4157 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
4159 unsigned int sub_count = level_count * layer_count;
4160 unsigned int i;
4161 HRESULT hr;
4163 TRACE("device %p, desc %p, layer_count %u, level_count %u, flags %#x, data %p, "
4164 "parent %p, parent_ops %p, texture %p.\n",
4165 device, desc, layer_count, level_count, flags, data, parent, parent_ops, texture);
4167 if (!layer_count)
4169 WARN("Invalid layer count.\n");
4170 return E_INVALIDARG;
4172 if ((desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP) && layer_count != 6)
4174 ERR("Invalid layer count %u for legacy cubemap.\n", layer_count);
4175 layer_count = 6;
4178 if (!level_count)
4180 WARN("Invalid level count.\n");
4181 return WINED3DERR_INVALIDCALL;
4184 if (desc->multisample_type != WINED3D_MULTISAMPLE_NONE)
4186 const struct wined3d_format *format = wined3d_get_format(device->adapter, desc->format, desc->bind_flags);
4188 if (desc->multisample_type == WINED3D_MULTISAMPLE_NON_MASKABLE
4189 && desc->multisample_quality >= wined3d_popcount(format->multisample_types))
4191 WARN("Unsupported quality level %u requested for WINED3D_MULTISAMPLE_NON_MASKABLE.\n",
4192 desc->multisample_quality);
4193 return WINED3DERR_NOTAVAILABLE;
4195 if (desc->multisample_type != WINED3D_MULTISAMPLE_NON_MASKABLE
4196 && (!(format->multisample_types & 1u << (desc->multisample_type - 1))
4197 || (desc->multisample_quality && desc->multisample_quality != WINED3D_STANDARD_MULTISAMPLE_PATTERN)))
4199 WARN("Unsupported multisample type %u quality %u requested.\n", desc->multisample_type,
4200 desc->multisample_quality);
4201 return WINED3DERR_NOTAVAILABLE;
4205 if (data)
4207 for (i = 0; i < sub_count; ++i)
4209 if (data[i].data)
4210 continue;
4212 WARN("Invalid sub-resource data specified for sub-resource %u.\n", i);
4213 return E_INVALIDARG;
4217 if (FAILED(hr = device->adapter->adapter_ops->adapter_create_texture(device, desc,
4218 layer_count, level_count, flags, parent, parent_ops, texture)))
4219 return hr;
4221 /* FIXME: We'd like to avoid ever allocating system memory for the texture
4222 * in this case. */
4223 if (data)
4225 struct wined3d_box box;
4227 for (i = 0; i < sub_count; ++i)
4229 wined3d_texture_get_level_box(*texture, i % (*texture)->level_count, &box);
4230 wined3d_device_context_emit_update_sub_resource(&device->cs->c, &(*texture)->resource,
4231 i, &box, data[i].data, data[i].row_pitch, data[i].slice_pitch);
4235 TRACE("Created texture %p.\n", *texture);
4237 return WINED3D_OK;
4240 HRESULT CDECL wined3d_texture_get_dc(struct wined3d_texture *texture, unsigned int sub_resource_idx, HDC *dc)
4242 struct wined3d_device *device = texture->resource.device;
4243 struct wined3d_texture_sub_resource *sub_resource;
4244 struct wined3d_dc_info *dc_info;
4246 TRACE("texture %p, sub_resource_idx %u, dc %p.\n", texture, sub_resource_idx, dc);
4248 if (!(texture->flags & WINED3D_TEXTURE_GET_DC))
4250 WARN("Texture does not support GetDC\n");
4251 /* Don't touch the DC */
4252 return WINED3DERR_INVALIDCALL;
4255 if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx)))
4256 return WINED3DERR_INVALIDCALL;
4258 if (texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
4260 WARN("Not supported on %s resources.\n", debug_d3dresourcetype(texture->resource.type));
4261 return WINED3DERR_INVALIDCALL;
4264 if (texture->resource.map_count && !(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT))
4265 return WINED3DERR_INVALIDCALL;
4267 if (!(dc_info = texture->dc_info) || !dc_info[sub_resource_idx].dc)
4269 struct wined3d_texture_idx texture_idx = {texture, sub_resource_idx};
4271 wined3d_cs_init_object(device->cs, wined3d_texture_create_dc, &texture_idx);
4272 wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
4273 if (!(dc_info = texture->dc_info) || !dc_info[sub_resource_idx].dc)
4274 return WINED3DERR_INVALIDCALL;
4277 if (!(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT))
4278 texture->flags |= WINED3D_TEXTURE_DC_IN_USE;
4279 ++texture->resource.map_count;
4280 ++sub_resource->map_count;
4282 *dc = dc_info[sub_resource_idx].dc;
4283 TRACE("Returning dc %p.\n", *dc);
4285 return WINED3D_OK;
4288 HRESULT CDECL wined3d_texture_release_dc(struct wined3d_texture *texture, unsigned int sub_resource_idx, HDC dc)
4290 struct wined3d_device *device = texture->resource.device;
4291 struct wined3d_texture_sub_resource *sub_resource;
4292 struct wined3d_dc_info *dc_info;
4294 TRACE("texture %p, sub_resource_idx %u, dc %p.\n", texture, sub_resource_idx, dc);
4296 if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx)))
4297 return WINED3DERR_INVALIDCALL;
4299 if (texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
4301 WARN("Not supported on %s resources.\n", debug_d3dresourcetype(texture->resource.type));
4302 return WINED3DERR_INVALIDCALL;
4305 if (!(texture->flags & (WINED3D_TEXTURE_GET_DC_LENIENT | WINED3D_TEXTURE_DC_IN_USE)))
4306 return WINED3DERR_INVALIDCALL;
4308 if (!(dc_info = texture->dc_info) || dc_info[sub_resource_idx].dc != dc)
4310 WARN("Application tries to release invalid DC %p, sub-resource DC is %p.\n",
4311 dc, dc_info ? dc_info[sub_resource_idx].dc : NULL);
4312 return WINED3DERR_INVALIDCALL;
4315 if (!(texture->resource.usage & WINED3DUSAGE_OWNDC))
4317 struct wined3d_texture_idx texture_idx = {texture, sub_resource_idx};
4319 wined3d_cs_destroy_object(device->cs, wined3d_texture_destroy_dc, &texture_idx);
4320 wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
4323 --sub_resource->map_count;
4324 if (!--texture->resource.map_count && texture->update_map_binding)
4325 wined3d_texture_update_map_binding(texture);
4326 if (!(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT))
4327 texture->flags &= ~WINED3D_TEXTURE_DC_IN_USE;
4329 return WINED3D_OK;
4332 void wined3d_texture_upload_from_texture(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
4333 unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, struct wined3d_texture *src_texture,
4334 unsigned int src_sub_resource_idx, const struct wined3d_box *src_box)
4336 unsigned int src_row_pitch, src_slice_pitch;
4337 unsigned int update_w, update_h, update_d;
4338 unsigned int src_level, dst_level;
4339 struct wined3d_context *context;
4340 struct wined3d_bo_address data;
4342 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_x %u, dst_y %u, dst_z %u, "
4343 "src_texture %p, src_sub_resource_idx %u, src_box %s.\n",
4344 dst_texture, dst_sub_resource_idx, dst_x, dst_y, dst_z,
4345 src_texture, src_sub_resource_idx, debug_box(src_box));
4347 context = context_acquire(dst_texture->resource.device, NULL, 0);
4349 /* Only load the sub-resource for partial updates. For newly allocated
4350 * textures the texture wouldn't be the current location, and we'd upload
4351 * zeroes just to overwrite them again. */
4352 update_w = src_box->right - src_box->left;
4353 update_h = src_box->bottom - src_box->top;
4354 update_d = src_box->back - src_box->front;
4355 dst_level = dst_sub_resource_idx % dst_texture->level_count;
4356 if (update_w == wined3d_texture_get_level_width(dst_texture, dst_level)
4357 && update_h == wined3d_texture_get_level_height(dst_texture, dst_level)
4358 && update_d == wined3d_texture_get_level_depth(dst_texture, dst_level))
4359 wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
4360 else
4361 wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
4363 src_level = src_sub_resource_idx % src_texture->level_count;
4364 wined3d_texture_get_memory(src_texture, src_sub_resource_idx, context, &data);
4365 wined3d_texture_get_pitch(src_texture, src_level, &src_row_pitch, &src_slice_pitch);
4367 dst_texture->texture_ops->texture_upload_data(context, wined3d_const_bo_address(&data),
4368 src_texture->resource.format, src_box, src_row_pitch, src_slice_pitch, dst_texture,
4369 dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, dst_x, dst_y, dst_z);
4371 context_release(context);
4373 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
4374 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
4377 /* Partial downloads are not supported. */
4378 void wined3d_texture_download_from_texture(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
4379 struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx)
4381 unsigned int src_level, dst_level, dst_row_pitch, dst_slice_pitch;
4382 unsigned int dst_location = dst_texture->resource.map_binding;
4383 struct wined3d_context *context;
4384 struct wined3d_bo_address data;
4385 struct wined3d_box src_box;
4386 unsigned int src_location;
4388 context = context_acquire(src_texture->resource.device, NULL, 0);
4390 wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location);
4391 wined3d_texture_get_bo_address(dst_texture, dst_sub_resource_idx, &data, dst_location);
4393 if (src_texture->sub_resources[src_sub_resource_idx].locations & WINED3D_LOCATION_TEXTURE_RGB)
4394 src_location = WINED3D_LOCATION_TEXTURE_RGB;
4395 else
4396 src_location = WINED3D_LOCATION_TEXTURE_SRGB;
4397 src_level = src_sub_resource_idx % src_texture->level_count;
4398 wined3d_texture_get_level_box(src_texture, src_level, &src_box);
4400 dst_level = dst_sub_resource_idx % dst_texture->level_count;
4401 wined3d_texture_get_pitch(dst_texture, dst_level, &dst_row_pitch, &dst_slice_pitch);
4403 src_texture->texture_ops->texture_download_data(context, src_texture, src_sub_resource_idx, src_location,
4404 &src_box, &data, dst_texture->resource.format, 0, 0, 0, dst_row_pitch, dst_slice_pitch);
4406 context_release(context);
4408 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, dst_location);
4409 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~dst_location);
4412 static void wined3d_texture_set_bo(struct wined3d_texture *texture,
4413 unsigned sub_resource_idx, struct wined3d_context *context, struct wined3d_bo *bo)
4415 struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx];
4416 struct wined3d_bo *prev_bo = sub_resource->bo;
4418 TRACE("texture %p, sub_resource_idx %u, context %p, bo %p.\n", texture, sub_resource_idx, context, bo);
4420 if (prev_bo)
4422 struct wined3d_bo_user *bo_user;
4424 LIST_FOR_EACH_ENTRY(bo_user, &prev_bo->users, struct wined3d_bo_user, entry)
4425 bo_user->valid = false;
4426 list_init(&prev_bo->users);
4428 assert(list_empty(&bo->users));
4430 wined3d_context_destroy_bo(context, prev_bo);
4431 free(prev_bo);
4434 sub_resource->bo = bo;
4437 void wined3d_texture_update_sub_resource(struct wined3d_texture *texture, unsigned int sub_resource_idx,
4438 struct wined3d_context *context, const struct upload_bo *upload_bo, const struct wined3d_box *box,
4439 unsigned int row_pitch, unsigned int slice_pitch)
4441 unsigned int level = sub_resource_idx % texture->level_count;
4442 unsigned int width = wined3d_texture_get_level_width(texture, level);
4443 unsigned int height = wined3d_texture_get_level_height(texture, level);
4444 unsigned int depth = wined3d_texture_get_level_depth(texture, level);
4445 struct wined3d_box src_box;
4447 if (upload_bo->flags & UPLOAD_BO_RENAME_ON_UNMAP)
4449 wined3d_texture_set_bo(texture, sub_resource_idx, context, upload_bo->addr.buffer_object);
4450 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_BUFFER);
4451 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~WINED3D_LOCATION_BUFFER);
4452 /* Try to free address space if we are not mapping persistently. */
4453 if (upload_bo->addr.buffer_object->map_ptr)
4454 wined3d_context_unmap_bo_address(context, (const struct wined3d_bo_address *)&upload_bo->addr, 0, NULL);
4457 /* Only load the sub-resource for partial updates. */
4458 if (!box->left && !box->top && !box->front
4459 && box->right == width && box->bottom == height && box->back == depth)
4460 wined3d_texture_prepare_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
4461 else
4462 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
4464 wined3d_box_set(&src_box, 0, 0, box->right - box->left, box->bottom - box->top, 0, box->back - box->front);
4465 texture->texture_ops->texture_upload_data(context, &upload_bo->addr, texture->resource.format,
4466 &src_box, row_pitch, slice_pitch, texture, sub_resource_idx,
4467 WINED3D_LOCATION_TEXTURE_RGB, box->left, box->top, box->front);
4469 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
4470 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
4473 struct wined3d_shader_resource_view * CDECL wined3d_texture_acquire_identity_srv(struct wined3d_texture *texture)
4475 struct wined3d_view_desc desc;
4476 HRESULT hr;
4478 TRACE("texture %p.\n", texture);
4480 if (texture->identity_srv)
4481 return texture->identity_srv;
4483 desc.format_id = texture->resource.format->id;
4484 /* The texture owns a reference to the SRV, so we can't have the SRV hold
4485 * a reference to the texture.
4486 * At the same time, a view must be destroyed before its texture, and we
4487 * need a bound SRV to keep the texture alive even if it doesn't have any
4488 * other references.
4489 * In order to achieve this we have the objects share reference counts.
4490 * This means the view doesn't hold a reference to the resource, but any
4491 * references to the view are forwarded to the resource instead. The view
4492 * is destroyed manually when all references are released. */
4493 desc.flags = WINED3D_VIEW_FORWARD_REFERENCE;
4494 desc.u.texture.level_idx = 0;
4495 desc.u.texture.level_count = texture->level_count;
4496 desc.u.texture.layer_idx = 0;
4497 desc.u.texture.layer_count = texture->layer_count;
4498 if (FAILED(hr = wined3d_shader_resource_view_create(&desc, &texture->resource,
4499 NULL, &wined3d_null_parent_ops, &texture->identity_srv)))
4501 ERR("Failed to create shader resource view, hr %#lx.\n", hr);
4502 return NULL;
4504 wined3d_shader_resource_view_decref(texture->identity_srv);
4506 return texture->identity_srv;
4509 static void wined3d_texture_no3d_upload_data(struct wined3d_context *context,
4510 const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *src_format,
4511 const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch,
4512 struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, unsigned int dst_location,
4513 unsigned int dst_x, unsigned int dst_y, unsigned int dst_z)
4515 FIXME("Not implemented.\n");
4518 static void wined3d_texture_no3d_download_data(struct wined3d_context *context,
4519 struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, unsigned int src_location,
4520 const struct wined3d_box *src_box, const struct wined3d_bo_address *dst_bo_addr,
4521 const struct wined3d_format *dst_format, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z,
4522 unsigned int dst_row_pitch, unsigned int dst_slice_pitch)
4524 FIXME("Not implemented.\n");
4527 static BOOL wined3d_texture_no3d_prepare_location(struct wined3d_texture *texture,
4528 unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location)
4530 if (location == WINED3D_LOCATION_SYSMEM)
4531 return texture->sub_resources[sub_resource_idx].user_memory ? TRUE
4532 : wined3d_resource_prepare_sysmem(&texture->resource);
4534 FIXME("Unhandled location %s.\n", wined3d_debug_location(location));
4535 return FALSE;
4538 static BOOL wined3d_texture_no3d_load_location(struct wined3d_texture *texture,
4539 unsigned int sub_resource_idx, struct wined3d_context *context, uint32_t location)
4541 TRACE("texture %p, sub_resource_idx %u, context %p, location %s.\n",
4542 texture, sub_resource_idx, context, wined3d_debug_location(location));
4544 if (location == WINED3D_LOCATION_SYSMEM)
4545 return TRUE;
4547 ERR("Unhandled location %s.\n", wined3d_debug_location(location));
4549 return FALSE;
4552 static void wined3d_texture_no3d_unload_location(struct wined3d_texture *texture,
4553 struct wined3d_context *context, unsigned int location)
4555 TRACE("texture %p, context %p, location %s.\n", texture, context, wined3d_debug_location(location));
4558 static const struct wined3d_texture_ops wined3d_texture_no3d_ops =
4560 wined3d_texture_no3d_prepare_location,
4561 wined3d_texture_no3d_load_location,
4562 wined3d_texture_no3d_unload_location,
4563 wined3d_texture_no3d_upload_data,
4564 wined3d_texture_no3d_download_data,
4567 HRESULT wined3d_texture_no3d_init(struct wined3d_texture *texture_no3d, struct wined3d_device *device,
4568 const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count,
4569 uint32_t flags, void *parent, const struct wined3d_parent_ops *parent_ops)
4571 TRACE("texture_no3d %p, device %p, desc %p, layer_count %u, "
4572 "level_count %u, flags %#x, parent %p, parent_ops %p.\n",
4573 texture_no3d, device, desc, layer_count,
4574 level_count, flags, parent, parent_ops);
4576 return wined3d_texture_init(texture_no3d, desc, layer_count, level_count,
4577 flags, device, parent, parent_ops, &texture_no3d[1], &wined3d_texture_no3d_ops);
4580 void wined3d_vk_swizzle_from_color_fixup(VkComponentMapping *mapping, struct color_fixup_desc fixup)
4582 static const VkComponentSwizzle swizzle_source[] =
4584 VK_COMPONENT_SWIZZLE_ZERO, /* CHANNEL_SOURCE_ZERO */
4585 VK_COMPONENT_SWIZZLE_ONE, /* CHANNEL_SOURCE_ONE */
4586 VK_COMPONENT_SWIZZLE_R, /* CHANNEL_SOURCE_X */
4587 VK_COMPONENT_SWIZZLE_G, /* CHANNEL_SOURCE_Y */
4588 VK_COMPONENT_SWIZZLE_B, /* CHANNEL_SOURCE_Z */
4589 VK_COMPONENT_SWIZZLE_A, /* CHANNEL_SOURCE_W */
4592 mapping->r = swizzle_source[fixup.x_source];
4593 mapping->g = swizzle_source[fixup.y_source];
4594 mapping->b = swizzle_source[fixup.z_source];
4595 mapping->a = swizzle_source[fixup.w_source];
4598 const VkDescriptorImageInfo *wined3d_texture_vk_get_default_image_info(struct wined3d_texture_vk *texture_vk,
4599 struct wined3d_context_vk *context_vk)
4601 const struct wined3d_format_vk *format_vk;
4602 const struct wined3d_vk_info *vk_info;
4603 struct wined3d_device_vk *device_vk;
4604 VkImageViewCreateInfo create_info;
4605 struct color_fixup_desc fixup;
4606 uint32_t flags = 0;
4607 VkResult vr;
4609 if (texture_vk->default_image_info.imageView)
4610 return &texture_vk->default_image_info;
4612 format_vk = wined3d_format_vk(texture_vk->t.resource.format);
4613 device_vk = wined3d_device_vk(texture_vk->t.resource.device);
4614 vk_info = context_vk->vk_info;
4616 if (texture_vk->t.layer_count > 1)
4617 flags |= WINED3D_VIEW_TEXTURE_ARRAY;
4619 wined3d_texture_vk_prepare_texture(texture_vk, context_vk);
4620 create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
4621 create_info.pNext = NULL;
4622 create_info.flags = 0;
4623 create_info.image = texture_vk->image.vk_image;
4624 create_info.viewType = vk_image_view_type_from_wined3d(texture_vk->t.resource.type, flags);
4625 create_info.format = format_vk->vk_format;
4626 fixup = format_vk->f.color_fixup;
4627 if (is_identity_fixup(fixup) || !can_use_texture_swizzle(context_vk->c.d3d_info, &format_vk->f))
4629 create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
4630 create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
4631 create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
4632 create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
4634 else
4636 wined3d_vk_swizzle_from_color_fixup(&create_info.components, fixup);
4638 create_info.subresourceRange.aspectMask = vk_aspect_mask_from_format(&format_vk->f);
4639 create_info.subresourceRange.baseMipLevel = 0;
4640 create_info.subresourceRange.levelCount = texture_vk->t.level_count;
4641 create_info.subresourceRange.baseArrayLayer = 0;
4642 create_info.subresourceRange.layerCount = texture_vk->t.layer_count;
4643 if ((vr = VK_CALL(vkCreateImageView(device_vk->vk_device, &create_info,
4644 NULL, &texture_vk->default_image_info.imageView))) < 0)
4646 ERR("Failed to create Vulkan image view, vr %s.\n", wined3d_debug_vkresult(vr));
4647 return NULL;
4650 TRACE("Created image view 0x%s.\n", wine_dbgstr_longlong(texture_vk->default_image_info.imageView));
4652 texture_vk->default_image_info.sampler = VK_NULL_HANDLE;
4654 /* The default image view is used for SRVs, UAVs and RTVs when the d3d view encompasses the entire
4655 * resource. Any UAV capable resource will always use VK_IMAGE_LAYOUT_GENERAL, so we can use the
4656 * same image info for SRVs and UAVs. For render targets wined3d_rendertarget_view_vk_get_image_view
4657 * only cares about the VkImageView, not entire image info. So using SHADER_READ_ONLY_OPTIMAL works,
4658 * but relies on what the callers of the function do and don't do with the descriptor we return.
4660 * Note that VkWriteDescriptorSet for SRV/UAV use takes a VkDescriptorImageInfo *, so we need a
4661 * place to store the VkDescriptorImageInfo. So returning onlky a VkImageView from this function
4662 * would bring its own problems. */
4663 if (texture_vk->layout == VK_IMAGE_LAYOUT_GENERAL)
4664 texture_vk->default_image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
4665 else
4666 texture_vk->default_image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
4668 return &texture_vk->default_image_info;
4671 static void wined3d_texture_vk_upload_data(struct wined3d_context *context,
4672 const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *src_format,
4673 const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch,
4674 struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, unsigned int dst_location,
4675 unsigned int dst_x, unsigned int dst_y, unsigned int dst_z)
4677 struct wined3d_texture_vk *dst_texture_vk = wined3d_texture_vk(dst_texture);
4678 struct wined3d_context_vk *context_vk = wined3d_context_vk(context);
4679 unsigned int dst_level, dst_row_pitch, dst_slice_pitch;
4680 struct wined3d_texture_sub_resource *sub_resource;
4681 unsigned int src_width, src_height, src_depth;
4682 struct wined3d_bo_address staging_bo_addr;
4683 VkPipelineStageFlags bo_stage_flags = 0;
4684 const struct wined3d_vk_info *vk_info;
4685 VkCommandBuffer vk_command_buffer;
4686 VkBufferMemoryBarrier vk_barrier;
4687 VkImageSubresourceRange vk_range;
4688 struct wined3d_bo_vk staging_bo;
4689 VkImageAspectFlags aspect_mask;
4690 struct wined3d_bo_vk *src_bo;
4691 struct wined3d_range range;
4692 VkBufferImageCopy region;
4693 size_t src_offset;
4694 void *map_ptr;
4696 TRACE("context %p, src_bo_addr %s, src_format %s, src_box %s, src_row_pitch %u, src_slice_pitch %u, "
4697 "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_x %u, dst_y %u, dst_z %u.\n",
4698 context, debug_const_bo_address(src_bo_addr), debug_d3dformat(src_format->id), debug_box(src_box),
4699 src_row_pitch, src_slice_pitch, dst_texture, dst_sub_resource_idx,
4700 wined3d_debug_location(dst_location), dst_x, dst_y, dst_z);
4702 if (src_format->id != dst_texture->resource.format->id)
4704 FIXME("Unhandled format conversion (%s -> %s).\n",
4705 debug_d3dformat(src_format->id),
4706 debug_d3dformat(dst_texture->resource.format->id));
4707 return;
4710 dst_level = dst_sub_resource_idx % dst_texture->level_count;
4711 wined3d_texture_get_pitch(dst_texture, dst_level, &dst_row_pitch, &dst_slice_pitch);
4712 if (dst_texture->resource.type == WINED3D_RTYPE_TEXTURE_1D)
4713 src_row_pitch = dst_row_pitch = 0;
4714 if (dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_3D)
4715 src_slice_pitch = dst_slice_pitch = 0;
4717 if (dst_location != WINED3D_LOCATION_TEXTURE_RGB)
4719 FIXME("Unhandled location %s.\n", wined3d_debug_location(dst_location));
4720 return;
4723 if (wined3d_resource_get_sample_count(&dst_texture_vk->t.resource) > 1)
4725 FIXME("Not supported for multisample textures.\n");
4726 return;
4729 aspect_mask = vk_aspect_mask_from_format(dst_texture->resource.format);
4730 if (wined3d_popcount(aspect_mask) > 1)
4732 FIXME("Unhandled multi-aspect format %s.\n", debug_d3dformat(dst_texture->resource.format->id));
4733 return;
4736 sub_resource = &dst_texture_vk->t.sub_resources[dst_sub_resource_idx];
4737 vk_info = context_vk->vk_info;
4739 src_width = src_box->right - src_box->left;
4740 src_height = src_box->bottom - src_box->top;
4741 src_depth = src_box->back - src_box->front;
4743 src_offset = src_box->front * src_slice_pitch
4744 + (src_box->top / src_format->block_height) * src_row_pitch
4745 + (src_box->left / src_format->block_width) * src_format->block_byte_count;
4747 if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk)))
4749 ERR("Failed to get command buffer.\n");
4750 return;
4753 /* We need to be outside of a render pass for vkCmdPipelineBarrier() and vkCmdCopyBufferToImage() calls below. */
4754 wined3d_context_vk_end_current_render_pass(context_vk);
4755 if (!src_bo_addr->buffer_object)
4757 unsigned int staging_row_pitch, staging_slice_pitch, staging_size;
4759 wined3d_format_calculate_pitch(src_format, context->device->surface_alignment, src_width, src_height,
4760 &staging_row_pitch, &staging_slice_pitch);
4761 staging_size = staging_slice_pitch * src_depth;
4763 if (!wined3d_context_vk_create_bo(context_vk, staging_size,
4764 VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &staging_bo))
4766 ERR("Failed to create staging bo.\n");
4767 return;
4770 staging_bo_addr.buffer_object = &staging_bo.b;
4771 staging_bo_addr.addr = NULL;
4772 if (!(map_ptr = wined3d_context_map_bo_address(context, &staging_bo_addr,
4773 staging_size, WINED3D_MAP_DISCARD | WINED3D_MAP_WRITE)))
4775 ERR("Failed to map staging bo.\n");
4776 wined3d_context_vk_destroy_bo(context_vk, &staging_bo);
4777 return;
4780 wined3d_format_copy_data(src_format, src_bo_addr->addr + src_offset, src_row_pitch, src_slice_pitch,
4781 map_ptr, staging_row_pitch, staging_slice_pitch, src_width, src_height, src_depth);
4783 range.offset = 0;
4784 range.size = staging_size;
4785 wined3d_context_unmap_bo_address(context, &staging_bo_addr, 1, &range);
4787 src_bo = &staging_bo;
4789 src_offset = 0;
4790 src_row_pitch = staging_row_pitch;
4791 src_slice_pitch = staging_slice_pitch;
4793 else
4795 src_bo = wined3d_bo_vk(src_bo_addr->buffer_object);
4797 vk_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
4798 vk_barrier.pNext = NULL;
4799 vk_barrier.srcAccessMask = vk_access_mask_from_buffer_usage(src_bo->usage) & ~WINED3D_READ_ONLY_ACCESS_FLAGS;
4800 vk_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
4801 vk_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4802 vk_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4803 vk_barrier.buffer = src_bo->vk_buffer;
4804 vk_barrier.offset = src_bo->b.buffer_offset + (size_t)src_bo_addr->addr;
4805 vk_barrier.size = sub_resource->size;
4807 src_offset += (size_t)src_bo_addr->addr;
4809 bo_stage_flags = vk_pipeline_stage_mask_from_buffer_usage(src_bo->usage);
4810 if (vk_barrier.srcAccessMask)
4811 VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, bo_stage_flags,
4812 VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 1, &vk_barrier, 0, NULL));
4815 vk_range.aspectMask = aspect_mask;
4816 vk_range.baseMipLevel = dst_level;
4817 vk_range.levelCount = 1;
4818 vk_range.baseArrayLayer = dst_sub_resource_idx / dst_texture_vk->t.level_count;
4819 vk_range.layerCount = 1;
4821 wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
4822 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4823 vk_access_mask_from_bind_flags(dst_texture_vk->t.resource.bind_flags),
4824 VK_ACCESS_TRANSFER_WRITE_BIT,
4825 dst_texture_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4826 dst_texture_vk->image.vk_image, &vk_range);
4828 region.bufferOffset = src_bo->b.buffer_offset + src_offset;
4829 region.bufferRowLength = (src_row_pitch / src_format->block_byte_count) * src_format->block_width;
4830 if (src_row_pitch)
4831 region.bufferImageHeight = (src_slice_pitch / src_row_pitch) * src_format->block_height;
4832 else
4833 region.bufferImageHeight = 1;
4834 region.imageSubresource.aspectMask = vk_range.aspectMask;
4835 region.imageSubresource.mipLevel = vk_range.baseMipLevel;
4836 region.imageSubresource.baseArrayLayer = vk_range.baseArrayLayer;
4837 region.imageSubresource.layerCount = vk_range.layerCount;
4838 region.imageOffset.x = dst_x;
4839 region.imageOffset.y = dst_y;
4840 region.imageOffset.z = dst_z;
4841 region.imageExtent.width = src_width;
4842 region.imageExtent.height = src_height;
4843 region.imageExtent.depth = src_depth;
4845 VK_CALL(vkCmdCopyBufferToImage(vk_command_buffer, src_bo->vk_buffer,
4846 dst_texture_vk->image.vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region));
4848 wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
4849 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
4850 VK_ACCESS_TRANSFER_WRITE_BIT,
4851 vk_access_mask_from_bind_flags(dst_texture_vk->t.resource.bind_flags),
4852 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_texture_vk->layout,
4853 dst_texture_vk->image.vk_image, &vk_range);
4854 wined3d_context_vk_reference_texture(context_vk, dst_texture_vk);
4855 wined3d_context_vk_reference_bo(context_vk, src_bo);
4857 if (src_bo == &staging_bo)
4859 wined3d_context_vk_destroy_bo(context_vk, &staging_bo);
4861 else if (vk_barrier.srcAccessMask)
4863 VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
4864 bo_stage_flags, 0, 0, NULL, 0, NULL, 0, NULL));
4868 static void wined3d_texture_vk_download_data(struct wined3d_context *context,
4869 struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, unsigned int src_location,
4870 const struct wined3d_box *src_box, const struct wined3d_bo_address *dst_bo_addr,
4871 const struct wined3d_format *dst_format, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z,
4872 unsigned int dst_row_pitch, unsigned int dst_slice_pitch)
4874 struct wined3d_texture_vk *src_texture_vk = wined3d_texture_vk(src_texture);
4875 struct wined3d_context_vk *context_vk = wined3d_context_vk(context);
4876 unsigned int src_level, src_width, src_height, src_depth;
4877 struct wined3d_texture_sub_resource *sub_resource;
4878 unsigned int src_row_pitch, src_slice_pitch;
4879 struct wined3d_bo_address staging_bo_addr;
4880 VkPipelineStageFlags bo_stage_flags = 0;
4881 const struct wined3d_vk_info *vk_info;
4882 VkCommandBuffer vk_command_buffer;
4883 VkImageSubresourceRange vk_range;
4884 VkBufferMemoryBarrier vk_barrier;
4885 struct wined3d_bo_vk staging_bo;
4886 VkImageAspectFlags aspect_mask;
4887 struct wined3d_bo_vk *dst_bo;
4888 VkBufferImageCopy region;
4889 size_t dst_offset = 0;
4890 void *map_ptr;
4892 TRACE("context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_box %s, dst_bo_addr %s, "
4893 "dst_format %s, dst_x %u, dst_y %u, dst_z %u, dst_row_pitch %u, dst_slice_pitch %u.\n",
4894 context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location),
4895 debug_box(src_box), debug_bo_address(dst_bo_addr), debug_d3dformat(dst_format->id),
4896 dst_x, dst_y, dst_z, dst_row_pitch, dst_slice_pitch);
4898 if (src_location != WINED3D_LOCATION_TEXTURE_RGB)
4900 FIXME("Unhandled location %s.\n", wined3d_debug_location(src_location));
4901 return;
4904 src_level = src_sub_resource_idx % src_texture->level_count;
4905 src_width = wined3d_texture_get_level_width(src_texture, src_level);
4906 src_height = wined3d_texture_get_level_height(src_texture, src_level);
4907 src_depth = wined3d_texture_get_level_depth(src_texture, src_level);
4908 if (src_box->left || src_box->top || src_box->right != src_width || src_box->bottom != src_height
4909 || src_box->front || src_box->back != src_depth)
4911 FIXME("Unhandled source box %s.\n", debug_box(src_box));
4912 return;
4915 if (dst_format->id != src_texture->resource.format->id)
4917 FIXME("Unhandled format conversion (%s -> %s).\n",
4918 debug_d3dformat(src_texture->resource.format->id),
4919 debug_d3dformat(dst_format->id));
4920 return;
4923 if (dst_x || dst_y || dst_z)
4925 FIXME("Unhandled destination (%u, %u, %u).\n", dst_x, dst_y, dst_z);
4926 return;
4929 if (wined3d_resource_get_sample_count(&src_texture_vk->t.resource) > 1)
4931 FIXME("Not supported for multisample textures.\n");
4932 return;
4935 aspect_mask = vk_aspect_mask_from_format(src_texture->resource.format);
4936 if (wined3d_popcount(aspect_mask) > 1)
4938 FIXME("Unhandled multi-aspect format %s.\n", debug_d3dformat(src_texture->resource.format->id));
4939 return;
4942 wined3d_texture_get_pitch(src_texture, src_level, &src_row_pitch, &src_slice_pitch);
4943 if (src_texture->resource.type == WINED3D_RTYPE_TEXTURE_1D)
4944 src_row_pitch = dst_row_pitch = 0;
4945 if (src_texture->resource.type != WINED3D_RTYPE_TEXTURE_3D)
4946 src_slice_pitch = dst_slice_pitch = 0;
4948 sub_resource = &src_texture_vk->t.sub_resources[src_sub_resource_idx];
4949 vk_info = context_vk->vk_info;
4950 if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk)))
4952 ERR("Failed to get command buffer.\n");
4953 return;
4956 /* We need to be outside of a render pass for vkCmdPipelineBarrier() and vkCmdCopyImageToBuffer() calls below. */
4957 wined3d_context_vk_end_current_render_pass(context_vk);
4959 if (!dst_bo_addr->buffer_object)
4961 if (!wined3d_context_vk_create_bo(context_vk, sub_resource->size,
4962 VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &staging_bo))
4964 ERR("Failed to create staging bo.\n");
4965 return;
4968 dst_bo = &staging_bo;
4970 else
4972 dst_bo = wined3d_bo_vk(dst_bo_addr->buffer_object);
4974 vk_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
4975 vk_barrier.pNext = NULL;
4976 vk_barrier.srcAccessMask = vk_access_mask_from_buffer_usage(dst_bo->usage);
4977 vk_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
4978 vk_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4979 vk_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4980 vk_barrier.buffer = dst_bo->vk_buffer;
4981 vk_barrier.offset = dst_bo->b.buffer_offset + (size_t)dst_bo_addr->addr;
4982 vk_barrier.size = sub_resource->size;
4984 bo_stage_flags = vk_pipeline_stage_mask_from_buffer_usage(dst_bo->usage);
4985 dst_offset = (size_t)dst_bo_addr->addr;
4987 VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, bo_stage_flags,
4988 VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 1, &vk_barrier, 0, NULL));
4991 vk_range.aspectMask = aspect_mask;
4992 vk_range.baseMipLevel = src_level;
4993 vk_range.levelCount = 1;
4994 vk_range.baseArrayLayer = src_sub_resource_idx / src_texture_vk->t.level_count;
4995 vk_range.layerCount = 1;
4997 wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
4998 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4999 vk_access_mask_from_bind_flags(src_texture_vk->t.resource.bind_flags),
5000 VK_ACCESS_TRANSFER_READ_BIT,
5001 src_texture_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
5002 src_texture_vk->image.vk_image, &vk_range);
5004 region.bufferOffset = dst_bo->b.buffer_offset + dst_offset;
5005 region.bufferRowLength = 0;
5006 region.bufferImageHeight = 0;
5007 region.imageSubresource.aspectMask = vk_range.aspectMask;
5008 region.imageSubresource.mipLevel = vk_range.baseMipLevel;
5009 region.imageSubresource.baseArrayLayer = vk_range.baseArrayLayer;
5010 region.imageSubresource.layerCount = vk_range.layerCount;
5011 region.imageOffset.x = 0;
5012 region.imageOffset.y = 0;
5013 region.imageOffset.z = 0;
5014 region.imageExtent.width = src_width;
5015 region.imageExtent.height = src_height;
5016 region.imageExtent.depth = src_depth;
5018 VK_CALL(vkCmdCopyImageToBuffer(vk_command_buffer, src_texture_vk->image.vk_image,
5019 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_bo->vk_buffer, 1, &region));
5021 wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
5022 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
5023 VK_ACCESS_TRANSFER_READ_BIT,
5024 vk_access_mask_from_bind_flags(src_texture_vk->t.resource.bind_flags),
5025 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, src_texture_vk->layout,
5026 src_texture_vk->image.vk_image, &vk_range);
5028 wined3d_context_vk_reference_texture(context_vk, src_texture_vk);
5029 wined3d_context_vk_reference_bo(context_vk, dst_bo);
5031 if (dst_bo == &staging_bo)
5033 wined3d_context_vk_submit_command_buffer(context_vk, 0, NULL, NULL, 0, NULL);
5034 wined3d_context_vk_wait_command_buffer(context_vk, src_texture_vk->image.command_buffer_id);
5036 staging_bo_addr.buffer_object = &staging_bo.b;
5037 staging_bo_addr.addr = NULL;
5038 if (!(map_ptr = wined3d_context_map_bo_address(context, &staging_bo_addr,
5039 sub_resource->size, WINED3D_MAP_READ)))
5041 ERR("Failed to map staging bo.\n");
5042 wined3d_context_vk_destroy_bo(context_vk, &staging_bo);
5043 return;
5046 wined3d_format_copy_data(dst_format, map_ptr, src_row_pitch, src_slice_pitch,
5047 dst_bo_addr->addr, dst_row_pitch, dst_slice_pitch, src_box->right - src_box->left,
5048 src_box->bottom - src_box->top, src_box->back - src_box->front);
5050 wined3d_context_unmap_bo_address(context, &staging_bo_addr, 0, NULL);
5051 wined3d_context_vk_destroy_bo(context_vk, &staging_bo);
5053 else
5055 vk_barrier.dstAccessMask = vk_barrier.srcAccessMask;
5056 vk_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
5058 if (dst_bo->host_synced)
5060 vk_barrier.dstAccessMask |= VK_ACCESS_HOST_READ_BIT;
5061 bo_stage_flags |= VK_PIPELINE_STAGE_HOST_BIT;
5064 VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
5065 bo_stage_flags, 0, 0, NULL, 1, &vk_barrier, 0, NULL));
5066 /* Start the download so we don't stall waiting for the result. */
5067 wined3d_context_vk_submit_command_buffer(context_vk, 0, NULL, NULL, 0, NULL);
5071 static bool wined3d_texture_vk_clear(struct wined3d_texture_vk *texture_vk,
5072 unsigned int sub_resource_idx, struct wined3d_context *context)
5074 struct wined3d_texture_sub_resource *sub_resource = &texture_vk->t.sub_resources[sub_resource_idx];
5075 struct wined3d_context_vk *context_vk = wined3d_context_vk(context);
5076 const struct wined3d_format *format = texture_vk->t.resource.format;
5077 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
5078 VkClearDepthStencilValue depth_value;
5079 VkCommandBuffer vk_command_buffer;
5080 VkImageSubresourceRange vk_range;
5081 VkClearColorValue colour_value;
5082 VkImageAspectFlags aspect_mask;
5083 VkImage vk_image;
5085 if (texture_vk->t.resource.format_attrs & WINED3D_FORMAT_ATTR_COMPRESSED)
5087 struct wined3d_bo_address addr;
5088 struct wined3d_color *c = &sub_resource->clear_value.colour;
5090 if (c->r || c->g || c-> b || c->a)
5091 FIXME("Compressed resource %p is cleared to a non-zero color.\n", &texture_vk->t);
5093 if (!wined3d_texture_prepare_location(&texture_vk->t, sub_resource_idx, context, WINED3D_LOCATION_SYSMEM))
5094 return false;
5095 wined3d_texture_get_bo_address(&texture_vk->t, sub_resource_idx, &addr, WINED3D_LOCATION_SYSMEM);
5096 memset(addr.addr, 0, sub_resource->size);
5097 wined3d_texture_validate_location(&texture_vk->t, sub_resource_idx, WINED3D_LOCATION_SYSMEM);
5098 return true;
5101 vk_image = texture_vk->image.vk_image;
5103 if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk)))
5105 ERR("Failed to get command buffer.\n");
5106 return false;
5109 aspect_mask = vk_aspect_mask_from_format(format);
5111 vk_range.aspectMask = aspect_mask;
5112 vk_range.baseMipLevel = sub_resource_idx % texture_vk->t.level_count;
5113 vk_range.levelCount = 1;
5114 vk_range.baseArrayLayer = sub_resource_idx / texture_vk->t.level_count;
5115 vk_range.layerCount = 1;
5117 wined3d_context_vk_end_current_render_pass(context_vk);
5119 wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
5120 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
5121 vk_access_mask_from_bind_flags(texture_vk->t.resource.bind_flags), VK_ACCESS_TRANSFER_WRITE_BIT,
5122 texture_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, vk_image, &vk_range);
5124 if (format->depth_size || format->stencil_size)
5126 depth_value.depth = sub_resource->clear_value.depth;
5127 depth_value.stencil = sub_resource->clear_value.stencil;
5128 VK_CALL(vkCmdClearDepthStencilImage(vk_command_buffer, vk_image,
5129 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &depth_value, 1, &vk_range));
5131 else
5133 wined3d_format_colour_to_vk(format, &sub_resource->clear_value.colour, &colour_value);
5134 VK_CALL(vkCmdClearColorImage(vk_command_buffer, vk_image,
5135 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &colour_value, 1, &vk_range));
5138 wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
5139 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
5140 VK_ACCESS_TRANSFER_WRITE_BIT, vk_access_mask_from_bind_flags(texture_vk->t.resource.bind_flags),
5141 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_vk->layout, vk_image, &vk_range);
5142 wined3d_context_vk_reference_texture(context_vk, texture_vk);
5144 wined3d_texture_validate_location(&texture_vk->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
5145 return true;
5148 static BOOL wined3d_texture_vk_load_texture(struct wined3d_texture_vk *texture_vk,
5149 unsigned int sub_resource_idx, struct wined3d_context *context)
5151 struct wined3d_texture_sub_resource *sub_resource;
5152 unsigned int level, row_pitch, slice_pitch;
5153 struct wined3d_bo_address data;
5154 struct wined3d_box src_box;
5156 sub_resource = &texture_vk->t.sub_resources[sub_resource_idx];
5158 if (sub_resource->locations & WINED3D_LOCATION_CLEARED)
5160 if (!wined3d_texture_vk_clear(texture_vk, sub_resource_idx, context))
5161 return FALSE;
5163 if (sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB)
5164 return TRUE;
5167 if (!(sub_resource->locations & wined3d_texture_sysmem_locations))
5169 ERR("Unimplemented load from %s.\n", wined3d_debug_location(sub_resource->locations));
5170 return FALSE;
5173 level = sub_resource_idx % texture_vk->t.level_count;
5174 wined3d_texture_get_memory(&texture_vk->t, sub_resource_idx, context, &data);
5175 wined3d_texture_get_level_box(&texture_vk->t, level, &src_box);
5176 wined3d_texture_get_pitch(&texture_vk->t, level, &row_pitch, &slice_pitch);
5177 wined3d_texture_vk_upload_data(context, wined3d_const_bo_address(&data), texture_vk->t.resource.format,
5178 &src_box, row_pitch, slice_pitch, &texture_vk->t, sub_resource_idx,
5179 WINED3D_LOCATION_TEXTURE_RGB, 0, 0, 0);
5181 return TRUE;
5184 static BOOL wined3d_texture_vk_load_sysmem(struct wined3d_texture_vk *texture_vk,
5185 unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location)
5187 struct wined3d_texture_sub_resource *sub_resource;
5188 unsigned int level, row_pitch, slice_pitch;
5189 struct wined3d_bo_address data;
5190 struct wined3d_box src_box;
5192 sub_resource = &texture_vk->t.sub_resources[sub_resource_idx];
5193 if (!(sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB))
5195 ERR("Unimplemented load from %s.\n", wined3d_debug_location(sub_resource->locations));
5196 return FALSE;
5199 level = sub_resource_idx % texture_vk->t.level_count;
5200 wined3d_texture_get_bo_address(&texture_vk->t, sub_resource_idx, &data, location);
5201 wined3d_texture_get_level_box(&texture_vk->t, level, &src_box);
5202 wined3d_texture_get_pitch(&texture_vk->t, level, &row_pitch, &slice_pitch);
5203 wined3d_texture_vk_download_data(context, &texture_vk->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB,
5204 &src_box, &data, texture_vk->t.resource.format, 0, 0, 0, row_pitch, slice_pitch);
5206 return TRUE;
5209 BOOL wined3d_texture_vk_prepare_texture(struct wined3d_texture_vk *texture_vk,
5210 struct wined3d_context_vk *context_vk)
5212 const struct wined3d_format_vk *format_vk;
5213 struct wined3d_resource *resource;
5214 VkCommandBuffer vk_command_buffer;
5215 VkImageSubresourceRange vk_range;
5216 VkImageUsageFlags vk_usage;
5217 VkImageType vk_image_type;
5218 unsigned int flags = 0;
5220 if (texture_vk->t.flags & WINED3D_TEXTURE_RGB_ALLOCATED)
5221 return TRUE;
5223 if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk)))
5225 ERR("Failed to get command buffer.\n");
5226 return FALSE;
5229 resource = &texture_vk->t.resource;
5230 format_vk = wined3d_format_vk(resource->format);
5232 if (wined3d_format_is_typeless(&format_vk->f) || texture_vk->t.swapchain
5233 || (texture_vk->t.resource.bind_flags & WINED3D_BIND_UNORDERED_ACCESS))
5235 /* For UAVs, we need this in case a clear necessitates creation of a new view
5236 * with a different format. */
5237 flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
5240 switch (resource->type)
5242 case WINED3D_RTYPE_TEXTURE_1D:
5243 vk_image_type = VK_IMAGE_TYPE_1D;
5244 break;
5245 case WINED3D_RTYPE_TEXTURE_2D:
5246 vk_image_type = VK_IMAGE_TYPE_2D;
5247 if (texture_vk->t.layer_count >= 6 && resource->width == resource->height)
5248 flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
5249 break;
5250 case WINED3D_RTYPE_TEXTURE_3D:
5251 vk_image_type = VK_IMAGE_TYPE_3D;
5252 if (resource->bind_flags & (WINED3D_BIND_RENDER_TARGET | WINED3D_BIND_UNORDERED_ACCESS))
5253 flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
5254 break;
5255 default:
5256 ERR("Invalid resource type %s.\n", debug_d3dresourcetype(resource->type));
5257 vk_image_type = VK_IMAGE_TYPE_2D;
5258 break;
5261 vk_usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
5262 if (resource->bind_flags & WINED3D_BIND_SHADER_RESOURCE)
5263 vk_usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
5264 if (resource->bind_flags & WINED3D_BIND_RENDER_TARGET)
5265 vk_usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
5266 if (resource->bind_flags & WINED3D_BIND_DEPTH_STENCIL)
5267 vk_usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
5268 if (resource->bind_flags & WINED3D_BIND_UNORDERED_ACCESS)
5269 vk_usage |= VK_IMAGE_USAGE_STORAGE_BIT;
5271 if (resource->bind_flags & WINED3D_BIND_UNORDERED_ACCESS)
5272 texture_vk->layout = VK_IMAGE_LAYOUT_GENERAL;
5273 else if (resource->bind_flags & WINED3D_BIND_RENDER_TARGET)
5274 texture_vk->layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
5275 else if (resource->bind_flags & WINED3D_BIND_DEPTH_STENCIL)
5276 texture_vk->layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
5277 else if (resource->bind_flags & WINED3D_BIND_SHADER_RESOURCE)
5278 texture_vk->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5279 else
5281 FIXME("unexpected bind flags %s, using VK_IMAGE_LAYOUT_GENERAL\n", wined3d_debug_bind_flags(resource->bind_flags));
5282 texture_vk->layout = VK_IMAGE_LAYOUT_GENERAL;
5285 if (!wined3d_context_vk_create_image(context_vk, vk_image_type, vk_usage, format_vk->vk_format,
5286 resource->width, resource->height, resource->depth, max(1, wined3d_resource_get_sample_count(resource)),
5287 texture_vk->t.level_count, texture_vk->t.layer_count, flags, &texture_vk->image))
5289 return FALSE;
5292 /* We can't use a zero src access mask without synchronization2. Set the last-used bind mask to something
5293 * non-zero to avoid this. */
5294 texture_vk->bind_mask = resource->bind_flags;
5296 vk_range.aspectMask = vk_aspect_mask_from_format(&format_vk->f);
5297 vk_range.baseMipLevel = 0;
5298 vk_range.levelCount = VK_REMAINING_MIP_LEVELS;
5299 vk_range.baseArrayLayer = 0;
5300 vk_range.layerCount = VK_REMAINING_ARRAY_LAYERS;
5302 wined3d_context_vk_reference_texture(context_vk, texture_vk);
5303 wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
5304 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
5305 0, 0,
5306 VK_IMAGE_LAYOUT_UNDEFINED, texture_vk->layout,
5307 texture_vk->image.vk_image, &vk_range);
5309 texture_vk->t.flags |= WINED3D_TEXTURE_RGB_ALLOCATED;
5311 TRACE("Created image 0x%s, memory 0x%s for texture %p.\n",
5312 wine_dbgstr_longlong(texture_vk->image.vk_image), wine_dbgstr_longlong(texture_vk->image.vk_memory), texture_vk);
5314 return TRUE;
5317 static BOOL wined3d_texture_vk_prepare_buffer_object(struct wined3d_texture_vk *texture_vk,
5318 unsigned int sub_resource_idx, struct wined3d_context_vk *context_vk)
5320 struct wined3d_texture_sub_resource *sub_resource;
5321 struct wined3d_bo_vk *bo;
5323 sub_resource = &texture_vk->t.sub_resources[sub_resource_idx];
5324 if (sub_resource->bo)
5325 return TRUE;
5327 if (!(bo = malloc(sizeof(*bo))))
5328 return FALSE;
5330 if (!wined3d_context_vk_create_bo(context_vk, sub_resource->size,
5331 VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
5332 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, bo))
5334 free(bo);
5335 return FALSE;
5338 /* Texture buffer objects receive a barrier to HOST_READ in wined3d_texture_vk_download_data(),
5339 * so they don't need it when they are mapped for reading. */
5340 bo->host_synced = true;
5341 sub_resource->bo = &bo->b;
5342 TRACE("Created buffer object %p for texture %p, sub-resource %u.\n", bo, texture_vk, sub_resource_idx);
5343 return TRUE;
5346 static BOOL wined3d_texture_vk_prepare_location(struct wined3d_texture *texture,
5347 unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location)
5349 switch (location)
5351 case WINED3D_LOCATION_SYSMEM:
5352 return texture->sub_resources[sub_resource_idx].user_memory ? TRUE
5353 : wined3d_resource_prepare_sysmem(&texture->resource);
5355 case WINED3D_LOCATION_TEXTURE_RGB:
5356 return wined3d_texture_vk_prepare_texture(wined3d_texture_vk(texture), wined3d_context_vk(context));
5358 case WINED3D_LOCATION_BUFFER:
5359 return wined3d_texture_vk_prepare_buffer_object(wined3d_texture_vk(texture), sub_resource_idx,
5360 wined3d_context_vk(context));
5362 default:
5363 FIXME("Unhandled location %s.\n", wined3d_debug_location(location));
5364 return FALSE;
5368 static BOOL wined3d_texture_vk_load_location(struct wined3d_texture *texture,
5369 unsigned int sub_resource_idx, struct wined3d_context *context, uint32_t location)
5371 if (!wined3d_texture_vk_prepare_location(texture, sub_resource_idx, context, location))
5372 return FALSE;
5374 switch (location)
5376 case WINED3D_LOCATION_TEXTURE_RGB:
5377 return wined3d_texture_vk_load_texture(wined3d_texture_vk(texture), sub_resource_idx, context);
5379 case WINED3D_LOCATION_SYSMEM:
5380 case WINED3D_LOCATION_BUFFER:
5381 return wined3d_texture_vk_load_sysmem(wined3d_texture_vk(texture), sub_resource_idx, context, location);
5383 default:
5384 FIXME("Unimplemented location %s.\n", wined3d_debug_location(location));
5385 return FALSE;
5389 static void wined3d_texture_vk_unload_location(struct wined3d_texture *texture,
5390 struct wined3d_context *context, unsigned int location)
5392 struct wined3d_texture_vk *texture_vk = wined3d_texture_vk(texture);
5393 struct wined3d_context_vk *context_vk = wined3d_context_vk(context);
5394 unsigned int i, sub_count;
5396 TRACE("texture %p, context %p, location %s.\n", texture, context, wined3d_debug_location(location));
5398 switch (location)
5400 case WINED3D_LOCATION_TEXTURE_RGB:
5401 if (texture_vk->default_image_info.imageView)
5403 wined3d_context_vk_destroy_vk_image_view(context_vk,
5404 texture_vk->default_image_info.imageView, texture_vk->image.command_buffer_id);
5405 texture_vk->default_image_info.imageView = VK_NULL_HANDLE;
5408 if (texture_vk->image.vk_image)
5409 wined3d_context_vk_destroy_image(context_vk, &texture_vk->image);
5410 break;
5412 case WINED3D_LOCATION_BUFFER:
5413 sub_count = texture->level_count * texture->layer_count;
5414 for (i = 0; i < sub_count; ++i)
5416 struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[i];
5418 if (sub_resource->bo)
5420 struct wined3d_bo_vk *bo_vk = wined3d_bo_vk(sub_resource->bo);
5422 wined3d_context_vk_destroy_bo(context_vk, bo_vk);
5423 free(bo_vk);
5424 sub_resource->bo = NULL;
5427 break;
5429 case WINED3D_LOCATION_TEXTURE_SRGB:
5430 case WINED3D_LOCATION_RB_MULTISAMPLE:
5431 case WINED3D_LOCATION_RB_RESOLVED:
5432 break;
5434 default:
5435 ERR("Unhandled location %s.\n", wined3d_debug_location(location));
5436 break;
5440 static const struct wined3d_texture_ops wined3d_texture_vk_ops =
5442 wined3d_texture_vk_prepare_location,
5443 wined3d_texture_vk_load_location,
5444 wined3d_texture_vk_unload_location,
5445 wined3d_texture_vk_upload_data,
5446 wined3d_texture_vk_download_data,
5449 HRESULT wined3d_texture_vk_init(struct wined3d_texture_vk *texture_vk, struct wined3d_device *device,
5450 const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count,
5451 uint32_t flags, void *parent, const struct wined3d_parent_ops *parent_ops)
5453 TRACE("texture_vk %p, device %p, desc %p, layer_count %u, "
5454 "level_count %u, flags %#x, parent %p, parent_ops %p.\n",
5455 texture_vk, device, desc, layer_count,
5456 level_count, flags, parent, parent_ops);
5458 return wined3d_texture_init(&texture_vk->t, desc, layer_count, level_count,
5459 flags, device, parent, parent_ops, &texture_vk[1], &wined3d_texture_vk_ops);
5462 enum VkImageLayout wined3d_layout_from_bind_mask(const struct wined3d_texture_vk *texture_vk, const uint32_t bind_mask)
5464 assert(wined3d_popcount(bind_mask) == 1);
5466 /* We want to avoid switching between LAYOUT_GENERAL and other layouts. In Radeon GPUs (and presumably
5467 * others), this will trigger decompressing and recompressing the texture. We also hardcode the layout
5468 * into views when they are created. */
5469 if (texture_vk->layout == VK_IMAGE_LAYOUT_GENERAL)
5470 return VK_IMAGE_LAYOUT_GENERAL;
5472 switch (bind_mask)
5474 case WINED3D_BIND_RENDER_TARGET:
5475 return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
5477 case WINED3D_BIND_DEPTH_STENCIL:
5478 return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
5480 case WINED3D_BIND_SHADER_RESOURCE:
5481 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5483 default:
5484 ERR("Unexpected bind mask %s.\n", wined3d_debug_bind_flags(bind_mask));
5485 return VK_IMAGE_LAYOUT_GENERAL;
5489 void wined3d_texture_vk_barrier(struct wined3d_texture_vk *texture_vk,
5490 struct wined3d_context_vk *context_vk, uint32_t bind_mask)
5492 enum VkImageLayout new_layout;
5493 uint32_t src_bind_mask = 0;
5495 TRACE("texture_vk %p, context_vk %p, bind_mask %s.\n",
5496 texture_vk, context_vk, wined3d_debug_bind_flags(bind_mask));
5498 new_layout = wined3d_layout_from_bind_mask(texture_vk, bind_mask);
5500 /* A layout transition is potentially a read-write operation, so even if we
5501 * prepare the texture to e.g. read only shader resource mode, we have to wait
5502 * for past operations to finish. */
5503 if (bind_mask & ~WINED3D_READ_ONLY_BIND_MASK || new_layout != texture_vk->layout)
5505 src_bind_mask = texture_vk->bind_mask & WINED3D_READ_ONLY_BIND_MASK;
5506 if (!src_bind_mask)
5507 src_bind_mask = texture_vk->bind_mask;
5509 texture_vk->bind_mask = bind_mask;
5511 else if ((texture_vk->bind_mask & bind_mask) != bind_mask)
5513 src_bind_mask = texture_vk->bind_mask & ~WINED3D_READ_ONLY_BIND_MASK;
5514 texture_vk->bind_mask |= bind_mask;
5517 if (src_bind_mask)
5519 VkImageSubresourceRange vk_range;
5521 TRACE(" %s(%x) -> %s(%x).\n",
5522 wined3d_debug_bind_flags(src_bind_mask), texture_vk->layout,
5523 wined3d_debug_bind_flags(bind_mask), new_layout);
5525 vk_range.aspectMask = vk_aspect_mask_from_format(texture_vk->t.resource.format);
5526 vk_range.baseMipLevel = 0;
5527 vk_range.levelCount = VK_REMAINING_MIP_LEVELS;
5528 vk_range.baseArrayLayer = 0;
5529 vk_range.layerCount = VK_REMAINING_ARRAY_LAYERS;
5531 wined3d_context_vk_image_barrier(context_vk, wined3d_context_vk_get_command_buffer(context_vk),
5532 vk_pipeline_stage_mask_from_bind_flags(src_bind_mask),
5533 vk_pipeline_stage_mask_from_bind_flags(bind_mask),
5534 vk_access_mask_from_bind_flags(src_bind_mask), vk_access_mask_from_bind_flags(bind_mask),
5535 texture_vk->layout, new_layout, texture_vk->image.vk_image, &vk_range);
5537 texture_vk->layout = new_layout;
5541 /* This is called when a texture is used as render target and shader resource
5542 * or depth stencil and shader resource at the same time. This can either be
5543 * read-only simultaneos use as depth stencil, but also for rendering to one
5544 * subresource while reading from another. Without tracking of barriers and
5545 * layouts per subresource VK_IMAGE_LAYOUT_GENERAL is the only thing we can do. */
5546 void wined3d_texture_vk_make_generic(struct wined3d_texture_vk *texture_vk,
5547 struct wined3d_context_vk *context_vk)
5549 VkImageSubresourceRange vk_range;
5551 if (texture_vk->layout == VK_IMAGE_LAYOUT_GENERAL)
5552 return;
5554 vk_range.aspectMask = vk_aspect_mask_from_format(texture_vk->t.resource.format);
5555 vk_range.baseMipLevel = 0;
5556 vk_range.levelCount = VK_REMAINING_MIP_LEVELS;
5557 vk_range.baseArrayLayer = 0;
5558 vk_range.layerCount = VK_REMAINING_ARRAY_LAYERS;
5560 wined3d_context_vk_image_barrier(context_vk, wined3d_context_vk_get_command_buffer(context_vk),
5561 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
5562 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
5563 0, 0,
5564 texture_vk->layout, VK_IMAGE_LAYOUT_GENERAL, texture_vk->image.vk_image, &vk_range);
5566 texture_vk->layout = VK_IMAGE_LAYOUT_GENERAL;
5567 texture_vk->default_image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
5570 static void ffp_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
5572 struct wined3d_blitter *next;
5574 if ((next = blitter->next))
5575 next->ops->blitter_destroy(next, context);
5577 free(blitter);
5580 static bool is_full_clear(const struct wined3d_rendertarget_view *rtv, const RECT *draw_rect, const RECT *clear_rect)
5582 unsigned int height = rtv->height;
5583 unsigned int width = rtv->width;
5585 /* partial draw rect */
5586 if (draw_rect->left || draw_rect->top || draw_rect->right < width || draw_rect->bottom < height)
5587 return false;
5589 /* partial clear rect */
5590 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
5591 || clear_rect->right < width || clear_rect->bottom < height))
5592 return false;
5594 return true;
5597 static void ffp_blitter_clear_rendertargets(struct wined3d_device *device, unsigned int rt_count,
5598 const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rect, const RECT *draw_rect,
5599 uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int stencil)
5601 struct wined3d_rendertarget_view *rtv = rt_count ? fb->render_targets[0] : NULL;
5602 struct wined3d_rendertarget_view *dsv = fb->depth_stencil;
5603 const struct wined3d_state *state = &device->cs->state;
5604 struct wined3d_texture *depth_stencil = NULL;
5605 unsigned int drawable_width, drawable_height;
5606 const struct wined3d_gl_info *gl_info;
5607 struct wined3d_context_gl *context_gl;
5608 struct wined3d_texture *target = NULL;
5609 struct wined3d_color colour_srgb;
5610 struct wined3d_context *context;
5611 GLbitfield clear_mask = 0;
5612 bool render_offscreen;
5613 unsigned int i;
5615 if (rtv && rtv->resource->type != WINED3D_RTYPE_BUFFER)
5617 target = texture_from_resource(rtv->resource);
5618 context = context_acquire(device, target, rtv->sub_resource_idx);
5620 else
5622 context = context_acquire(device, NULL, 0);
5624 context_gl = wined3d_context_gl(context);
5626 if (dsv && dsv->resource->type != WINED3D_RTYPE_BUFFER)
5627 depth_stencil = texture_from_resource(dsv->resource);
5629 if (!context_gl->valid)
5631 context_release(context);
5632 WARN("Invalid context, skipping clear.\n");
5633 return;
5635 gl_info = context_gl->gl_info;
5637 /* When we're clearing parts of the drawable, make sure that the target
5638 * surface is well up to date in the drawable. After the clear we'll mark
5639 * the drawable up to date, so we have to make sure that this is true for
5640 * the cleared parts, and the untouched parts.
5642 * If we're clearing the whole target there is no need to copy it into the
5643 * drawable, it will be overwritten anyway. If we're not clearing the
5644 * colour buffer we don't have to copy either since we're not going to set
5645 * the drawable up to date. We have to check all settings that limit the
5646 * clear area though. Do not bother checking all this if the destination
5647 * surface is in the drawable anyway. */
5648 for (i = 0; i < rt_count; ++i)
5650 struct wined3d_rendertarget_view *rtv = fb->render_targets[i];
5652 if (rtv && rtv->format->id != WINED3DFMT_NULL)
5654 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(rtv, draw_rect, rect_count ? clear_rect : NULL))
5655 wined3d_rendertarget_view_load_location(rtv, context, rtv->resource->draw_binding);
5656 else
5657 wined3d_rendertarget_view_prepare_location(rtv, context, rtv->resource->draw_binding);
5661 if (target)
5663 render_offscreen = wined3d_resource_is_offscreen(&target->resource);
5664 wined3d_rendertarget_view_get_drawable_size(rtv, context, &drawable_width, &drawable_height);
5666 else
5668 unsigned int ds_level = dsv->sub_resource_idx % depth_stencil->level_count;
5670 render_offscreen = true;
5671 drawable_width = wined3d_texture_get_level_width(depth_stencil, ds_level);
5672 drawable_height = wined3d_texture_get_level_height(depth_stencil, ds_level);
5675 if (depth_stencil)
5677 DWORD ds_location = render_offscreen ? dsv->resource->draw_binding : WINED3D_LOCATION_DRAWABLE;
5679 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)
5680 && !is_full_clear(dsv, draw_rect, rect_count ? clear_rect : NULL))
5681 wined3d_rendertarget_view_load_location(dsv, context, ds_location);
5682 else
5683 wined3d_rendertarget_view_prepare_location(dsv, context, ds_location);
5685 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
5687 wined3d_rendertarget_view_validate_location(dsv, ds_location);
5688 wined3d_rendertarget_view_invalidate_location(dsv, ~ds_location);
5692 if (!wined3d_context_gl_apply_clear_state(context_gl, state, rt_count, fb))
5694 context_release(context);
5695 WARN("Failed to apply clear state, skipping clear.\n");
5696 return;
5699 /* Only set the values up once, as they are not changing. */
5700 if (flags & WINED3DCLEAR_STENCIL)
5702 if (gl_info->supported[EXT_STENCIL_TWO_SIDE])
5703 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
5704 gl_info->gl_ops.gl.p_glStencilMask(~0u);
5705 context_invalidate_state(context, STATE_DEPTH_STENCIL);
5706 gl_info->gl_ops.gl.p_glClearStencil(stencil);
5707 checkGLcall("glClearStencil");
5708 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
5711 if (flags & WINED3DCLEAR_ZBUFFER)
5713 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
5714 context_invalidate_state(context, STATE_DEPTH_STENCIL);
5715 if (gl_info->supported[ARB_ES2_COMPATIBILITY])
5716 GL_EXTCALL(glClearDepthf(depth));
5717 else
5718 gl_info->gl_ops.gl.p_glClearDepth(depth);
5719 checkGLcall("glClearDepth");
5720 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
5723 if (flags & WINED3DCLEAR_TARGET)
5725 for (i = 0; i < rt_count; ++i)
5727 struct wined3d_rendertarget_view *rtv = fb->render_targets[i];
5729 if (!rtv)
5730 continue;
5732 if (rtv->resource->type == WINED3D_RTYPE_BUFFER)
5734 FIXME("Not supported on buffer resources.\n");
5735 continue;
5738 wined3d_rendertarget_view_validate_location(rtv, rtv->resource->draw_binding);
5739 wined3d_rendertarget_view_invalidate_location(rtv, ~rtv->resource->draw_binding);
5742 if (!gl_info->supported[ARB_FRAMEBUFFER_SRGB] && needs_srgb_write(context->d3d_info, state, fb))
5744 if (rt_count > 1)
5745 WARN("Clearing multiple sRGB render targets without GL_ARB_framebuffer_sRGB "
5746 "support, this might cause graphical issues.\n");
5748 wined3d_colour_srgb_from_linear(&colour_srgb, colour);
5749 colour = &colour_srgb;
5752 gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5753 context_invalidate_state(context, STATE_BLEND);
5754 gl_info->gl_ops.gl.p_glClearColor(colour->r, colour->g, colour->b, colour->a);
5755 checkGLcall("glClearColor");
5756 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
5759 if (!rect_count)
5761 if (render_offscreen)
5763 gl_info->gl_ops.gl.p_glScissor(draw_rect->left, draw_rect->top,
5764 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
5766 else
5768 gl_info->gl_ops.gl.p_glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
5769 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
5771 gl_info->gl_ops.gl.p_glClear(clear_mask);
5773 else
5775 RECT current_rect;
5777 /* Now process each rect in turn. */
5778 for (i = 0; i < rect_count; ++i)
5780 /* Note that GL uses lower left, width/height. */
5781 IntersectRect(&current_rect, draw_rect, &clear_rect[i]);
5783 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
5784 wine_dbgstr_rect(&clear_rect[i]),
5785 wine_dbgstr_rect(&current_rect));
5787 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored
5788 * silently. The rectangle is not cleared, no error is returned,
5789 * but further rectangles are still cleared if they are valid. */
5790 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
5792 TRACE("Rectangle with negative dimensions, ignoring.\n");
5793 continue;
5796 if (render_offscreen)
5798 gl_info->gl_ops.gl.p_glScissor(current_rect.left, current_rect.top,
5799 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
5801 else
5803 gl_info->gl_ops.gl.p_glScissor(current_rect.left, drawable_height - current_rect.bottom,
5804 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
5806 gl_info->gl_ops.gl.p_glClear(clear_mask);
5809 context->scissor_rect_count = WINED3D_MAX_VIEWPORTS;
5810 checkGLcall("clear");
5812 if (flags & WINED3DCLEAR_TARGET && target->swapchain && target->swapchain->front_buffer == target)
5813 gl_info->gl_ops.gl.p_glFlush();
5815 context_release(context);
5818 static bool blitter_use_cpu_clear(struct wined3d_rendertarget_view *view)
5820 struct wined3d_resource *resource;
5821 struct wined3d_texture *texture;
5822 DWORD locations;
5824 resource = view->resource;
5825 if (resource->type == WINED3D_RTYPE_BUFFER)
5826 return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU);
5828 texture = texture_from_resource(resource);
5829 locations = texture->sub_resources[view->sub_resource_idx].locations;
5830 if (locations & (resource->map_binding | WINED3D_LOCATION_DISCARDED))
5831 return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU)
5832 || texture->resource.pin_sysmem;
5834 return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU)
5835 && !(texture->flags & WINED3D_TEXTURE_CONVERTED);
5838 static void ffp_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
5839 unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
5840 const RECT *draw_rect, uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int stencil)
5842 struct wined3d_rendertarget_view *view, *previous = NULL;
5843 bool have_identical_size = TRUE;
5844 struct wined3d_fb_state tmp_fb;
5845 unsigned int next_rt_count = 0;
5846 struct wined3d_blitter *next;
5847 DWORD next_flags = 0;
5848 unsigned int i;
5850 if (flags & WINED3DCLEAR_TARGET)
5852 for (i = 0; i < rt_count; ++i)
5854 if (!(view = fb->render_targets[i]))
5855 continue;
5857 if (blitter_use_cpu_clear(view)
5858 || (!(view->resource->bind_flags & WINED3D_BIND_RENDER_TARGET)
5859 && !(view->format_caps & WINED3D_FORMAT_CAP_FBO_ATTACHABLE)))
5861 next_flags |= WINED3DCLEAR_TARGET;
5862 flags &= ~WINED3DCLEAR_TARGET;
5863 next_rt_count = rt_count;
5864 rt_count = 0;
5865 break;
5868 /* FIXME: We should reject colour fills on formats with fixups,
5869 * but this would break P8 colour fills for example. */
5873 if ((flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) && (view = fb->depth_stencil)
5874 && (!view->format->depth_size || (flags & WINED3DCLEAR_ZBUFFER))
5875 && (!view->format->stencil_size || (flags & WINED3DCLEAR_STENCIL))
5876 && blitter_use_cpu_clear(view))
5878 next_flags |= flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
5879 flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
5882 if (flags)
5884 for (i = 0; i < rt_count; ++i)
5886 if (!(view = fb->render_targets[i]))
5887 continue;
5889 if (previous && (previous->width != view->width || previous->height != view->height))
5890 have_identical_size = false;
5891 previous = view;
5893 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
5895 view = fb->depth_stencil;
5897 if (previous && (previous->width != view->width || previous->height != view->height))
5898 have_identical_size = false;
5901 if (have_identical_size)
5903 ffp_blitter_clear_rendertargets(device, rt_count, fb, rect_count,
5904 clear_rects, draw_rect, flags, colour, depth, stencil);
5906 else
5908 for (i = 0; i < rt_count; ++i)
5910 if (!(view = fb->render_targets[i]))
5911 continue;
5913 tmp_fb.render_targets[0] = view;
5914 tmp_fb.depth_stencil = NULL;
5915 ffp_blitter_clear_rendertargets(device, 1, &tmp_fb, rect_count,
5916 clear_rects, draw_rect, WINED3DCLEAR_TARGET, colour, depth, stencil);
5918 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
5920 tmp_fb.render_targets[0] = NULL;
5921 tmp_fb.depth_stencil = fb->depth_stencil;
5922 ffp_blitter_clear_rendertargets(device, 0, &tmp_fb, rect_count,
5923 clear_rects, draw_rect, flags & ~WINED3DCLEAR_TARGET, colour, depth, stencil);
5928 if (next_flags && (next = blitter->next))
5929 next->ops->blitter_clear(next, device, next_rt_count, fb, rect_count,
5930 clear_rects, draw_rect, next_flags, colour, depth, stencil);
5933 static DWORD ffp_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
5934 struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
5935 DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
5936 unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect,
5937 const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter,
5938 const struct wined3d_format *resolve_format)
5940 struct wined3d_blitter *next;
5942 if (!(next = blitter->next))
5944 ERR("No blitter to handle blit op %#x.\n", op);
5945 return dst_location;
5948 return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location,
5949 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter,
5950 resolve_format);
5953 static const struct wined3d_blitter_ops ffp_blitter_ops =
5955 ffp_blitter_destroy,
5956 ffp_blitter_clear,
5957 ffp_blitter_blit,
5960 void wined3d_ffp_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info)
5962 struct wined3d_blitter *blitter;
5964 if (!(blitter = malloc(sizeof(*blitter))))
5965 return;
5967 TRACE("Created blitter %p.\n", blitter);
5969 blitter->ops = &ffp_blitter_ops;
5970 blitter->next = *next;
5971 *next = blitter;
5974 static void fbo_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
5976 struct wined3d_blitter *next;
5978 if ((next = blitter->next))
5979 next->ops->blitter_destroy(next, context);
5981 free(blitter);
5984 static void fbo_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
5985 unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
5986 const RECT *draw_rect, uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int stencil)
5988 struct wined3d_blitter *next;
5990 if ((next = blitter->next))
5991 next->ops->blitter_clear(next, device, rt_count, fb, rect_count,
5992 clear_rects, draw_rect, flags, colour, depth, stencil);
5995 static DWORD fbo_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
5996 struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
5997 DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
5998 unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect,
5999 const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter,
6000 const struct wined3d_format *resolve_format)
6002 struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
6003 struct wined3d_resource *src_resource, *dst_resource;
6004 enum wined3d_blit_op blit_op = op;
6005 struct wined3d_device *device;
6006 struct wined3d_blitter *next;
6008 TRACE("blitter %p, op %#x, context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, "
6009 "src_rect %s, dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s, "
6010 "colour_key %p, filter %s, resolve_format %p.\n",
6011 blitter, op, context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location),
6012 wine_dbgstr_rect(src_rect), dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location),
6013 wine_dbgstr_rect(dst_rect), colour_key, debug_d3dtexturefiltertype(filter), resolve_format);
6015 src_resource = &src_texture->resource;
6016 dst_resource = &dst_texture->resource;
6018 device = dst_resource->device;
6020 if (blit_op == WINED3D_BLIT_OP_RAW_BLIT && dst_resource->format->id == src_resource->format->id)
6022 if (dst_resource->format->depth_size || dst_resource->format->stencil_size)
6023 blit_op = WINED3D_BLIT_OP_DEPTH_BLIT;
6024 else
6025 blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
6028 if (!fbo_blitter_supported(blit_op, context_gl->gl_info,
6029 src_resource, src_location, dst_resource, dst_location))
6031 if (!(next = blitter->next))
6033 ERR("No blitter to handle blit op %#x.\n", op);
6034 return dst_location;
6037 TRACE("Forwarding to blitter %p.\n", next);
6038 return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location,
6039 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter,
6040 resolve_format);
6043 if (blit_op == WINED3D_BLIT_OP_COLOR_BLIT)
6045 TRACE("Colour blit.\n");
6046 texture2d_blt_fbo(device, context, filter, src_texture, src_sub_resource_idx, src_location,
6047 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, resolve_format);
6048 return dst_location;
6051 if (blit_op == WINED3D_BLIT_OP_DEPTH_BLIT)
6053 TRACE("Depth/stencil blit.\n");
6054 texture2d_depth_blt_fbo(device, context, src_texture, src_sub_resource_idx, src_location,
6055 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect);
6056 return dst_location;
6059 ERR("This blitter does not implement blit op %#x.\n", blit_op);
6060 return dst_location;
6063 static const struct wined3d_blitter_ops fbo_blitter_ops =
6065 fbo_blitter_destroy,
6066 fbo_blitter_clear,
6067 fbo_blitter_blit,
6070 void wined3d_fbo_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info)
6072 struct wined3d_blitter *blitter;
6074 if (!(blitter = malloc(sizeof(*blitter))))
6075 return;
6077 TRACE("Created blitter %p.\n", blitter);
6079 blitter->ops = &fbo_blitter_ops;
6080 blitter->next = *next;
6081 *next = blitter;
6084 static void raw_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
6086 struct wined3d_blitter *next;
6088 if ((next = blitter->next))
6089 next->ops->blitter_destroy(next, context);
6091 free(blitter);
6094 static void raw_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
6095 unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
6096 const RECT *draw_rect, uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int stencil)
6098 struct wined3d_blitter *next;
6100 if (!(next = blitter->next))
6102 ERR("No blitter to handle clear.\n");
6103 return;
6106 TRACE("Forwarding to blitter %p.\n", next);
6107 next->ops->blitter_clear(next, device, rt_count, fb, rect_count,
6108 clear_rects, draw_rect, flags, colour, depth, stencil);
6111 static bool gl_formats_compatible(struct wined3d_texture *src_texture, DWORD src_location,
6112 struct wined3d_texture *dst_texture, DWORD dst_location)
6114 GLuint src_internal, dst_internal;
6115 bool src_ds, dst_ds;
6117 src_ds = src_texture->resource.format->depth_size || src_texture->resource.format->stencil_size;
6118 dst_ds = dst_texture->resource.format->depth_size || dst_texture->resource.format->stencil_size;
6119 if (src_ds == dst_ds)
6120 return true;
6121 /* Also check the internal format because, e.g. WINED3DFMT_D24_UNORM_S8_UINT has nonzero depth and stencil
6122 * sizes as does WINED3DFMT_R24G8_TYPELESS when bound with flag WINED3D_BIND_DEPTH_STENCIL, but these share
6123 * the same internal format with WINED3DFMT_R24_UNORM_X8_TYPELESS. */
6124 src_internal = wined3d_gl_get_internal_format(&src_texture->resource,
6125 wined3d_format_gl(src_texture->resource.format), src_location == WINED3D_LOCATION_TEXTURE_SRGB);
6126 dst_internal = wined3d_gl_get_internal_format(&dst_texture->resource,
6127 wined3d_format_gl(dst_texture->resource.format), dst_location == WINED3D_LOCATION_TEXTURE_SRGB);
6128 return src_internal == dst_internal;
6131 static DWORD raw_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
6132 struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
6133 DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
6134 unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect,
6135 const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter,
6136 const struct wined3d_format *resolve_format)
6138 struct wined3d_texture_gl *src_texture_gl = wined3d_texture_gl(src_texture);
6139 struct wined3d_texture_gl *dst_texture_gl = wined3d_texture_gl(dst_texture);
6140 struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
6141 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
6142 unsigned int src_level, src_layer, dst_level, dst_layer;
6143 struct wined3d_blitter *next;
6144 GLuint src_name, dst_name;
6145 DWORD location;
6147 /* If we would need to copy from a renderbuffer or drawable, we'd probably
6148 * be better off using the FBO blitter directly, since we'd need to use it
6149 * to copy the resource contents to the texture anyway.
6151 * We also can't copy between depth/stencil and colour resources, since
6152 * the formats are considered incompatible in OpenGL. */
6153 if (op != WINED3D_BLIT_OP_RAW_BLIT || !gl_formats_compatible(src_texture, src_location, dst_texture, dst_location)
6154 || ((src_texture->resource.format_attrs | dst_texture->resource.format_attrs)
6155 & WINED3D_FORMAT_ATTR_HEIGHT_SCALE)
6156 || (src_texture->resource.format->id == dst_texture->resource.format->id
6157 && (!(src_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
6158 || !(dst_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB)))))
6160 if (!(next = blitter->next))
6162 ERR("No blitter to handle blit op %#x.\n", op);
6163 return dst_location;
6166 TRACE("Forwarding to blitter %p.\n", next);
6167 return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location,
6168 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter,
6169 resolve_format);
6172 TRACE("Blit using ARB_copy_image.\n");
6174 src_level = src_sub_resource_idx % src_texture->level_count;
6175 src_layer = src_sub_resource_idx / src_texture->level_count;
6177 dst_level = dst_sub_resource_idx % dst_texture->level_count;
6178 dst_layer = dst_sub_resource_idx / dst_texture->level_count;
6180 location = src_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB);
6181 if (!location)
6182 location = src_texture->flags & WINED3D_TEXTURE_IS_SRGB
6183 ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
6184 if (!wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, location))
6185 ERR("Failed to load the source sub-resource into %s.\n", wined3d_debug_location(location));
6186 src_name = wined3d_texture_gl_get_texture_name(src_texture_gl,
6187 context, location == WINED3D_LOCATION_TEXTURE_SRGB);
6189 location = dst_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB);
6190 if (!location)
6191 location = dst_texture->flags & WINED3D_TEXTURE_IS_SRGB
6192 ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
6193 if (wined3d_texture_is_full_rect(dst_texture, dst_level, dst_rect))
6195 if (!wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, location))
6196 ERR("Failed to prepare the destination sub-resource into %s.\n", wined3d_debug_location(location));
6198 else
6200 if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, location))
6201 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(location));
6203 dst_name = wined3d_texture_gl_get_texture_name(dst_texture_gl,
6204 context, location == WINED3D_LOCATION_TEXTURE_SRGB);
6206 GL_EXTCALL(glCopyImageSubData(src_name, src_texture_gl->target, src_level,
6207 src_rect->left, src_rect->top, src_layer, dst_name, dst_texture_gl->target, dst_level,
6208 dst_rect->left, dst_rect->top, dst_layer, src_rect->right - src_rect->left,
6209 src_rect->bottom - src_rect->top, 1));
6210 checkGLcall("copy image data");
6212 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, location);
6213 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~location);
6214 if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location))
6215 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(dst_location));
6217 return dst_location | location;
6220 static const struct wined3d_blitter_ops raw_blitter_ops =
6222 raw_blitter_destroy,
6223 raw_blitter_clear,
6224 raw_blitter_blit,
6227 void wined3d_raw_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info)
6229 struct wined3d_blitter *blitter;
6231 if (!gl_info->supported[ARB_COPY_IMAGE])
6232 return;
6234 if (!(blitter = malloc(sizeof(*blitter))))
6235 return;
6237 TRACE("Created blitter %p.\n", blitter);
6239 blitter->ops = &raw_blitter_ops;
6240 blitter->next = *next;
6241 *next = blitter;
6244 static void vk_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
6246 struct wined3d_blitter *next;
6248 TRACE("blitter %p, context %p.\n", blitter, context);
6250 if ((next = blitter->next))
6251 next->ops->blitter_destroy(next, context);
6253 free(blitter);
6256 static void vk_blitter_clear_rendertargets(struct wined3d_context_vk *context_vk, unsigned int rt_count,
6257 const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects, const RECT *draw_rect,
6258 uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int stencil)
6260 unsigned int i, attachment_count, immediate_rt_count = 0, delay_count = 0;
6261 VkClearValue clear_values[WINED3D_MAX_RENDER_TARGETS + 1];
6262 VkImageView views[WINED3D_MAX_RENDER_TARGETS + 1];
6263 struct wined3d_rendertarget_view_vk *rtv_vk;
6264 struct wined3d_rendertarget_view *view;
6265 const struct wined3d_vk_info *vk_info;
6266 struct wined3d_fb_state immediate_fb;
6267 struct wined3d_device_vk *device_vk;
6268 VkCommandBuffer vk_command_buffer;
6269 VkRenderPassBeginInfo begin_desc;
6270 VkFramebufferCreateInfo fb_desc;
6271 VkFramebuffer vk_framebuffer;
6272 VkRenderPass vk_render_pass;
6273 bool depth_stencil = false;
6274 unsigned int layer_count;
6275 VkClearColorValue *c;
6276 VkResult vr;
6277 RECT r;
6279 TRACE("context_vk %p, rt_count %u, fb %p, rect_count %u, clear_rects %p, "
6280 "draw_rect %s, flags %#x, colour %s, depth %.8e, stencil %#x.\n",
6281 context_vk, rt_count, fb, rect_count, clear_rects,
6282 wine_dbgstr_rect(draw_rect), flags, debug_color(colour), depth, stencil);
6284 device_vk = wined3d_device_vk(context_vk->c.device);
6285 vk_info = context_vk->vk_info;
6287 if (!(flags & WINED3DCLEAR_TARGET))
6288 rt_count = 0;
6290 for (i = 0, attachment_count = 0, layer_count = 1; i < rt_count; ++i)
6292 if (!(view = fb->render_targets[i]))
6293 continue;
6295 /* Don't delay typeless clears because the data written into the resource depends on the
6296 * view format. Except all-zero clears, those should result in zeros in either case.
6298 * We could store the clear format along with the clear value, but then we'd have to
6299 * create a matching RTV at draw time, which would need its own render pass, thus mooting
6300 * the point of the delayed clear. (Unless we are lucky enough that the application
6301 * draws with the same RTV as it clears.) */
6302 if (is_full_clear(view, draw_rect, clear_rects)
6303 && (!wined3d_format_is_typeless(view->resource->format) || (!colour->r && !colour->g
6304 && !colour->b && !colour->a)))
6306 struct wined3d_texture *texture = texture_from_resource(view->resource);
6307 wined3d_rendertarget_view_validate_location(view, WINED3D_LOCATION_CLEARED);
6308 wined3d_rendertarget_view_invalidate_location(view, ~WINED3D_LOCATION_CLEARED);
6309 texture->sub_resources[view->sub_resource_idx].clear_value.colour = *colour;
6310 delay_count++;
6311 continue;
6313 else
6315 wined3d_rendertarget_view_load_location(view, &context_vk->c, view->resource->draw_binding);
6317 wined3d_rendertarget_view_validate_location(view, view->resource->draw_binding);
6318 wined3d_rendertarget_view_invalidate_location(view, ~view->resource->draw_binding);
6320 immediate_fb.render_targets[immediate_rt_count++] = view;
6321 rtv_vk = wined3d_rendertarget_view_vk(view);
6322 views[attachment_count] = wined3d_rendertarget_view_vk_get_image_view(rtv_vk, context_vk);
6323 wined3d_rendertarget_view_vk_barrier(rtv_vk, context_vk, WINED3D_BIND_RENDER_TARGET);
6325 c = &clear_values[attachment_count].color;
6326 wined3d_format_colour_to_vk(view->format, colour, c);
6328 if (view->layer_count > layer_count)
6329 layer_count = view->layer_count;
6331 ++attachment_count;
6334 if (!attachment_count)
6335 flags &= ~WINED3DCLEAR_TARGET;
6337 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && (view = fb->depth_stencil))
6339 DWORD full_flags = 0;
6341 /* Vulkan can clear only depth or stencil, but at the moment we can't put the depth and
6342 * stencil parts in separate locations. It isn't easy to do either, as such a half-cleared
6343 * texture would need to be handled not just as a DS target but also when used as a shader
6344 * resource or accessed on sysmem. */
6345 if (view->format->depth_size)
6346 full_flags = WINED3DCLEAR_ZBUFFER;
6347 if (view->format->stencil_size)
6348 full_flags |= WINED3DCLEAR_STENCIL;
6350 if (!is_full_clear(view, draw_rect, clear_rects) || (flags & full_flags) != full_flags
6351 || (wined3d_format_is_typeless(view->resource->format) && (depth || stencil)))
6353 wined3d_rendertarget_view_load_location(view, &context_vk->c, view->resource->draw_binding);
6354 wined3d_rendertarget_view_validate_location(view, view->resource->draw_binding);
6355 wined3d_rendertarget_view_invalidate_location(view, ~view->resource->draw_binding);
6357 immediate_fb.depth_stencil = view;
6358 rtv_vk = wined3d_rendertarget_view_vk(view);
6359 views[attachment_count] = wined3d_rendertarget_view_vk_get_image_view(rtv_vk, context_vk);
6360 wined3d_rendertarget_view_vk_barrier(rtv_vk, context_vk, WINED3D_BIND_DEPTH_STENCIL);
6362 clear_values[attachment_count].depthStencil.depth = depth;
6363 clear_values[attachment_count].depthStencil.stencil = stencil;
6365 if (view->layer_count > layer_count)
6366 layer_count = view->layer_count;
6368 depth_stencil = true;
6369 ++attachment_count;
6371 else
6373 struct wined3d_texture *texture = texture_from_resource(view->resource);
6374 texture->sub_resources[view->sub_resource_idx].clear_value.depth = depth;
6375 texture->sub_resources[view->sub_resource_idx].clear_value.stencil = stencil;
6376 wined3d_rendertarget_view_validate_location(view, WINED3D_LOCATION_CLEARED);
6377 wined3d_rendertarget_view_invalidate_location(view, ~WINED3D_LOCATION_CLEARED);
6378 flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
6379 delay_count++;
6383 if (!attachment_count)
6385 TRACE("The clear has been delayed until draw time.\n");
6386 return;
6389 TRACE("Doing an immediate clear of %u attachments.\n", attachment_count);
6390 if (delay_count)
6391 TRACE_(d3d_perf)("Partial clear: %u immediate, %u delayed.\n", attachment_count, delay_count);
6393 if (!(vk_render_pass = wined3d_context_vk_get_render_pass(context_vk, &immediate_fb,
6394 immediate_rt_count, flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL), flags)))
6396 ERR("Failed to get render pass.\n");
6397 return;
6400 if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk)))
6402 ERR("Failed to get command buffer.\n");
6403 return;
6406 fb_desc.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
6407 fb_desc.pNext = NULL;
6408 fb_desc.flags = 0;
6409 fb_desc.renderPass = vk_render_pass;
6410 fb_desc.attachmentCount = attachment_count;
6411 fb_desc.pAttachments = views;
6412 fb_desc.width = draw_rect->right - draw_rect->left;
6413 fb_desc.height = draw_rect->bottom - draw_rect->top;
6414 fb_desc.layers = layer_count;
6415 if ((vr = VK_CALL(vkCreateFramebuffer(device_vk->vk_device, &fb_desc, NULL, &vk_framebuffer))) < 0)
6417 ERR("Failed to create Vulkan framebuffer, vr %s.\n", wined3d_debug_vkresult(vr));
6418 return;
6421 begin_desc.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
6422 begin_desc.pNext = NULL;
6423 begin_desc.renderPass = vk_render_pass;
6424 begin_desc.framebuffer = vk_framebuffer;
6425 begin_desc.clearValueCount = attachment_count;
6426 begin_desc.pClearValues = clear_values;
6428 wined3d_context_vk_end_current_render_pass(context_vk);
6430 for (i = 0; i < rect_count; ++i)
6432 r.left = max(clear_rects[i].left, draw_rect->left);
6433 r.top = max(clear_rects[i].top, draw_rect->top);
6434 r.right = min(clear_rects[i].right, draw_rect->right);
6435 r.bottom = min(clear_rects[i].bottom, draw_rect->bottom);
6437 if (r.left >= r.right || r.top >= r.bottom)
6438 continue;
6440 begin_desc.renderArea.offset.x = r.left;
6441 begin_desc.renderArea.offset.y = r.top;
6442 begin_desc.renderArea.extent.width = r.right - r.left;
6443 begin_desc.renderArea.extent.height = r.bottom - r.top;
6444 VK_CALL(vkCmdBeginRenderPass(vk_command_buffer, &begin_desc, VK_SUBPASS_CONTENTS_INLINE));
6445 VK_CALL(vkCmdEndRenderPass(vk_command_buffer));
6448 wined3d_context_vk_destroy_vk_framebuffer(context_vk, vk_framebuffer, context_vk->current_command_buffer.id);
6450 for (i = 0; i < immediate_rt_count; ++i)
6451 wined3d_context_vk_reference_rendertarget_view(context_vk,
6452 wined3d_rendertarget_view_vk(immediate_fb.render_targets[i]));
6454 if (depth_stencil)
6455 wined3d_context_vk_reference_rendertarget_view(context_vk,
6456 wined3d_rendertarget_view_vk(immediate_fb.depth_stencil));
6459 static void vk_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
6460 unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
6461 const RECT *draw_rect, uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int stencil)
6463 struct wined3d_device_vk *device_vk = wined3d_device_vk(device);
6464 struct wined3d_rendertarget_view *view, *previous = NULL;
6465 struct wined3d_context_vk *context_vk;
6466 bool have_identical_size = true;
6467 struct wined3d_fb_state tmp_fb;
6468 unsigned int next_rt_count = 0;
6469 struct wined3d_blitter *next;
6470 uint32_t next_flags = 0;
6471 unsigned int i;
6473 TRACE("blitter %p, device %p, rt_count %u, fb %p, rect_count %u, clear_rects %p, "
6474 "draw_rect %s, flags %#x, colour %s, depth %.8e, stencil %#x.\n",
6475 blitter, device, rt_count, fb, rect_count, clear_rects,
6476 wine_dbgstr_rect(draw_rect), flags, debug_color(colour), depth, stencil);
6478 if (!rect_count)
6480 rect_count = 1;
6481 clear_rects = draw_rect;
6484 if (flags & WINED3DCLEAR_TARGET)
6486 for (i = 0; i < rt_count; ++i)
6488 if (!(view = fb->render_targets[i]))
6489 continue;
6491 if (blitter_use_cpu_clear(view))
6493 next_flags |= WINED3DCLEAR_TARGET;
6494 flags &= ~WINED3DCLEAR_TARGET;
6495 next_rt_count = rt_count;
6496 rt_count = 0;
6497 break;
6502 if ((flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) && (view = fb->depth_stencil)
6503 && (!view->format->depth_size || (flags & WINED3DCLEAR_ZBUFFER))
6504 && (!view->format->stencil_size || (flags & WINED3DCLEAR_STENCIL))
6505 && blitter_use_cpu_clear(view))
6507 next_flags |= flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
6508 flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
6511 if (flags)
6513 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
6515 for (i = 0; i < rt_count; ++i)
6517 if (!(view = fb->render_targets[i]))
6518 continue;
6520 if (previous && (previous->width != view->width || previous->height != view->height))
6521 have_identical_size = false;
6522 previous = view;
6524 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
6526 view = fb->depth_stencil;
6528 if (previous && (previous->width != view->width || previous->height != view->height))
6529 have_identical_size = false;
6532 if (have_identical_size)
6534 vk_blitter_clear_rendertargets(context_vk, rt_count, fb, rect_count,
6535 clear_rects, draw_rect, flags, colour, depth, stencil);
6537 else
6539 for (i = 0; i < rt_count; ++i)
6541 if (!(view = fb->render_targets[i]))
6542 continue;
6544 tmp_fb.render_targets[0] = view;
6545 tmp_fb.depth_stencil = NULL;
6546 vk_blitter_clear_rendertargets(context_vk, 1, &tmp_fb, rect_count,
6547 clear_rects, draw_rect, WINED3DCLEAR_TARGET, colour, depth, stencil);
6549 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
6551 tmp_fb.render_targets[0] = NULL;
6552 tmp_fb.depth_stencil = fb->depth_stencil;
6553 vk_blitter_clear_rendertargets(context_vk, 0, &tmp_fb, rect_count,
6554 clear_rects, draw_rect, flags & ~WINED3DCLEAR_TARGET, colour, depth, stencil);
6558 context_release(&context_vk->c);
6561 if (!next_flags)
6562 return;
6564 if (!(next = blitter->next))
6566 ERR("No blitter to handle clear.\n");
6567 return;
6570 TRACE("Forwarding to blitter %p.\n", next);
6571 next->ops->blitter_clear(next, device, next_rt_count, fb, rect_count,
6572 clear_rects, draw_rect, next_flags, colour, depth, stencil);
6575 static bool vk_blitter_blit_supported(enum wined3d_blit_op op, const struct wined3d_context *context,
6576 const struct wined3d_resource *src_resource, const RECT *src_rect,
6577 const struct wined3d_resource *dst_resource, const RECT *dst_rect, const struct wined3d_format *resolve_format)
6579 const struct wined3d_format *src_format = src_resource->format;
6580 const struct wined3d_format *dst_format = dst_resource->format;
6582 if (!(dst_resource->access & WINED3D_RESOURCE_ACCESS_GPU))
6584 TRACE("Destination resource does not have GPU access.\n");
6585 return false;
6588 if (!(src_resource->access & WINED3D_RESOURCE_ACCESS_GPU))
6590 TRACE("Source resource does not have GPU access.\n");
6591 return false;
6594 if (dst_format->id != src_format->id)
6596 if (!is_identity_fixup(dst_format->color_fixup))
6598 TRACE("Destination fixups are not supported.\n");
6599 return false;
6602 if (!is_identity_fixup(src_format->color_fixup))
6604 TRACE("Source fixups are not supported.\n");
6605 return false;
6608 if (op != WINED3D_BLIT_OP_RAW_BLIT
6609 && wined3d_format_vk(src_format)->vk_format != wined3d_format_vk(dst_format)->vk_format
6610 && ((!wined3d_format_is_typeless(src_format) && !wined3d_format_is_typeless(dst_format))
6611 || !resolve_format))
6613 TRACE("Format conversion not supported.\n");
6614 return false;
6618 if (wined3d_resource_get_sample_count(dst_resource) > 1)
6620 TRACE("Multi-sample destination resource not supported.\n");
6621 return false;
6624 if (op == WINED3D_BLIT_OP_RAW_BLIT)
6625 return true;
6627 if (op != WINED3D_BLIT_OP_COLOR_BLIT)
6629 TRACE("Unsupported blit operation %#x.\n", op);
6630 return false;
6633 if ((src_rect->right - src_rect->left != dst_rect->right - dst_rect->left)
6634 || (src_rect->bottom - src_rect->top != dst_rect->bottom - dst_rect->top))
6636 TRACE("Scaling not supported.\n");
6637 return false;
6640 return true;
6643 static DWORD vk_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
6644 struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
6645 DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
6646 unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect,
6647 const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter,
6648 const struct wined3d_format *resolve_format)
6650 struct wined3d_texture_vk *src_texture_vk = wined3d_texture_vk(src_texture);
6651 struct wined3d_texture_vk *dst_texture_vk = wined3d_texture_vk(dst_texture);
6652 struct wined3d_context_vk *context_vk = wined3d_context_vk(context);
6653 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
6654 VkImageSubresourceRange vk_src_range, vk_dst_range;
6655 VkImageLayout src_layout, dst_layout;
6656 VkCommandBuffer vk_command_buffer;
6657 struct wined3d_blitter *next;
6658 unsigned src_sample_count;
6659 bool resolve = false;
6661 TRACE("blitter %p, op %#x, context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, "
6662 "src_rect %s, dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s, "
6663 "colour_key %p, filter %s, resolve format %p.\n",
6664 blitter, op, context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location),
6665 wine_dbgstr_rect(src_rect), dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location),
6666 wine_dbgstr_rect(dst_rect), colour_key, debug_d3dtexturefiltertype(filter), resolve_format);
6668 if (!vk_blitter_blit_supported(op, context, &src_texture->resource, src_rect, &dst_texture->resource, dst_rect,
6669 resolve_format))
6670 goto next;
6672 src_sample_count = wined3d_resource_get_sample_count(&src_texture_vk->t.resource);
6673 if (src_sample_count > 1)
6674 resolve = true;
6676 vk_src_range.aspectMask = vk_aspect_mask_from_format(src_texture_vk->t.resource.format);
6677 vk_src_range.baseMipLevel = src_sub_resource_idx % src_texture->level_count;
6678 vk_src_range.levelCount = 1;
6679 vk_src_range.baseArrayLayer = src_sub_resource_idx / src_texture->level_count;
6680 vk_src_range.layerCount = 1;
6682 vk_dst_range.aspectMask = vk_aspect_mask_from_format(dst_texture_vk->t.resource.format);
6683 vk_dst_range.baseMipLevel = dst_sub_resource_idx % dst_texture->level_count;
6684 vk_dst_range.levelCount = 1;
6685 vk_dst_range.baseArrayLayer = dst_sub_resource_idx / dst_texture->level_count;
6686 vk_dst_range.layerCount = 1;
6688 if (!wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB))
6689 ERR("Failed to load the source sub-resource.\n");
6691 if (wined3d_texture_is_full_rect(dst_texture, vk_dst_range.baseMipLevel, dst_rect))
6693 if (!wined3d_texture_prepare_location(dst_texture,
6694 dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB))
6696 ERR("Failed to prepare the destination sub-resource.\n");
6697 goto next;
6700 else
6702 if (!wined3d_texture_load_location(dst_texture,
6703 dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB))
6705 ERR("Failed to load the destination sub-resource.\n");
6706 goto next;
6710 if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk)))
6712 ERR("Failed to get command buffer.\n");
6713 goto next;
6716 if (src_texture_vk->layout == VK_IMAGE_LAYOUT_GENERAL)
6717 src_layout = VK_IMAGE_LAYOUT_GENERAL;
6718 else
6719 src_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
6721 if (dst_texture_vk->layout == VK_IMAGE_LAYOUT_GENERAL)
6722 dst_layout = VK_IMAGE_LAYOUT_GENERAL;
6723 else
6724 dst_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
6726 wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
6727 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
6728 vk_access_mask_from_bind_flags(src_texture_vk->t.resource.bind_flags),
6729 VK_ACCESS_TRANSFER_READ_BIT, src_texture_vk->layout, src_layout,
6730 src_texture_vk->image.vk_image, &vk_src_range);
6731 wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
6732 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
6733 vk_access_mask_from_bind_flags(dst_texture_vk->t.resource.bind_flags),
6734 VK_ACCESS_TRANSFER_WRITE_BIT, dst_texture_vk->layout, dst_layout,
6735 dst_texture_vk->image.vk_image, &vk_dst_range);
6737 if (resolve)
6739 const struct wined3d_format_vk *src_format_vk = wined3d_format_vk(src_texture->resource.format);
6740 const struct wined3d_format_vk *dst_format_vk = wined3d_format_vk(dst_texture->resource.format);
6741 const unsigned int usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT
6742 | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
6743 VkImageLayout resolve_src_layout, resolve_dst_layout;
6744 VkImage src_vk_image, dst_vk_image;
6745 VkImageSubresourceRange vk_range;
6746 VkImageResolve resolve_region;
6747 VkImageType vk_image_type;
6748 VkImageCopy copy_region;
6749 VkFormat vk_format;
6751 if (resolve_format)
6753 vk_format = wined3d_format_vk(resolve_format)->vk_format;
6755 else if (!wined3d_format_is_typeless(src_texture->resource.format))
6757 vk_format = src_format_vk->vk_format;
6759 else
6761 vk_format = dst_format_vk->vk_format;
6764 switch (src_texture->resource.type)
6766 case WINED3D_RTYPE_TEXTURE_1D:
6767 vk_image_type = VK_IMAGE_TYPE_1D;
6768 break;
6769 case WINED3D_RTYPE_TEXTURE_2D:
6770 vk_image_type = VK_IMAGE_TYPE_2D;
6771 break;
6772 case WINED3D_RTYPE_TEXTURE_3D:
6773 vk_image_type = VK_IMAGE_TYPE_3D;
6774 break;
6775 default:
6776 ERR("Unexpected resource type: %s\n", debug_d3dresourcetype(src_texture->resource.type));
6777 goto barrier_next;
6780 vk_range.baseMipLevel = 0;
6781 vk_range.levelCount = 1;
6782 vk_range.baseArrayLayer = 0;
6783 vk_range.layerCount = 1;
6785 resolve_region.srcSubresource.aspectMask = vk_src_range.aspectMask;
6786 resolve_region.dstSubresource.aspectMask = vk_dst_range.aspectMask;
6787 resolve_region.extent.width = src_rect->right - src_rect->left;
6788 resolve_region.extent.height = src_rect->bottom - src_rect->top;
6789 resolve_region.extent.depth = 1;
6791 /* In case of typeless resolve the texture type may not match the resolve type.
6792 * To handle that, allocate intermediate texture(s) to resolve from/to.
6793 * A possible performance improvement would be to resolve using a shader instead. */
6794 if (src_format_vk->vk_format != vk_format)
6796 struct wined3d_image_vk src_image;
6798 if (!wined3d_context_vk_create_image(context_vk, vk_image_type, usage, vk_format,
6799 resolve_region.extent.width, resolve_region.extent.height, 1,
6800 src_sample_count, 1, 1, 0, &src_image))
6801 goto barrier_next;
6803 wined3d_context_vk_reference_image(context_vk, &src_image);
6804 src_vk_image = src_image.vk_image;
6805 wined3d_context_vk_destroy_image(context_vk, &src_image);
6807 vk_range.aspectMask = vk_src_range.aspectMask;
6809 wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
6810 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
6811 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
6812 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, src_vk_image, &vk_range);
6814 copy_region.srcSubresource.aspectMask = vk_src_range.aspectMask;
6815 copy_region.srcSubresource.mipLevel = vk_src_range.baseMipLevel;
6816 copy_region.srcSubresource.baseArrayLayer = vk_src_range.baseArrayLayer;
6817 copy_region.srcSubresource.layerCount = 1;
6818 copy_region.srcOffset.x = src_rect->left;
6819 copy_region.srcOffset.y = src_rect->top;
6820 copy_region.srcOffset.z = 0;
6821 copy_region.dstSubresource.aspectMask = vk_src_range.aspectMask;
6822 copy_region.dstSubresource.mipLevel = 0;
6823 copy_region.dstSubresource.baseArrayLayer = 0;
6824 copy_region.dstSubresource.layerCount = 1;
6825 copy_region.dstOffset.x = 0;
6826 copy_region.dstOffset.y = 0;
6827 copy_region.dstOffset.z = 0;
6828 copy_region.extent.width = resolve_region.extent.width;
6829 copy_region.extent.height = resolve_region.extent.height;
6830 copy_region.extent.depth = 1;
6832 VK_CALL(vkCmdCopyImage(vk_command_buffer, src_texture_vk->image.vk_image,
6833 src_layout, src_vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
6834 1, &copy_region));
6836 wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
6837 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
6838 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
6839 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
6840 src_vk_image, &vk_range);
6841 resolve_src_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
6843 resolve_region.srcSubresource.mipLevel = 0;
6844 resolve_region.srcSubresource.baseArrayLayer = 0;
6845 resolve_region.srcSubresource.layerCount = 1;
6846 resolve_region.srcOffset.x = 0;
6847 resolve_region.srcOffset.y = 0;
6848 resolve_region.srcOffset.z = 0;
6850 else
6852 src_vk_image = src_texture_vk->image.vk_image;
6853 resolve_src_layout = src_layout;
6855 resolve_region.srcSubresource.mipLevel = vk_src_range.baseMipLevel;
6856 resolve_region.srcSubresource.baseArrayLayer = vk_src_range.baseArrayLayer;
6857 resolve_region.srcSubresource.layerCount = 1;
6858 resolve_region.srcOffset.x = src_rect->left;
6859 resolve_region.srcOffset.y = src_rect->top;
6860 resolve_region.srcOffset.z = 0;
6863 if (dst_format_vk->vk_format != vk_format)
6865 struct wined3d_image_vk dst_image;
6867 if (!wined3d_context_vk_create_image(context_vk, vk_image_type, usage, vk_format,
6868 resolve_region.extent.width, resolve_region.extent.height, 1,
6869 VK_SAMPLE_COUNT_1_BIT, 1, 1, 0, &dst_image))
6870 goto barrier_next;
6872 wined3d_context_vk_reference_image(context_vk, &dst_image);
6873 dst_vk_image = dst_image.vk_image;
6874 wined3d_context_vk_destroy_image(context_vk, &dst_image);
6876 vk_range.aspectMask = vk_dst_range.aspectMask;
6877 wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
6878 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_WRITE_BIT,
6879 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_vk_image, &vk_range);
6880 resolve_dst_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
6882 resolve_region.dstSubresource.mipLevel = 0;
6883 resolve_region.dstSubresource.baseArrayLayer = 0;
6884 resolve_region.dstSubresource.layerCount = 1;
6885 resolve_region.dstOffset.x = 0;
6886 resolve_region.dstOffset.y = 0;
6887 resolve_region.dstOffset.z = 0;
6889 else
6891 dst_vk_image = dst_texture_vk->image.vk_image;
6892 resolve_dst_layout = dst_layout;
6894 resolve_region.dstSubresource.mipLevel = vk_dst_range.baseMipLevel;
6895 resolve_region.dstSubresource.baseArrayLayer = vk_dst_range.baseArrayLayer;
6896 resolve_region.dstSubresource.layerCount = 1;
6897 resolve_region.dstOffset.x = dst_rect->left;
6898 resolve_region.dstOffset.y = dst_rect->top;
6899 resolve_region.dstOffset.z = 0;
6902 VK_CALL(vkCmdResolveImage(vk_command_buffer, src_vk_image, resolve_src_layout,
6903 dst_vk_image, resolve_dst_layout, 1, &resolve_region));
6905 if (dst_vk_image != dst_texture_vk->image.vk_image)
6907 wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
6908 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
6909 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
6910 resolve_dst_layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
6911 dst_vk_image, &vk_range);
6913 copy_region.srcSubresource.aspectMask = vk_dst_range.aspectMask;
6914 copy_region.srcSubresource.mipLevel = 0;
6915 copy_region.srcSubresource.baseArrayLayer = 0;
6916 copy_region.srcSubresource.layerCount = 1;
6917 copy_region.srcOffset.x = 0;
6918 copy_region.srcOffset.y = 0;
6919 copy_region.srcOffset.z = 0;
6920 copy_region.dstSubresource.aspectMask = vk_dst_range.aspectMask;
6921 copy_region.dstSubresource.mipLevel = vk_dst_range.baseMipLevel;
6922 copy_region.dstSubresource.baseArrayLayer = vk_dst_range.baseArrayLayer;
6923 copy_region.dstSubresource.layerCount = 1;
6924 copy_region.dstOffset.x = dst_rect->left;
6925 copy_region.dstOffset.y = dst_rect->top;
6926 copy_region.dstOffset.z = 0;
6927 copy_region.extent.width = resolve_region.extent.width;
6928 copy_region.extent.height = resolve_region.extent.height;
6929 copy_region.extent.depth = 1;
6931 VK_CALL(vkCmdCopyImage(vk_command_buffer, dst_vk_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
6932 dst_texture_vk->image.vk_image, dst_layout, 1, &copy_region));
6935 else
6937 VkImageCopy region;
6939 region.srcSubresource.aspectMask = vk_src_range.aspectMask;
6940 region.srcSubresource.mipLevel = vk_src_range.baseMipLevel;
6941 region.srcSubresource.baseArrayLayer = vk_src_range.baseArrayLayer;
6942 region.srcSubresource.layerCount = vk_src_range.layerCount;
6943 region.srcOffset.x = src_rect->left;
6944 region.srcOffset.y = src_rect->top;
6945 region.srcOffset.z = 0;
6946 region.dstSubresource.aspectMask = vk_dst_range.aspectMask;
6947 region.dstSubresource.mipLevel = vk_dst_range.baseMipLevel;
6948 region.dstSubresource.baseArrayLayer = vk_dst_range.baseArrayLayer;
6949 region.dstSubresource.layerCount = vk_dst_range.layerCount;
6950 region.dstOffset.x = dst_rect->left;
6951 region.dstOffset.y = dst_rect->top;
6952 region.dstOffset.z = 0;
6953 region.extent.width = src_rect->right - src_rect->left;
6954 region.extent.height = src_rect->bottom - src_rect->top;
6955 region.extent.depth = 1;
6957 VK_CALL(vkCmdCopyImage(vk_command_buffer, src_texture_vk->image.vk_image, src_layout,
6958 dst_texture_vk->image.vk_image, dst_layout, 1, &region));
6961 wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
6962 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
6963 VK_ACCESS_TRANSFER_WRITE_BIT,
6964 vk_access_mask_from_bind_flags(dst_texture_vk->t.resource.bind_flags),
6965 dst_layout, dst_texture_vk->layout, dst_texture_vk->image.vk_image, &vk_dst_range);
6966 wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
6967 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
6968 VK_ACCESS_TRANSFER_READ_BIT,
6969 vk_access_mask_from_bind_flags(src_texture_vk->t.resource.bind_flags),
6970 src_layout, src_texture_vk->layout, src_texture_vk->image.vk_image, &vk_src_range);
6972 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
6973 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
6974 if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location))
6975 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(dst_location));
6977 wined3d_context_vk_reference_texture(context_vk, src_texture_vk);
6978 wined3d_context_vk_reference_texture(context_vk, dst_texture_vk);
6980 return dst_location | WINED3D_LOCATION_TEXTURE_RGB;
6982 barrier_next:
6983 wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
6984 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
6985 VK_ACCESS_TRANSFER_WRITE_BIT,
6986 vk_access_mask_from_bind_flags(dst_texture_vk->t.resource.bind_flags),
6987 dst_layout, dst_texture_vk->layout, dst_texture_vk->image.vk_image, &vk_dst_range);
6988 wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
6989 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
6990 VK_ACCESS_TRANSFER_READ_BIT,
6991 vk_access_mask_from_bind_flags(src_texture_vk->t.resource.bind_flags),
6992 src_layout, src_texture_vk->layout, src_texture_vk->image.vk_image, &vk_src_range);
6994 next:
6995 if (!(next = blitter->next))
6997 ERR("No blitter to handle blit op %#x.\n", op);
6998 return dst_location;
7001 TRACE("Forwarding to blitter %p.\n", next);
7002 return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location,
7003 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter, resolve_format);
7006 static const struct wined3d_blitter_ops vk_blitter_ops =
7008 .blitter_destroy = vk_blitter_destroy,
7009 .blitter_clear = vk_blitter_clear,
7010 .blitter_blit = vk_blitter_blit,
7013 void wined3d_vk_blitter_create(struct wined3d_blitter **next)
7015 struct wined3d_blitter *blitter;
7017 if (!(blitter = malloc(sizeof(*blitter))))
7018 return;
7020 TRACE("Created blitter %p.\n", blitter);
7022 blitter->ops = &vk_blitter_ops;
7023 blitter->next = *next;
7024 *next = blitter;