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
;
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
)
55 WARN("Invalid sub-resource index %u.\n", sub_resource_idx
);
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
)
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
))
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};
97 if (!texture
->swapchain
)
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
);
121 ERR("Texture %p is not part of a swapchain.\n", texture
);
125 if (texture
== swapchain
->front_buffer
)
127 TRACE("Returning GL_FRONT.\n");
131 if (texture
== swapchain
->back_buffers
[0])
133 TRACE("Returning GL_BACK.\n");
137 FIXME("Higher back buffer, returning GL_BACK.\n");
141 static uint32_t wined3d_resource_access_from_location(uint32_t location
)
145 case WINED3D_LOCATION_DISCARDED
:
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
;
160 FIXME("Unhandled location %#x.\n", location
);
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
;
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
);
190 FIXME("Unsupported texture target %#x.\n", target
);
191 /* Fall back to 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
;
198 coords
[1].x
= (float)rect
->right
/ w
;
199 coords
[1].y
= (float)rect
->top
/ h
;
202 coords
[2].x
= (float)rect
->left
/ w
;
203 coords
[2].y
= (float)rect
->bottom
/ h
;
206 coords
[3].x
= (float)rect
->right
/ w
;
207 coords
[3].y
= (float)rect
->bottom
/ h
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
281 if ((src_resource
->format_attrs
| dst_resource
->format_attrs
) & WINED3D_FORMAT_ATTR_HEIGHT_SCALE
)
284 /* Source and/or destination need to be on the GL side. */
285 if (!(src_resource
->access
& dst_resource
->access
& WINED3D_RESOURCE_ACCESS_GPU
))
288 if (src_resource
->type
!= WINED3D_RTYPE_TEXTURE_2D
)
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
)
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
)))
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
)))
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
)))
315 case WINED3D_BLIT_OP_DEPTH_BLIT
:
316 if (!(src_format
->caps
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3D_FORMAT_CAP_DEPTH_STENCIL
))
318 if (!(dst_format
->caps
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3D_FORMAT_CAP_DEPTH_STENCIL
))
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
))
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
;
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
;
367 gl_filter
= scaled_resolve
? GL_SCALED_RESOLVE_FASTEST_EXT
: GL_NEAREST
;
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
);
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
;
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
;
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
;
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
);
417 hr
= wined3d_texture_create(device
, &desc
, 1, 1, 0, NULL
, NULL
, &wined3d_null_parent_ops
,
418 &src_staging_texture
);
421 ERR("Failed to create staging texture, hr %#lx.\n", hr
);
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
;
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
;
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
);
456 hr
= wined3d_texture_create(device
, &desc
, 1, 1, 0, NULL
, NULL
, &wined3d_null_parent_ops
,
460 ERR("Failed to create staging texture, hr %#lx.\n", hr
);
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
);
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
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
;
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);
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
;
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
);
513 wined3d_texture_translate_drawable_coords(src_texture
, context_gl
->window
, &s
);
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
)
533 wined3d_texture_translate_drawable_coords(dst_texture
, context_gl
->window
, &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
);
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
);
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
;
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
));
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
;
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
));
609 ERR("Not a depth / stencil format: %s.\n",
610 debug_d3dformat(src_texture
->resource
.format
->id
));
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
);
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
);
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",
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
)
734 data
->buffer_object
= sub_resource
->bo
;
738 assert(location
== WINED3D_LOCATION_SYSMEM
);
739 if (sub_resource
->user_memory
)
741 data
->addr
= sub_resource
->user_memory
;
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
)
756 TRACE("texture %p\n", texture
);
758 if (!texture
->dirty_regions
)
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
;
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
));
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
))
799 wined3d_texture_validate_location(texture
, sub_resource_idx
, location
);
800 wined3d_texture_invalidate_location(texture
, sub_resource_idx
, WINED3D_LOCATION_DISCARDED
);
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
))
820 wined3d_texture_get_bo_address(texture
, sub_resource_idx
, &destination
, location
);
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
;
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
);
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
);
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
);
866 ret
= texture
->texture_ops
->texture_load_location(texture
, sub_resource_idx
, context
, location
);
870 wined3d_texture_validate_location(texture
, sub_resource_idx
, location
);
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;
894 if (locations
& WINED3D_LOCATION_BUFFER
)
896 wined3d_texture_get_bo_address(texture
, sub_resource_idx
, data
, WINED3D_LOCATION_BUFFER
);
900 if (locations
& WINED3D_LOCATION_SYSMEM
)
902 wined3d_texture_get_bo_address(texture
, sub_resource_idx
, data
, WINED3D_LOCATION_SYSMEM
);
906 ERR("Unexpected locations %s.\n", wined3d_debug_location(locations
));
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
;
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
;
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
);
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
;
984 level_count
= texture_gl
->t
.level_count
;
985 if (texture_gl
->target
== GL_TEXTURE_1D_ARRAY
|| texture_gl
->target
== GL_TEXTURE_2D_ARRAY
)
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
);
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
)
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)));
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
));
1055 case GL_TEXTURE_2D_MULTISAMPLE
:
1056 GL_EXTCALL(glTexStorage2DMultisample(texture_gl
->target
, samples
,
1057 gl_internal_format
, width
, height
, standard_pattern
));
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
));
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
));
1068 GL_EXTCALL(glTexStorage1D(texture_gl
->target
, texture_gl
->t
.level_count
, gl_internal_format
, width
));
1071 GL_EXTCALL(glTexStorage2D(texture_gl
->target
, texture_gl
->t
.level_count
,
1072 gl_internal_format
, width
, height
));
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
;
1085 if (!texture
->dirty_regions
)
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
;
1100 if (!wined3d_array_reserve((void **)®ions
->boxes
, ®ions
->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
;
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
;
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
;
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
));
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");
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
)
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
);
1188 desc
.pMemory
= data
.addr
;
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
);
1205 WARN("Failed to create DC, status %#lx.\n", status
);
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
;
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
];
1238 ERR("Sub-resource {%p, %u} has no DC.\n", texture
, sub_resource_idx
);
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
);
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);
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
;
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
))
1301 /* sRGB mode cache for preload() calls outside drawprim. */
1303 texture_gl
->t
.flags
|= WINED3D_TEXTURE_IS_SRGB
;
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
;
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
);
1319 ERR("Failed to generate a texture name.\n");
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
;
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
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
))
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
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
;
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
);
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
);
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
);
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
;
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
)
1552 struct wined3d_texture_idx texture_idx
= {texture
, i
};
1554 wined3d_texture_destroy_dc(&texture_idx
);
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
);
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. */
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
);
1646 texture
->resource
.device
->adapter
->adapter_ops
->adapter_destroy_texture(texture
);
1648 wined3d_mutex_unlock();
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
;
1669 TRACE("texture %p, context %p, srgb %#x.\n", texture
, context
, srgb
);
1671 if (!needs_separate_srgb_gl_texture(context
, texture
))
1675 flag
= WINED3D_TEXTURE_SRGB_VALID
;
1677 flag
= WINED3D_TEXTURE_RGB_VALID
;
1679 if (texture
->flags
& flag
)
1681 TRACE("Texture %p not dirty, nothing to do.\n", texture
);
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
;
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
));
1744 if (lod
>= texture
->level_count
)
1745 lod
= texture
->level_count
- 1;
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
);
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
])
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
));
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
);
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
)
1826 /* Remove any renderbuffer set if the sizes match */
1827 if (width
== src_width
&& height
== src_height
)
1829 texture_gl
->current_renderbuffer
= NULL
;
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
;
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
);
1887 slice_pitch
= height
* pitch
;
1889 wined3d_format_calculate_pitch(format
, 1, width
, height
, &pitch
, &slice_pitch
);
1891 wined3d_texture_get_pitch(texture
, level
, ¤t_row_pitch
, ¤t_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
);
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
)
1946 if (i
== sub_resource_count
)
1947 wined3d_resource_free_sysmem(&texture
->resource
);
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
);
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
);
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
)
1995 if (!(bo
= malloc(sizeof(*bo
))))
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
))
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
;
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
;
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
)
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
);
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
);
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
);
2087 if (texture_gl
->rb_multisample
)
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
);
2101 if (texture_gl
->rb_resolved
)
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
))
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
);
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
));
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
;
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
));
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");
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
);
2234 unpacking_rows
= true;
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
);
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
));
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
);
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
)
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
;
2322 byte_count
= format
->byte_count
;
2323 alpha_mask
= wined3d_mask_from_size(format
->alpha_size
) << format
->alpha_offset
;
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
;
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
;
2354 ERR("Unsupported byte count %u.\n", byte_count
);
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
;
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
)
2387 else if (dst_location
!= WINED3D_LOCATION_TEXTURE_RGB
)
2389 FIXME("Unhandled location %s.\n", wined3d_debug_location(dst_location
));
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
;
2412 case GL_TEXTURE_1D_ARRAY
:
2413 dst_y
= dst_sub_resource_idx
/ dst_texture
->level_count
;
2416 case GL_TEXTURE_2D_ARRAY
:
2417 dst_z
= dst_sub_resource_idx
/ dst_texture
->level_count
;
2420 case GL_TEXTURE_2D_MULTISAMPLE
:
2421 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY
:
2422 FIXME("Not supported for multisample textures.\n");
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
;
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
;
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
);
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
;
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");
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
)
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
);
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
);
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
;
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
;
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
;
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
));
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
);
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");
2589 if (format_gl
->f
.download
)
2591 struct wined3d_format f
;
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
));
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");
2616 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
2617 checkGLcall("glBindBuffer");
2618 mem
= temporary_mem
;
2622 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, bo
->id
));
2623 checkGLcall("glBindBuffer");
2624 mem
= (uint8_t *)data
->addr
+ bo
->b
.buffer_offset
;
2628 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
2629 checkGLcall("glBindBuffer");
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");
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
;
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");
2670 memcpy(data
->addr
, src_data
, sub_resource
->size
);
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
;
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
)
2711 else if (src_location
!= WINED3D_LOCATION_TEXTURE_RGB
)
2713 FIXME("Unhandled location %s.\n", wined3d_debug_location(src_location
));
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
));
2728 if (dst_x
|| dst_y
|| dst_z
)
2730 FIXME("Unhandled destination (%u, %u, %u).\n", dst_x
, dst_y
, dst_z
);
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
));
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
);
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
);
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
));
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
;
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");
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");
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
);
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
;
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
);
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
));
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
;
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
));
2877 if (wined3d_resource_is_offscreen(&texture
->resource
))
2879 ERR("Trying to load offscreen texture into WINED3D_LOCATION_DRAWABLE.\n");
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
);
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
));
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
);
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
;
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
))
2962 SetRect(&src_rect
, src_box
.left
, src_box
.top
, src_box
.right
, src_box
.bottom
);
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
);
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
);
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
;
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
);
2992 /* Upload from system memory */
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
);
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
);
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
);
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);
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
);
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
);
3089 case WINED3D_LOCATION_TEXTURE_RGB
:
3090 wined3d_texture_gl_prepare_texture(texture_gl
, context_gl
, FALSE
);
3093 case WINED3D_LOCATION_TEXTURE_SRGB
:
3094 wined3d_texture_gl_prepare_texture(texture_gl
, context_gl
, TRUE
);
3097 case WINED3D_LOCATION_DRAWABLE
:
3098 if (!texture
->swapchain
)
3099 ERR("Texture %p does not have a drawable.\n", texture
);
3102 case WINED3D_LOCATION_RB_MULTISAMPLE
:
3103 wined3d_texture_gl_prepare_rb(texture_gl
, context_gl
->gl_info
, TRUE
);
3106 case WINED3D_LOCATION_RB_RESOLVED
:
3107 wined3d_texture_gl_prepare_rb(texture_gl
, context_gl
->gl_info
, FALSE
);
3111 ERR("Invalid location %s.\n", wined3d_debug_location(location
));
3116 static bool use_ffp_clear(const struct wined3d_texture
*texture
, unsigned int location
)
3118 if (location
== WINED3D_LOCATION_DRAWABLE
)
3121 if (location
== WINED3D_LOCATION_TEXTURE_RGB
3122 && !(texture
->resource
.format_caps
& WINED3D_FORMAT_CAP_FBO_ATTACHABLE
))
3124 if (location
== WINED3D_LOCATION_TEXTURE_SRGB
3125 && !(texture
->resource
.format_caps
& WINED3D_FORMAT_CAP_FBO_ATTACHABLE_SRGB
))
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
);
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
));
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
);
3207 if (!wined3d_texture_prepare_location(texture
, sub_resource_idx
, &context_gl
->c
, WINED3D_LOCATION_SYSMEM
))
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
);
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
))
3229 if (sub_resource
->locations
& WINED3D_LOCATION_CLEARED
)
3231 if (!wined3d_texture_gl_clear(texture
, sub_resource_idx
, context_gl
, location
))
3234 if (sub_resource
->locations
& 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
);
3257 FIXME("Unhandled %s load from %s.\n", wined3d_debug_location(location
),
3258 wined3d_debug_location(texture
->sub_resources
[sub_resource_idx
].locations
));
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
));
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
);
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
);
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
);
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;
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
);
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;
3326 ERR("Unhandled location %s.\n", wined3d_debug_location(location
));
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
)
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
);
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
);
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
;
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
);
3490 if (resource
->usage
& WINED3DUSAGE_DYNAMIC
)
3491 WARN_(d3d_perf
)("Mapping a dynamic texture without WINED3D_MAP_DISCARD.\n");
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
)))
3504 ret
= wined3d_texture_load_location(texture
, sub_resource_idx
, context
, resource
->map_binding
);
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
)
3526 for (i
= 0; i
< texture
->level_count
; ++i
)
3527 wined3d_texture_invalidate_location(texture
, sub_resource_idx
+ i
, ~resource
->map_binding
);
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
);
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
)
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
);
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
);
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
;
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
;
3714 offset
= (offset
+ (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1);
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
)
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
);
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
;
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");
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
);
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
;
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};
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
)))
3880 if (FAILED(hr
= wined3d_resource_check_box_dimensions(&src_texture
->resource
, src_sub_resource_idx
, &src_box
)))
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");
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
);
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");
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
);
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
;
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
);
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
;
3984 overlay
->src_rect
= *src_rect
;
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
;
3992 overlay
->dst_rect
= *dst_rect
;
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
;
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
))
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
))
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
;
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
;
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
;
4105 texture_gl
->target
= GL_TEXTURE_1D
;
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
;
4118 texture_gl
->target
= GL_TEXTURE_2D_MULTISAMPLE
;
4122 if (layer_count
> 1)
4123 texture_gl
->target
= GL_TEXTURE_2D_ARRAY
;
4125 texture_gl
->target
= GL_TEXTURE_2D
;
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
;
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
)))
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
;
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
;
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
);
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
);
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
;
4207 for (i
= 0; i
< sub_count
; ++i
)
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
)))
4221 /* FIXME: We'd like to avoid ever allocating system memory for the texture
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
);
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
);
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
;
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
);
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
;
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
);
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
);
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
);
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
;
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
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
);
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
));
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
)
4547 ERR("Unhandled location %s.\n", wined3d_debug_location(location
));
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
;
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
;
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
));
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
;
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
;
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
));
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
));
4723 if (wined3d_resource_get_sample_count(&dst_texture_vk
->t
.resource
) > 1)
4725 FIXME("Not supported for multisample textures.\n");
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
));
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");
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");
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
);
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
);
4784 range
.size
= staging_size
;
4785 wined3d_context_unmap_bo_address(context
, &staging_bo_addr
, 1, &range
);
4787 src_bo
= &staging_bo
;
4790 src_row_pitch
= staging_row_pitch
;
4791 src_slice_pitch
= staging_slice_pitch
;
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
;
4831 region
.bufferImageHeight
= (src_slice_pitch
/ src_row_pitch
) * src_format
->block_height
;
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, ®ion
));
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;
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
));
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
));
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
));
4923 if (dst_x
|| dst_y
|| dst_z
)
4925 FIXME("Unhandled destination (%u, %u, %u).\n", dst_x
, dst_y
, dst_z
);
4929 if (wined3d_resource_get_sample_count(&src_texture_vk
->t
.resource
) > 1)
4931 FIXME("Not supported for multisample textures.\n");
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
));
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");
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");
4968 dst_bo
= &staging_bo
;
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, ®ion
));
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
);
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
);
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
;
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
))
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
);
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");
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
));
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
);
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
))
5163 if (sub_resource
->locations
& WINED3D_LOCATION_TEXTURE_RGB
)
5167 if (!(sub_resource
->locations
& wined3d_texture_sysmem_locations
))
5169 ERR("Unimplemented load from %s.\n", wined3d_debug_location(sub_resource
->locations
));
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);
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
));
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
);
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
)
5223 if (!(vk_command_buffer
= wined3d_context_vk_get_command_buffer(context_vk
)))
5225 ERR("Failed to get command buffer.\n");
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
;
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
;
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
;
5256 ERR("Invalid resource type %s.\n", debug_d3dresourcetype(resource
->type
));
5257 vk_image_type
= VK_IMAGE_TYPE_2D
;
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
;
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
))
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
,
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
);
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
)
5327 if (!(bo
= malloc(sizeof(*bo
))))
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
))
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
);
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
)
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
));
5363 FIXME("Unhandled location %s.\n", wined3d_debug_location(location
));
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
))
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
);
5384 FIXME("Unimplemented location %s.\n", wined3d_debug_location(location
));
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
));
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
);
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
);
5424 sub_resource
->bo
= NULL
;
5429 case WINED3D_LOCATION_TEXTURE_SRGB
:
5430 case WINED3D_LOCATION_RB_MULTISAMPLE
:
5431 case WINED3D_LOCATION_RB_RESOLVED
:
5435 ERR("Unhandled location %s.\n", wined3d_debug_location(location
));
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
;
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
;
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
;
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
;
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
)
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
,
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
);
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
)
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
))
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
;
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
);
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");
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
);
5657 wined3d_rendertarget_view_prepare_location(rtv
, context
, rtv
->resource
->draw_binding
);
5663 render_offscreen
= wined3d_resource_is_offscreen(&target
->resource
);
5664 wined3d_rendertarget_view_get_drawable_size(rtv
, context
, &drawable_width
, &drawable_height
);
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
);
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
);
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");
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
));
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
];
5732 if (rtv
->resource
->type
== WINED3D_RTYPE_BUFFER
)
5734 FIXME("Not supported on buffer resources.\n");
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
))
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
;
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
);
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
);
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(¤t_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(¤t_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");
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
);
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
;
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;
5850 if (flags
& WINED3DCLEAR_TARGET
)
5852 for (i
= 0; i
< rt_count
; ++i
)
5854 if (!(view
= fb
->render_targets
[i
]))
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
;
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
);
5884 for (i
= 0; i
< rt_count
; ++i
)
5886 if (!(view
= fb
->render_targets
[i
]))
5889 if (previous
&& (previous
->width
!= view
->width
|| previous
->height
!= view
->height
))
5890 have_identical_size
= false;
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
);
5908 for (i
= 0; i
< rt_count
; ++i
)
5910 if (!(view
= fb
->render_targets
[i
]))
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
,
5953 static const struct wined3d_blitter_ops ffp_blitter_ops
=
5955 ffp_blitter_destroy
,
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
))))
5967 TRACE("Created blitter %p.\n", blitter
);
5969 blitter
->ops
= &ffp_blitter_ops
;
5970 blitter
->next
= *next
;
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
);
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
;
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
,
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
,
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
))))
6077 TRACE("Created blitter %p.\n", blitter
);
6079 blitter
->ops
= &fbo_blitter_ops
;
6080 blitter
->next
= *next
;
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
);
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");
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
)
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
;
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
,
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
);
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
);
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
));
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
,
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
])
6234 if (!(blitter
= malloc(sizeof(*blitter
))))
6237 TRACE("Created blitter %p.\n", blitter
);
6239 blitter
->ops
= &raw_blitter_ops
;
6240 blitter
->next
= *next
;
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
);
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
;
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
))
6290 for (i
= 0, attachment_count
= 0, layer_count
= 1; i
< rt_count
; ++i
)
6292 if (!(view
= fb
->render_targets
[i
]))
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
;
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
;
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;
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
);
6383 if (!attachment_count
)
6385 TRACE("The clear has been delayed until draw time.\n");
6389 TRACE("Doing an immediate clear of %u attachments.\n", attachment_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");
6400 if (!(vk_command_buffer
= wined3d_context_vk_get_command_buffer(context_vk
)))
6402 ERR("Failed to get command buffer.\n");
6406 fb_desc
.sType
= VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO
;
6407 fb_desc
.pNext
= NULL
;
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
));
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
)
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
]));
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;
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
);
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
]))
6491 if (blitter_use_cpu_clear(view
))
6493 next_flags
|= WINED3DCLEAR_TARGET
;
6494 flags
&= ~WINED3DCLEAR_TARGET
;
6495 next_rt_count
= rt_count
;
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
);
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
]))
6520 if (previous
&& (previous
->width
!= view
->width
|| previous
->height
!= view
->height
))
6521 have_identical_size
= false;
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
);
6539 for (i
= 0; i
< rt_count
; ++i
)
6541 if (!(view
= fb
->render_targets
[i
]))
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
);
6564 if (!(next
= blitter
->next
))
6566 ERR("No blitter to handle clear.\n");
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");
6588 if (!(src_resource
->access
& WINED3D_RESOURCE_ACCESS_GPU
))
6590 TRACE("Source resource does not have GPU access.\n");
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");
6602 if (!is_identity_fixup(src_format
->color_fixup
))
6604 TRACE("Source fixups are not supported.\n");
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");
6618 if (wined3d_resource_get_sample_count(dst_resource
) > 1)
6620 TRACE("Multi-sample destination resource not supported.\n");
6624 if (op
== WINED3D_BLIT_OP_RAW_BLIT
)
6627 if (op
!= WINED3D_BLIT_OP_COLOR_BLIT
)
6629 TRACE("Unsupported blit operation %#x.\n", op
);
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");
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
,
6672 src_sample_count
= wined3d_resource_get_sample_count(&src_texture_vk
->t
.resource
);
6673 if (src_sample_count
> 1)
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");
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");
6710 if (!(vk_command_buffer
= wined3d_context_vk_get_command_buffer(context_vk
)))
6712 ERR("Failed to get command buffer.\n");
6716 if (src_texture_vk
->layout
== VK_IMAGE_LAYOUT_GENERAL
)
6717 src_layout
= VK_IMAGE_LAYOUT_GENERAL
;
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
;
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
);
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
;
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
;
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
;
6769 case WINED3D_RTYPE_TEXTURE_2D
:
6770 vk_image_type
= VK_IMAGE_TYPE_2D
;
6772 case WINED3D_RTYPE_TEXTURE_3D
:
6773 vk_image_type
= VK_IMAGE_TYPE_3D
;
6776 ERR("Unexpected resource type: %s\n", debug_d3dresourcetype(src_texture
->resource
.type
));
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
))
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
,
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;
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
))
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;
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, ©_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, ®ion
));
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
;
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
);
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
))))
7020 TRACE("Created blitter %p.\n", blitter
);
7022 blitter
->ops
= &vk_blitter_ops
;
7023 blitter
->next
= *next
;