From: Stian Low wineryyyyy@gmail.com
wined3d: texture.c split vulkan and opengl for cleaner clarity --- dlls/wined3d/Makefile.in | 2 + dlls/wined3d/texture.c | 6725 +++++--------------------------- dlls/wined3d/texture_gl.c | 2893 ++++++++++++++ dlls/wined3d/texture_vk.c | 1950 +++++++++ dlls/wined3d/wined3d_private.h | 44 + 5 files changed, 5827 insertions(+), 5787 deletions(-) create mode 100644 dlls/wined3d/texture_gl.c create mode 100644 dlls/wined3d/texture_vk.c
diff --git a/dlls/wined3d/Makefile.in b/dlls/wined3d/Makefile.in index 19a36c25674..8b077e310c1 100644 --- a/dlls/wined3d/Makefile.in +++ b/dlls/wined3d/Makefile.in @@ -31,6 +31,8 @@ SOURCES = \ surface.c \ swapchain.c \ texture.c \ + texture_gl.c \ + texture_vk.c \ utils.c \ version.rc \ vertexdeclaration.c \ diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index e0271151735..f88fdef9b37 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -21,8 +21,6 @@ */
#include "wined3d_private.h" -#include "wined3d_gl.h" -#include "wined3d_vk.h"
WINE_DEFAULT_DEBUG_CHANNEL(d3d); WINE_DECLARE_DEBUG_CHANNEL(d3d_perf); @@ -30,23 +28,12 @@ WINE_DECLARE_DEBUG_CHANNEL(winediag);
#define WINED3D_TEXTURE_DYNAMIC_MAP_THRESHOLD 50
-static const uint32_t wined3d_texture_sysmem_locations = WINED3D_LOCATION_SYSMEM | WINED3D_LOCATION_BUFFER; -static const struct wined3d_texture_ops texture_gl_ops; - struct wined3d_texture_idx { struct wined3d_texture *texture; unsigned int sub_resource_idx; };
-struct wined3d_rect_f -{ - float l; - float t; - float r; - float b; -}; - bool wined3d_texture_validate_sub_resource_idx(const struct wined3d_texture *texture, unsigned int sub_resource_idx) { if (sub_resource_idx < texture->level_count * texture->layer_count) @@ -75,15 +62,6 @@ static BOOL wined3d_texture_use_pbo(const struct wined3d_texture *texture, const || texture->resource.access == (WINED3D_RESOURCE_ACCESS_CPU | WINED3D_RESOURCE_ACCESS_MAP_R); }
-static BOOL wined3d_texture_use_immutable_storage(const struct wined3d_texture *texture, - const struct wined3d_gl_info *gl_info) -{ - /* We don't expect to create texture views for textures with height-scaled formats. - * Besides, ARB_texture_storage doesn't allow specifying exact sizes for all levels. */ - return gl_info->supported[ARB_TEXTURE_STORAGE] - && !(texture->resource.format_attrs & WINED3D_FORMAT_ATTR_HEIGHT_SCALE); -} - /* Front buffer coordinates are always full screen coordinates, but our GL * drawable is limited to the window's client area. The sysmem and texture * copies do have the full screen size. Note that GL has a bottom-left @@ -110,34 +88,6 @@ void wined3d_texture_translate_drawable_coords(const struct wined3d_texture *tex rect->bottom = drawable_height - rect->bottom; }
-GLenum wined3d_texture_get_gl_buffer(const struct wined3d_texture *texture) -{ - const struct wined3d_swapchain *swapchain = texture->swapchain; - - TRACE("texture %p.\n", texture); - - if (!swapchain) - { - ERR("Texture %p is not part of a swapchain.\n", texture); - return GL_NONE; - } - - if (texture == swapchain->front_buffer) - { - TRACE("Returning GL_FRONT.\n"); - return GL_FRONT; - } - - if (texture == swapchain->back_buffers[0]) - { - TRACE("Returning GL_BACK.\n"); - return GL_BACK; - } - - FIXME("Higher back buffer, returning GL_BACK.\n"); - return GL_BACK; -} - static uint32_t wined3d_resource_access_from_location(uint32_t location) { switch (location) @@ -162,492 +112,6 @@ static uint32_t wined3d_resource_access_from_location(uint32_t location) } }
-static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct wined3d_rect_f *f) -{ - f->l = ((r->left * 2.0f) / w) - 1.0f; - f->t = ((r->top * 2.0f) / h) - 1.0f; - f->r = ((r->right * 2.0f) / w) - 1.0f; - f->b = ((r->bottom * 2.0f) / h) - 1.0f; -} - -void texture2d_get_blt_info(const struct wined3d_texture_gl *texture_gl, - unsigned int sub_resource_idx, const RECT *rect, struct wined3d_blt_info *info) -{ - struct wined3d_vec3 *coords = info->texcoords; - struct wined3d_rect_f f; - unsigned int level; - GLenum target; - GLsizei w, h; - - level = sub_resource_idx % texture_gl->t.level_count; - w = wined3d_texture_get_level_width(&texture_gl->t, level); - h = wined3d_texture_get_level_height(&texture_gl->t, level); - target = wined3d_texture_gl_get_sub_resource_target(texture_gl, sub_resource_idx); - - switch (target) - { - default: - FIXME("Unsupported texture target %#x.\n", target); - /* Fall back to GL_TEXTURE_2D */ - case GL_TEXTURE_2D: - info->bind_target = GL_TEXTURE_2D; - coords[0].x = (float)rect->left / w; - coords[0].y = (float)rect->top / h; - coords[0].z = 0.0f; - - coords[1].x = (float)rect->right / w; - coords[1].y = (float)rect->top / h; - coords[1].z = 0.0f; - - coords[2].x = (float)rect->left / w; - coords[2].y = (float)rect->bottom / h; - coords[2].z = 0.0f; - - coords[3].x = (float)rect->right / w; - coords[3].y = (float)rect->bottom / h; - coords[3].z = 0.0f; - break; - - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; - cube_coords_float(rect, w, h, &f); - - coords[0].x = 1.0f; coords[0].y = -f.t; coords[0].z = -f.l; - coords[1].x = 1.0f; coords[1].y = -f.t; coords[1].z = -f.r; - coords[2].x = 1.0f; coords[2].y = -f.b; coords[2].z = -f.l; - coords[3].x = 1.0f; coords[3].y = -f.b; coords[3].z = -f.r; - break; - - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; - cube_coords_float(rect, w, h, &f); - - coords[0].x = -1.0f; coords[0].y = -f.t; coords[0].z = f.l; - coords[1].x = -1.0f; coords[1].y = -f.t; coords[1].z = f.r; - coords[2].x = -1.0f; coords[2].y = -f.b; coords[2].z = f.l; - coords[3].x = -1.0f; coords[3].y = -f.b; coords[3].z = f.r; - break; - - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; - cube_coords_float(rect, w, h, &f); - - coords[0].x = f.l; coords[0].y = 1.0f; coords[0].z = f.t; - coords[1].x = f.r; coords[1].y = 1.0f; coords[1].z = f.t; - coords[2].x = f.l; coords[2].y = 1.0f; coords[2].z = f.b; - coords[3].x = f.r; coords[3].y = 1.0f; coords[3].z = f.b; - break; - - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; - cube_coords_float(rect, w, h, &f); - - coords[0].x = f.l; coords[0].y = -1.0f; coords[0].z = -f.t; - coords[1].x = f.r; coords[1].y = -1.0f; coords[1].z = -f.t; - coords[2].x = f.l; coords[2].y = -1.0f; coords[2].z = -f.b; - coords[3].x = f.r; coords[3].y = -1.0f; coords[3].z = -f.b; - break; - - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; - cube_coords_float(rect, w, h, &f); - - coords[0].x = f.l; coords[0].y = -f.t; coords[0].z = 1.0f; - coords[1].x = f.r; coords[1].y = -f.t; coords[1].z = 1.0f; - coords[2].x = f.l; coords[2].y = -f.b; coords[2].z = 1.0f; - coords[3].x = f.r; coords[3].y = -f.b; coords[3].z = 1.0f; - break; - - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; - cube_coords_float(rect, w, h, &f); - - coords[0].x = -f.l; coords[0].y = -f.t; coords[0].z = -1.0f; - coords[1].x = -f.r; coords[1].y = -f.t; coords[1].z = -1.0f; - coords[2].x = -f.l; coords[2].y = -f.b; coords[2].z = -1.0f; - coords[3].x = -f.r; coords[3].y = -f.b; coords[3].z = -1.0f; - break; - } -} - -static bool fbo_blitter_supported(enum wined3d_blit_op blit_op, const struct wined3d_gl_info *gl_info, - const struct wined3d_resource *src_resource, DWORD src_location, - const struct wined3d_resource *dst_resource, DWORD dst_location) -{ - const struct wined3d_format *src_format = src_resource->format; - const struct wined3d_format *dst_format = dst_resource->format; - bool src_ds, dst_ds; - - if ((src_resource->format_attrs | dst_resource->format_attrs) & WINED3D_FORMAT_ATTR_HEIGHT_SCALE) - return false; - - /* Source and/or destination need to be on the GL side. */ - if (!(src_resource->access & dst_resource->access & WINED3D_RESOURCE_ACCESS_GPU)) - return false; - - if (src_resource->type != WINED3D_RTYPE_TEXTURE_2D) - return false; - - /* We can't copy between depth/stencil and colour attachments. One notable - * way we can end up here is when copying between typeless resources with - * formats like R16_TYPELESS, which can end up using either a - * depth/stencil or a colour format on the OpenGL side, depending on the - * resource's bind flags. */ - src_ds = src_format->depth_size || src_format->stencil_size; - dst_ds = dst_format->depth_size || dst_format->stencil_size; - if (src_ds != dst_ds) - return false; - - switch (blit_op) - { - case WINED3D_BLIT_OP_COLOR_BLIT: - if (!((src_format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_FBO_ATTACHABLE) - || (src_resource->bind_flags & WINED3D_BIND_RENDER_TARGET))) - return false; - if (!((dst_format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_FBO_ATTACHABLE) - || (dst_resource->bind_flags & WINED3D_BIND_RENDER_TARGET))) - return false; - if ((src_format->id != dst_format->id || dst_location == WINED3D_LOCATION_DRAWABLE) - && (!is_identity_fixup(src_format->color_fixup) || !is_identity_fixup(dst_format->color_fixup))) - return false; - break; - - case WINED3D_BLIT_OP_DEPTH_BLIT: - if (!(src_format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_DEPTH_STENCIL)) - return false; - if (!(dst_format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_DEPTH_STENCIL)) - return false; - /* Accept pure swizzle fixups for depth formats. In general we - * ignore the stencil component (if present) at the moment and the - * swizzle is not relevant with just the depth component. */ - if (is_complex_fixup(src_format->color_fixup) || is_complex_fixup(dst_format->color_fixup) - || is_scaling_fixup(src_format->color_fixup) || is_scaling_fixup(dst_format->color_fixup)) - return false; - break; - - default: - return false; - } - - return true; -} - -/* Blit between surface locations. Onscreen on different swapchains is not supported. - * Depth / stencil is not supported. Context activation is done by the caller. */ -static void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_context *context, - enum wined3d_texture_filter_type filter, struct wined3d_texture *src_texture, - unsigned int src_sub_resource_idx, DWORD src_location, const RECT *src_rect, - struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, DWORD dst_location, - const RECT *dst_rect, const struct wined3d_format *resolve_format) -{ - struct wined3d_texture *required_texture, *restore_texture, *dst_save_texture = dst_texture; - unsigned int restore_idx, dst_save_sub_resource_idx = dst_sub_resource_idx; - bool resolve, scaled_resolve, restore_context = false; - struct wined3d_texture *src_staging_texture = NULL; - const struct wined3d_gl_info *gl_info; - struct wined3d_context_gl *context_gl; - GLenum gl_filter; - GLenum buffer; - RECT s, d; - - TRACE("device %p, context %p, filter %s, src_texture %p, src_sub_resource_idx %u, src_location %s, " - "src_rect %s, dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s, resolve format %p.\n", - device, context, debug_d3dtexturefiltertype(filter), src_texture, src_sub_resource_idx, - wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect), dst_texture, - dst_sub_resource_idx, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect), resolve_format); - - resolve = wined3d_texture_gl_is_multisample_location(wined3d_texture_gl(src_texture), src_location); - scaled_resolve = resolve - && (abs(src_rect->bottom - src_rect->top) != abs(dst_rect->bottom - dst_rect->top) - || abs(src_rect->right - src_rect->left) != abs(dst_rect->right - dst_rect->left)); - - if (filter == WINED3D_TEXF_LINEAR) - gl_filter = scaled_resolve ? GL_SCALED_RESOLVE_NICEST_EXT : GL_LINEAR; - else - gl_filter = scaled_resolve ? GL_SCALED_RESOLVE_FASTEST_EXT : GL_NEAREST; - - if (resolve) - { - GLint resolve_internal, src_internal, dst_internal; - enum wined3d_format_id resolve_format_id; - - src_internal = wined3d_gl_get_internal_format(&src_texture->resource, - wined3d_format_gl(src_texture->resource.format), src_location == WINED3D_LOCATION_TEXTURE_SRGB); - dst_internal = wined3d_gl_get_internal_format(&dst_texture->resource, - wined3d_format_gl(dst_texture->resource.format), dst_location == WINED3D_LOCATION_TEXTURE_SRGB); - - if (resolve_format) - { - resolve_internal = wined3d_format_gl(resolve_format)->internal; - resolve_format_id = resolve_format->id; - } - else if (!wined3d_format_is_typeless(src_texture->resource.format)) - { - resolve_internal = src_internal; - resolve_format_id = src_texture->resource.format->id; - } - else - { - resolve_internal = dst_internal; - resolve_format_id = dst_texture->resource.format->id; - } - - /* In case of typeless resolve the texture type may not match the resolve type. - * To handle that, allocate intermediate texture(s) to resolve from/to. - * A possible performance improvement would be to resolve using a shader instead. */ - if (src_internal != resolve_internal) - { - struct wined3d_resource_desc desc; - unsigned src_level; - HRESULT hr; - - src_level = src_sub_resource_idx % src_texture->level_count; - desc.resource_type = WINED3D_RTYPE_TEXTURE_2D; - desc.format = resolve_format_id; - desc.multisample_type = src_texture->resource.multisample_type; - desc.multisample_quality = src_texture->resource.multisample_quality; - desc.usage = WINED3DUSAGE_CS; - desc.bind_flags = 0; - desc.access = WINED3D_RESOURCE_ACCESS_GPU; - desc.width = wined3d_texture_get_level_width(src_texture, src_level); - desc.height = wined3d_texture_get_level_height(src_texture, src_level); - desc.depth = 1; - desc.size = 0; - - hr = wined3d_texture_create(device, &desc, 1, 1, 0, NULL, NULL, &wined3d_null_parent_ops, - &src_staging_texture); - if (FAILED(hr)) - { - ERR("Failed to create staging texture, hr %#lx.\n", hr); - goto done; - } - - if (src_location == WINED3D_LOCATION_DRAWABLE) - FIXME("WINED3D_LOCATION_DRAWABLE not supported for the source of a typeless resolve.\n"); - - device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_RAW_BLIT, context, - src_texture, src_sub_resource_idx, src_location, src_rect, - src_staging_texture, 0, src_location, src_rect, - NULL, WINED3D_TEXF_NONE, NULL); - - src_texture = src_staging_texture; - src_sub_resource_idx = 0; - } - - if (dst_internal != resolve_internal) - { - struct wined3d_resource_desc desc; - unsigned dst_level; - HRESULT hr; - - dst_level = dst_sub_resource_idx % dst_texture->level_count; - desc.resource_type = WINED3D_RTYPE_TEXTURE_2D; - desc.format = resolve_format_id; - desc.multisample_type = dst_texture->resource.multisample_type; - desc.multisample_quality = dst_texture->resource.multisample_quality; - desc.usage = WINED3DUSAGE_CS; - desc.bind_flags = 0; - desc.access = WINED3D_RESOURCE_ACCESS_GPU; - desc.width = wined3d_texture_get_level_width(dst_texture, dst_level); - desc.height = wined3d_texture_get_level_height(dst_texture, dst_level); - desc.depth = 1; - desc.size = 0; - - hr = wined3d_texture_create(device, &desc, 1, 1, 0, NULL, NULL, &wined3d_null_parent_ops, - &dst_texture); - if (FAILED(hr)) - { - ERR("Failed to create staging texture, hr %#lx.\n", hr); - goto done; - } - - wined3d_texture_load_location(dst_texture, 0, context, dst_location); - dst_sub_resource_idx = 0; - } - } - - /* Make sure the locations are up-to-date. Loading the destination - * surface isn't required if the entire surface is overwritten. (And is - * in fact harmful if we're being called by surface_load_location() with - * the purpose of loading the destination surface.) */ - wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, src_location); - if (!wined3d_texture_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, dst_rect)) - wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location); - else - wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location); - - /* Acquire a context for the front-buffer, even though we may be blitting - * to/from a back-buffer. Since context_acquire() doesn't take the - * resource location into account, it may consider the back-buffer to be - * offscreen. */ - if (src_location == WINED3D_LOCATION_DRAWABLE) - required_texture = src_texture->swapchain->front_buffer; - else if (dst_location == WINED3D_LOCATION_DRAWABLE) - required_texture = dst_texture->swapchain->front_buffer; - else - required_texture = NULL; - - restore_texture = context->current_rt.texture; - restore_idx = context->current_rt.sub_resource_idx; - if (restore_texture != required_texture) - { - context = context_acquire(device, required_texture, 0); - restore_context = true; - } - - context_gl = wined3d_context_gl(context); - if (!context_gl->valid) - { - context_release(context); - WARN("Invalid context, skipping blit.\n"); - restore_context = false; - goto done; - } - - gl_info = context_gl->gl_info; - - if (src_location == WINED3D_LOCATION_DRAWABLE) - { - TRACE("Source texture %p is onscreen.\n", src_texture); - buffer = wined3d_texture_get_gl_buffer(src_texture); - s = *src_rect; - wined3d_texture_translate_drawable_coords(src_texture, context_gl->window, &s); - src_rect = &s; - } - else - { - TRACE("Source texture %p is offscreen.\n", src_texture); - buffer = GL_COLOR_ATTACHMENT0; - } - - wined3d_context_gl_apply_fbo_state_explicit(context_gl, GL_READ_FRAMEBUFFER, - &src_texture->resource, src_sub_resource_idx, NULL, 0, src_location); - gl_info->gl_ops.gl.p_glReadBuffer(buffer); - checkGLcall("glReadBuffer()"); - wined3d_context_gl_check_fbo_status(context_gl, GL_READ_FRAMEBUFFER); - - context_gl_apply_texture_draw_state(context_gl, dst_texture, dst_sub_resource_idx, dst_location); - - if (dst_location == WINED3D_LOCATION_DRAWABLE) - { - d = *dst_rect; - wined3d_texture_translate_drawable_coords(dst_texture, context_gl->window, &d); - dst_rect = &d; - } - - gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - context_invalidate_state(context, STATE_BLEND); - - gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST); - context_invalidate_state(context, STATE_RASTERIZER); - - gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, - dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, GL_COLOR_BUFFER_BIT, gl_filter); - checkGLcall("glBlitFramebuffer()"); - - if (dst_location == WINED3D_LOCATION_DRAWABLE && dst_texture->swapchain->front_buffer == dst_texture) - gl_info->gl_ops.gl.p_glFlush(); - - if (dst_texture != dst_save_texture) - { - if (dst_location == WINED3D_LOCATION_DRAWABLE) - FIXME("WINED3D_LOCATION_DRAWABLE not supported for the destination of a typeless resolve.\n"); - - device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_RAW_BLIT, context, - dst_texture, 0, dst_location, dst_rect, - dst_save_texture, dst_save_sub_resource_idx, dst_location, dst_rect, - NULL, WINED3D_TEXF_NONE, NULL); - } - -done: - if (dst_texture != dst_save_texture) - wined3d_texture_decref(dst_texture); - - if (src_staging_texture) - wined3d_texture_decref(src_staging_texture); - - if (restore_context) - context_restore(context, restore_texture, restore_idx); -} - -static void texture2d_depth_blt_fbo(const struct wined3d_device *device, struct wined3d_context *context, - struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, DWORD src_location, - const RECT *src_rect, struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, - DWORD dst_location, const RECT *dst_rect) -{ - struct wined3d_context_gl *context_gl = wined3d_context_gl(context); - const struct wined3d_gl_info *gl_info = context_gl->gl_info; - GLbitfield src_mask, dst_mask; - GLbitfield gl_mask; - - TRACE("device %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_rect %s, " - "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s.\n", device, - src_texture, src_sub_resource_idx, wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect), - dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect)); - - src_mask = 0; - if (src_texture->resource.format->depth_size) - src_mask |= GL_DEPTH_BUFFER_BIT; - if (src_texture->resource.format->stencil_size) - src_mask |= GL_STENCIL_BUFFER_BIT; - - dst_mask = 0; - if (dst_texture->resource.format->depth_size) - dst_mask |= GL_DEPTH_BUFFER_BIT; - if (dst_texture->resource.format->stencil_size) - dst_mask |= GL_STENCIL_BUFFER_BIT; - - if (src_mask != dst_mask) - { - ERR("Incompatible formats %s and %s.\n", - debug_d3dformat(src_texture->resource.format->id), - debug_d3dformat(dst_texture->resource.format->id)); - return; - } - - if (!src_mask) - { - ERR("Not a depth / stencil format: %s.\n", - debug_d3dformat(src_texture->resource.format->id)); - return; - } - gl_mask = src_mask; - - /* Make sure the locations are up-to-date. Loading the destination - * surface isn't required if the entire surface is overwritten. */ - wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, src_location); - if (!wined3d_texture_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, dst_rect)) - wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location); - else - wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location); - - wined3d_context_gl_apply_fbo_state_explicit(context_gl, GL_READ_FRAMEBUFFER, NULL, 0, - &src_texture->resource, src_sub_resource_idx, src_location); - wined3d_context_gl_check_fbo_status(context_gl, GL_READ_FRAMEBUFFER); - - context_gl_apply_texture_draw_state(context_gl, dst_texture, dst_sub_resource_idx, dst_location); - - if (gl_mask & GL_DEPTH_BUFFER_BIT) - { - gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE); - context_invalidate_state(context, STATE_DEPTH_STENCIL); - } - if (gl_mask & GL_STENCIL_BUFFER_BIT) - { - if (gl_info->supported[EXT_STENCIL_TWO_SIDE]) - gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT); - gl_info->gl_ops.gl.p_glStencilMask(~0U); - context_invalidate_state(context, STATE_DEPTH_STENCIL); - } - - gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST); - context_invalidate_state(context, STATE_RASTERIZER); - - gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, - dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST); - checkGLcall("glBlitFramebuffer()"); -} - static void wined3d_texture_evict_sysmem(struct wined3d_texture *texture) { struct wined3d_texture_sub_resource *sub_resource; @@ -694,7 +158,7 @@ void wined3d_texture_validate_location(struct wined3d_texture *texture, TRACE("New locations flags are %s.\n", wined3d_debug_location(sub_resource->locations)); }
-static void wined3d_texture_set_dirty(struct wined3d_texture *texture) +void wined3d_texture_set_dirty(struct wined3d_texture *texture) { texture->flags &= ~(WINED3D_TEXTURE_RGB_VALID | WINED3D_TEXTURE_SRGB_VALID); } @@ -873,7 +337,7 @@ BOOL wined3d_texture_load_location(struct wined3d_texture *texture, return ret; }
-static void wined3d_texture_get_memory(struct wined3d_texture *texture, unsigned int sub_resource_idx, +void wined3d_texture_get_memory(struct wined3d_texture *texture, unsigned int sub_resource_idx, struct wined3d_context *context, struct wined3d_bo_address *data) { struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx]; @@ -909,21 +373,6 @@ static void wined3d_texture_get_memory(struct wined3d_texture *texture, unsigned data->buffer_object = 0; }
-/* Context activation is done by the caller. */ -static void wined3d_texture_remove_buffer_object(struct wined3d_texture *texture, - unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl) -{ - struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx]; - struct wined3d_bo_gl *bo_gl = wined3d_bo_gl(sub_resource->bo); - - TRACE("texture %p, sub_resource_idx %u, context_gl %p.\n", texture, sub_resource_idx, context_gl); - - wined3d_context_gl_destroy_bo(context_gl, bo_gl); - wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_BUFFER); - sub_resource->bo = NULL; - free(bo_gl); -} - static void wined3d_texture_unload_location(struct wined3d_texture *texture, struct wined3d_context *context, unsigned int location) { @@ -956,127 +405,13 @@ static void wined3d_texture_update_map_binding(struct wined3d_texture *texture) texture->update_map_binding = 0; }
-static void wined3d_texture_set_map_binding(struct wined3d_texture *texture, DWORD map_binding) +void wined3d_texture_set_map_binding(struct wined3d_texture *texture, DWORD map_binding) { texture->update_map_binding = map_binding; if (!texture->resource.map_count) wined3d_texture_update_map_binding(texture); }
-/* A GL context is provided by the caller */ -static void gltexture_delete(struct wined3d_device *device, const struct wined3d_gl_info *gl_info, - struct gl_texture *tex) -{ - context_gl_resource_released(device, tex->name, FALSE); - gl_info->gl_ops.gl.p_glDeleteTextures(1, &tex->name); - tex->name = 0; -} - -/* Context activation is done by the caller. */ -/* The caller is responsible for binding the correct texture. */ -static void wined3d_texture_gl_allocate_mutable_storage(struct wined3d_texture_gl *texture_gl, - GLenum gl_internal_format, const struct wined3d_format_gl *format, - const struct wined3d_gl_info *gl_info) -{ - unsigned int level, level_count, layer, layer_count; - GLsizei width, height, depth; - GLenum target; - - level_count = texture_gl->t.level_count; - if (texture_gl->target == GL_TEXTURE_1D_ARRAY || texture_gl->target == GL_TEXTURE_2D_ARRAY) - layer_count = 1; - else - layer_count = texture_gl->t.layer_count; - - GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0)); - checkGLcall("glBindBuffer"); - - for (layer = 0; layer < layer_count; ++layer) - { - target = wined3d_texture_gl_get_sub_resource_target(texture_gl, layer * level_count); - - for (level = 0; level < level_count; ++level) - { - width = wined3d_texture_get_level_width(&texture_gl->t, level); - height = wined3d_texture_get_level_height(&texture_gl->t, level); - if (texture_gl->t.resource.format_attrs & WINED3D_FORMAT_ATTR_HEIGHT_SCALE) - { - height *= format->f.height_scale.numerator; - height /= format->f.height_scale.denominator; - } - - TRACE("texture_gl %p, layer %u, level %u, target %#x, width %u, height %u.\n", - texture_gl, layer, level, target, width, height); - - if (target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY) - { - depth = wined3d_texture_get_level_depth(&texture_gl->t, level); - GL_EXTCALL(glTexImage3D(target, level, gl_internal_format, width, height, - target == GL_TEXTURE_2D_ARRAY ? texture_gl->t.layer_count : depth, 0, - format->format, format->type, NULL)); - checkGLcall("glTexImage3D"); - } - else if (target == GL_TEXTURE_1D) - { - gl_info->gl_ops.gl.p_glTexImage1D(target, level, gl_internal_format, - width, 0, format->format, format->type, NULL); - } - else - { - gl_info->gl_ops.gl.p_glTexImage2D(target, level, gl_internal_format, width, - target == GL_TEXTURE_1D_ARRAY ? texture_gl->t.layer_count : height, 0, - format->format, format->type, NULL); - checkGLcall("glTexImage2D"); - } - } - } -} - -/* Context activation is done by the caller. */ -/* The caller is responsible for binding the correct texture. */ -static void wined3d_texture_gl_allocate_immutable_storage(struct wined3d_texture_gl *texture_gl, - GLenum gl_internal_format, const struct wined3d_gl_info *gl_info) -{ - unsigned int samples = wined3d_resource_get_sample_count(&texture_gl->t.resource); - GLboolean standard_pattern = texture_gl->t.resource.multisample_type != WINED3D_MULTISAMPLE_NON_MASKABLE - && texture_gl->t.resource.multisample_quality == WINED3D_STANDARD_MULTISAMPLE_PATTERN; - GLsizei height = wined3d_texture_get_level_height(&texture_gl->t, 0); - GLsizei width = wined3d_texture_get_level_width(&texture_gl->t, 0); - - switch (texture_gl->target) - { - case GL_TEXTURE_3D: - GL_EXTCALL(glTexStorage3D(texture_gl->target, texture_gl->t.level_count, - gl_internal_format, width, height, wined3d_texture_get_level_depth(&texture_gl->t, 0))); - break; - case GL_TEXTURE_2D_ARRAY: - GL_EXTCALL(glTexStorage3D(texture_gl->target, texture_gl->t.level_count, - gl_internal_format, width, height, texture_gl->t.layer_count)); - break; - case GL_TEXTURE_2D_MULTISAMPLE: - GL_EXTCALL(glTexStorage2DMultisample(texture_gl->target, samples, - gl_internal_format, width, height, standard_pattern)); - break; - case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: - GL_EXTCALL(glTexStorage3DMultisample(texture_gl->target, samples, - gl_internal_format, width, height, texture_gl->t.layer_count, standard_pattern)); - break; - case GL_TEXTURE_1D_ARRAY: - GL_EXTCALL(glTexStorage2D(texture_gl->target, texture_gl->t.level_count, - gl_internal_format, width, texture_gl->t.layer_count)); - break; - case GL_TEXTURE_1D: - GL_EXTCALL(glTexStorage1D(texture_gl->target, texture_gl->t.level_count, gl_internal_format, width)); - break; - default: - GL_EXTCALL(glTexStorage2D(texture_gl->target, texture_gl->t.level_count, - gl_internal_format, width, height)); - break; - } - - checkGLcall("allocate immutable storage"); -} - static void wined3d_texture_dirty_region_add(struct wined3d_texture *texture, unsigned int layer, const struct wined3d_box *box) { @@ -1266,298 +601,51 @@ void wined3d_texture_set_swapchain(struct wined3d_texture *texture, struct wined wined3d_resource_update_draw_binding(&texture->resource); }
-void wined3d_gl_texture_swizzle_from_color_fixup(GLint swizzle[4], struct color_fixup_desc fixup) -{ - static const GLenum swizzle_source[] = - { - GL_ZERO, /* CHANNEL_SOURCE_ZERO */ - GL_ONE, /* CHANNEL_SOURCE_ONE */ - GL_RED, /* CHANNEL_SOURCE_X */ - GL_GREEN, /* CHANNEL_SOURCE_Y */ - GL_BLUE, /* CHANNEL_SOURCE_Z */ - GL_ALPHA, /* CHANNEL_SOURCE_W */ - }; - - swizzle[0] = swizzle_source[fixup.x_source]; - swizzle[1] = swizzle_source[fixup.y_source]; - swizzle[2] = swizzle_source[fixup.z_source]; - swizzle[3] = swizzle_source[fixup.w_source]; -} - -/* Context activation is done by the caller. */ -void wined3d_texture_gl_bind(struct wined3d_texture_gl *texture_gl, - struct wined3d_context_gl *context_gl, BOOL srgb) +ULONG CDECL wined3d_texture_incref(struct wined3d_texture *texture) { - const struct wined3d_format *format = texture_gl->t.resource.format; - const struct wined3d_gl_info *gl_info = context_gl->gl_info; - const struct color_fixup_desc fixup = format->color_fixup; - struct gl_texture *gl_tex; - GLenum target; + unsigned int refcount;
- TRACE("texture_gl %p, context_gl %p, srgb %#x.\n", texture_gl, context_gl, srgb); + TRACE("texture %p, swapchain %p.\n", texture, texture->swapchain);
- if (!needs_separate_srgb_gl_texture(&context_gl->c, &texture_gl->t)) - srgb = FALSE; + refcount = InterlockedIncrement(&texture->resource.ref); + TRACE("%p increasing refcount to %u.\n", texture, refcount);
- /* sRGB mode cache for preload() calls outside drawprim. */ - if (srgb) - texture_gl->t.flags |= WINED3D_TEXTURE_IS_SRGB; - else - texture_gl->t.flags &= ~WINED3D_TEXTURE_IS_SRGB; + return refcount; +}
- gl_tex = wined3d_texture_gl_get_gl_texture(texture_gl, srgb); - target = texture_gl->target; +static void wined3d_texture_destroy_object(void *object) +{ + struct wined3d_texture *texture = object; + struct wined3d_resource *resource; + struct wined3d_dc_info *dc_info; + unsigned int sub_count; + unsigned int i;
- if (gl_tex->name) - { - wined3d_context_gl_bind_texture(context_gl, target, gl_tex->name); - return; - } + TRACE("texture %p.\n", texture);
- gl_info->gl_ops.gl.p_glGenTextures(1, &gl_tex->name); - checkGLcall("glGenTextures"); - TRACE("Generated texture %d.\n", gl_tex->name); + resource = &texture->resource; + sub_count = texture->level_count * texture->layer_count;
- if (!gl_tex->name) + if ((dc_info = texture->dc_info)) { - ERR("Failed to generate a texture name.\n"); - return; - } - - /* Initialise the state of the texture object to the OpenGL defaults, not - * the wined3d defaults. */ - gl_tex->sampler_desc.address_u = WINED3D_TADDRESS_WRAP; - gl_tex->sampler_desc.address_v = WINED3D_TADDRESS_WRAP; - gl_tex->sampler_desc.address_w = WINED3D_TADDRESS_WRAP; - memset(gl_tex->sampler_desc.border_color, 0, sizeof(gl_tex->sampler_desc.border_color)); - gl_tex->sampler_desc.mag_filter = WINED3D_TEXF_LINEAR; - gl_tex->sampler_desc.min_filter = WINED3D_TEXF_POINT; /* GL_NEAREST_MIPMAP_LINEAR */ - gl_tex->sampler_desc.mip_filter = WINED3D_TEXF_LINEAR; /* GL_NEAREST_MIPMAP_LINEAR */ - gl_tex->sampler_desc.lod_bias = 0.0f; - gl_tex->sampler_desc.min_lod = -1000.0f; - gl_tex->sampler_desc.max_lod = 1000.0f; - gl_tex->sampler_desc.max_anisotropy = 1; - gl_tex->sampler_desc.compare = FALSE; - gl_tex->sampler_desc.comparison_func = WINED3D_CMP_LESSEQUAL; - if (gl_info->supported[EXT_TEXTURE_SRGB_DECODE]) - gl_tex->sampler_desc.srgb_decode = TRUE; - else - gl_tex->sampler_desc.srgb_decode = srgb; - gl_tex->sampler_desc.mip_base_level = 0; - wined3d_texture_set_dirty(&texture_gl->t); - - wined3d_context_gl_bind_texture(context_gl, target, gl_tex->name); - - /* For a new texture we have to set the texture levels after binding the - * texture. */ - TRACE("Setting GL_TEXTURE_MAX_LEVEL to %u.\n", texture_gl->t.level_count - 1); - gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture_gl->t.level_count - 1); - checkGLcall("glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture->level_count)"); + for (i = 0; i < sub_count; ++i) + { + if (dc_info[i].dc) + { + struct wined3d_texture_idx texture_idx = {texture, i};
- if (target == GL_TEXTURE_CUBE_MAP_ARB) - { - /* Cubemaps are always set to clamp, regardless of the sampler state. */ - gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + wined3d_texture_destroy_dc(&texture_idx); + } + } + free(dc_info); }
- if (texture_gl->t.flags & WINED3D_TEXTURE_COND_NP2 && target != GL_TEXTURE_2D_MULTISAMPLE - && target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY) + if (texture->overlay_info) { - /* Conditional non power of two textures use a different clamping - * default. If we're using the GL_WINE_normalized_texrect partial - * driver emulation, we're dealing with a GL_TEXTURE_2D texture which - * has the address mode set to repeat - something that prevents us - * from hitting the accelerated codepath. Thus manually set the GL - * state. The same applies to filtering. Even if the texture has only - * one mip level, the default LINEAR_MIPMAP_LINEAR filter causes a SW - * fallback on macos. */ - gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - checkGLcall("glTexParameteri"); - gl_tex->sampler_desc.address_u = WINED3D_TADDRESS_CLAMP; - gl_tex->sampler_desc.address_v = WINED3D_TADDRESS_CLAMP; - gl_tex->sampler_desc.mag_filter = WINED3D_TEXF_POINT; - gl_tex->sampler_desc.min_filter = WINED3D_TEXF_POINT; - gl_tex->sampler_desc.mip_filter = WINED3D_TEXF_NONE; - } - - if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT] && gl_info->supported[ARB_DEPTH_TEXTURE]) - { - gl_info->gl_ops.gl.p_glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY); - checkGLcall("glTexParameteri(GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY)"); - } - - if (!is_identity_fixup(fixup) && can_use_texture_swizzle(context_gl->c.d3d_info, format)) - { - GLint swizzle[4]; - - wined3d_gl_texture_swizzle_from_color_fixup(swizzle, fixup); - gl_info->gl_ops.gl.p_glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle); - checkGLcall("set format swizzle"); - } -} - -/* Context activation is done by the caller. */ -void wined3d_texture_gl_bind_and_dirtify(struct wined3d_texture_gl *texture_gl, - struct wined3d_context_gl *context_gl, BOOL srgb) -{ - /* FIXME: Ideally we'd only do this when touching a binding that's used by - * a shader. */ - context_invalidate_compute_state(&context_gl->c, STATE_COMPUTE_SHADER_RESOURCE_BINDING); - context_invalidate_state(&context_gl->c, STATE_GRAPHICS_SHADER_RESOURCE_BINDING); - - wined3d_texture_gl_bind(texture_gl, context_gl, srgb); -} - -/* Context activation is done by the caller (state handler). */ -/* This function relies on the correct texture being bound and loaded. */ -void wined3d_texture_gl_apply_sampler_desc(struct wined3d_texture_gl *texture_gl, - const struct wined3d_sampler_desc *sampler_desc, const struct wined3d_context_gl *context_gl) -{ - const struct wined3d_gl_info *gl_info = context_gl->gl_info; - GLenum target = texture_gl->target; - struct gl_texture *gl_tex; - DWORD state; - - TRACE("texture_gl %p, sampler_desc %p, context_gl %p.\n", texture_gl, sampler_desc, context_gl); - - gl_tex = wined3d_texture_gl_get_gl_texture(texture_gl, texture_gl->t.flags & WINED3D_TEXTURE_IS_SRGB); - - state = sampler_desc->address_u; - if (state != gl_tex->sampler_desc.address_u) - { - gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S, - gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]); - gl_tex->sampler_desc.address_u = state; - } - - state = sampler_desc->address_v; - if (state != gl_tex->sampler_desc.address_v) - { - gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T, - gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]); - gl_tex->sampler_desc.address_v = state; - } - - state = sampler_desc->address_w; - if (state != gl_tex->sampler_desc.address_w) - { - gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_R, - gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]); - gl_tex->sampler_desc.address_w = state; - } - - if (memcmp(gl_tex->sampler_desc.border_color, sampler_desc->border_color, - sizeof(gl_tex->sampler_desc.border_color))) - { - gl_info->gl_ops.gl.p_glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, &sampler_desc->border_color[0]); - memcpy(gl_tex->sampler_desc.border_color, sampler_desc->border_color, - sizeof(gl_tex->sampler_desc.border_color)); - } - - state = sampler_desc->mag_filter; - if (state != gl_tex->sampler_desc.mag_filter) - { - gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(state)); - gl_tex->sampler_desc.mag_filter = state; - } - - if (sampler_desc->min_filter != gl_tex->sampler_desc.min_filter - || sampler_desc->mip_filter != gl_tex->sampler_desc.mip_filter) - { - gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MIN_FILTER, - wined3d_gl_min_mip_filter(sampler_desc->min_filter, sampler_desc->mip_filter)); - gl_tex->sampler_desc.min_filter = sampler_desc->min_filter; - gl_tex->sampler_desc.mip_filter = sampler_desc->mip_filter; - } - - state = sampler_desc->max_anisotropy; - if (state != gl_tex->sampler_desc.max_anisotropy) - { - if (gl_info->supported[ARB_TEXTURE_FILTER_ANISOTROPIC]) - gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY, state); - else - WARN("Anisotropic filtering not supported.\n"); - gl_tex->sampler_desc.max_anisotropy = state; - } - - if (!sampler_desc->srgb_decode != !gl_tex->sampler_desc.srgb_decode - && (context_gl->c.d3d_info->wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL) - && gl_info->supported[EXT_TEXTURE_SRGB_DECODE]) - { - gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_SRGB_DECODE_EXT, - sampler_desc->srgb_decode ? GL_DECODE_EXT : GL_SKIP_DECODE_EXT); - gl_tex->sampler_desc.srgb_decode = sampler_desc->srgb_decode; - } - - if (!sampler_desc->compare != !gl_tex->sampler_desc.compare) - { - if (sampler_desc->compare) - gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); - else - gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); - gl_tex->sampler_desc.compare = sampler_desc->compare; - } - - checkGLcall("Texture parameter application"); - - if (gl_info->supported[EXT_TEXTURE_LOD_BIAS]) - { - gl_info->gl_ops.gl.p_glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, - GL_TEXTURE_LOD_BIAS_EXT, sampler_desc->lod_bias); - checkGLcall("glTexEnvf(GL_TEXTURE_LOD_BIAS_EXT, ...)"); - } -} - -ULONG CDECL wined3d_texture_incref(struct wined3d_texture *texture) -{ - unsigned int refcount; - - TRACE("texture %p, swapchain %p.\n", texture, texture->swapchain); - - refcount = InterlockedIncrement(&texture->resource.ref); - TRACE("%p increasing refcount to %u.\n", texture, refcount); - - return refcount; -} - -static void wined3d_texture_destroy_object(void *object) -{ - struct wined3d_texture *texture = object; - struct wined3d_resource *resource; - struct wined3d_dc_info *dc_info; - unsigned int sub_count; - unsigned int i; - - TRACE("texture %p.\n", texture); - - resource = &texture->resource; - sub_count = texture->level_count * texture->layer_count; - - if ((dc_info = texture->dc_info)) - { - for (i = 0; i < sub_count; ++i) - { - if (dc_info[i].dc) - { - struct wined3d_texture_idx texture_idx = {texture, i}; - - wined3d_texture_destroy_dc(&texture_idx); - } - } - free(dc_info); - } - - if (texture->overlay_info) - { - for (i = 0; i < sub_count; ++i) - { - struct wined3d_overlay_info *info = &texture->overlay_info[i]; - struct wined3d_overlay_info *overlay, *cur; + for (i = 0; i < sub_count; ++i) + { + struct wined3d_overlay_info *info = &texture->overlay_info[i]; + struct wined3d_overlay_info *overlay, *cur;
list_remove(&info->entry); LIST_FOR_EACH_ENTRY_SAFE(overlay, cur, &info->overlays, struct wined3d_overlay_info, entry) @@ -1781,90 +869,6 @@ HRESULT CDECL wined3d_texture_set_color_key(struct wined3d_texture *texture, return WINED3D_OK; }
-/* In D3D the depth stencil dimensions have to be greater than or equal to the - * render target dimensions. With FBOs, the dimensions have to be an exact match. */ -/* TODO: We should synchronize the renderbuffer's content with the texture's content. */ -/* Context activation is done by the caller. */ -void wined3d_texture_gl_set_compatible_renderbuffer(struct wined3d_texture_gl *texture_gl, - struct wined3d_context_gl *context_gl, unsigned int level, const struct wined3d_rendertarget_info *rt) -{ - const struct wined3d_gl_info *gl_info = context_gl->gl_info; - struct wined3d_renderbuffer_entry *entry; - unsigned int src_width, src_height; - unsigned int width, height; - GLuint renderbuffer = 0; - - if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]) - return; - - if (rt && rt->resource->format->id != WINED3DFMT_NULL) - { - struct wined3d_texture *rt_texture; - unsigned int rt_level; - - if (rt->resource->type == WINED3D_RTYPE_BUFFER) - { - FIXME("Unsupported resource type %s.\n", debug_d3dresourcetype(rt->resource->type)); - return; - } - rt_texture = wined3d_texture_from_resource(rt->resource); - rt_level = rt->sub_resource_idx % rt_texture->level_count; - - width = wined3d_texture_get_level_width(rt_texture, rt_level); - height = wined3d_texture_get_level_height(rt_texture, rt_level); - } - else - { - width = wined3d_texture_get_level_width(&texture_gl->t, level); - height = wined3d_texture_get_level_height(&texture_gl->t, level); - } - - src_width = wined3d_texture_get_level_width(&texture_gl->t, level); - src_height = wined3d_texture_get_level_height(&texture_gl->t, level); - - /* A depth stencil smaller than the render target is not valid */ - if (width > src_width || height > src_height) - return; - - /* Remove any renderbuffer set if the sizes match */ - if (width == src_width && height == src_height) - { - texture_gl->current_renderbuffer = NULL; - return; - } - - /* Look if we've already got a renderbuffer of the correct dimensions */ - LIST_FOR_EACH_ENTRY(entry, &texture_gl->renderbuffers, struct wined3d_renderbuffer_entry, entry) - { - if (entry->width == width && entry->height == height) - { - renderbuffer = entry->id; - texture_gl->current_renderbuffer = entry; - break; - } - } - - if (!renderbuffer) - { - const struct wined3d_format_gl *format_gl; - - format_gl = wined3d_format_gl(texture_gl->t.resource.format); - gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer); - gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); - gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, format_gl->internal, width, height); - - entry = malloc(sizeof(*entry)); - entry->width = width; - entry->height = height; - entry->id = renderbuffer; - list_add_head(&texture_gl->renderbuffers, &entry->entry); - - texture_gl->current_renderbuffer = entry; - } - - checkGLcall("set compatible renderbuffer"); -} - HRESULT CDECL wined3d_texture_update_desc(struct wined3d_texture *texture, unsigned int sub_resource_idx, void *mem, unsigned int pitch) { @@ -1983,33 +987,6 @@ HRESULT CDECL wined3d_texture_update_desc(struct wined3d_texture *texture, return WINED3D_OK; }
-/* Context activation is done by the caller. */ -static void wined3d_texture_gl_prepare_buffer_object(struct wined3d_texture_gl *texture_gl, - unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl) -{ - struct wined3d_texture_sub_resource *sub_resource; - struct wined3d_bo_gl *bo; - - sub_resource = &texture_gl->t.sub_resources[sub_resource_idx]; - - if (sub_resource->bo) - return; - - if (!(bo = malloc(sizeof(*bo)))) - return; - - if (!wined3d_device_gl_create_bo(wined3d_device_gl(texture_gl->t.resource.device), - context_gl, sub_resource->size, GL_PIXEL_UNPACK_BUFFER, GL_STREAM_DRAW, true, - GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_CLIENT_STORAGE_BIT, bo)) - { - free(bo); - return; - } - - TRACE("Created buffer object %u for texture %p, sub-resource %u.\n", bo->id, texture_gl, sub_resource_idx); - sub_resource->bo = &bo->b; -} - static void wined3d_texture_force_reload(struct wined3d_texture *texture) { unsigned int sub_count = texture->level_count * texture->layer_count; @@ -2025,94 +1002,6 @@ static void wined3d_texture_force_reload(struct wined3d_texture *texture) } }
-/* Context activation is done by the caller. */ -void wined3d_texture_gl_prepare_texture(struct wined3d_texture_gl *texture_gl, - struct wined3d_context_gl *context_gl, BOOL srgb) -{ - DWORD alloc_flag = srgb ? WINED3D_TEXTURE_SRGB_ALLOCATED : WINED3D_TEXTURE_RGB_ALLOCATED; - const struct wined3d_gl_info *gl_info = context_gl->gl_info; - struct wined3d_resource *resource = &texture_gl->t.resource; - const struct wined3d_device *device = resource->device; - const struct wined3d_format *format = resource->format; - const struct wined3d_color_key_conversion *conversion; - const struct wined3d_format_gl *format_gl; - GLenum internal; - - TRACE("texture_gl %p, context_gl %p, srgb %d, format %s.\n", - texture_gl, context_gl, srgb, debug_d3dformat(format->id)); - - if (texture_gl->t.flags & alloc_flag) - return; - - if (resource->format_caps & WINED3D_FORMAT_CAP_DECOMPRESS) - { - TRACE("WINED3D_FORMAT_CAP_DECOMPRESS set.\n"); - texture_gl->t.flags |= WINED3D_TEXTURE_CONVERTED; - format = wined3d_resource_get_decompress_format(resource); - } - else if (format->conv_byte_count) - { - texture_gl->t.flags |= WINED3D_TEXTURE_CONVERTED; - } - else if ((conversion = wined3d_format_get_color_key_conversion(&texture_gl->t, TRUE))) - { - texture_gl->t.flags |= WINED3D_TEXTURE_CONVERTED; - format = wined3d_get_format(device->adapter, conversion->dst_format, resource->bind_flags); - TRACE("Using format %s for color key conversion.\n", debug_d3dformat(format->id)); - } - format_gl = wined3d_format_gl(format); - - wined3d_texture_gl_bind_and_dirtify(texture_gl, context_gl, srgb); - - internal = wined3d_gl_get_internal_format(resource, format_gl, srgb); - if (!internal) - FIXME("No GL internal format for format %s.\n", debug_d3dformat(format->id)); - - TRACE("internal %#x, format %#x, type %#x.\n", internal, format_gl->format, format_gl->type); - - if (wined3d_texture_use_immutable_storage(&texture_gl->t, gl_info)) - wined3d_texture_gl_allocate_immutable_storage(texture_gl, internal, gl_info); - else - wined3d_texture_gl_allocate_mutable_storage(texture_gl, internal, format_gl, gl_info); - texture_gl->t.flags |= alloc_flag; -} - -static void wined3d_texture_gl_prepare_rb(struct wined3d_texture_gl *texture_gl, - const struct wined3d_gl_info *gl_info, BOOL multisample) -{ - const struct wined3d_format_gl *format_gl; - - format_gl = wined3d_format_gl(texture_gl->t.resource.format); - if (multisample) - { - DWORD samples; - - if (texture_gl->rb_multisample) - return; - - samples = wined3d_resource_get_sample_count(&texture_gl->t.resource); - - gl_info->fbo_ops.glGenRenderbuffers(1, &texture_gl->rb_multisample); - gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, texture_gl->rb_multisample); - gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, - format_gl->internal, texture_gl->t.resource.width, texture_gl->t.resource.height); - checkGLcall("glRenderbufferStorageMultisample()"); - TRACE("Created multisample rb %u.\n", texture_gl->rb_multisample); - } - else - { - if (texture_gl->rb_resolved) - return; - - gl_info->fbo_ops.glGenRenderbuffers(1, &texture_gl->rb_resolved); - gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, texture_gl->rb_resolved); - gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, format_gl->internal, - texture_gl->t.resource.width, texture_gl->t.resource.height); - checkGLcall("glRenderbufferStorage()"); - TRACE("Created resolved rb %u.\n", texture_gl->rb_resolved); - } -} - BOOL wined3d_texture_prepare_location(struct wined3d_texture *texture, unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location) { @@ -2152,141 +1041,6 @@ HRESULT CDECL wined3d_texture_add_dirty_region(struct wined3d_texture *texture, return WINED3D_OK; }
-static void wined3d_texture_gl_upload_bo(const struct wined3d_format *src_format, GLenum target, - unsigned int level, unsigned int src_row_pitch, unsigned int src_slice_pitch, - unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, unsigned int update_w, - unsigned int update_h, unsigned int update_d, const BYTE *addr, BOOL srgb, - struct wined3d_texture *dst_texture, const struct wined3d_gl_info *gl_info) -{ - const struct wined3d_format_gl *format_gl = wined3d_format_gl(src_format); - - if (src_format->attrs & WINED3D_FORMAT_ATTR_COMPRESSED) - { - GLenum internal = wined3d_gl_get_internal_format(&dst_texture->resource, format_gl, srgb); - unsigned int dst_row_pitch, dst_slice_pitch; - - wined3d_format_calculate_pitch(src_format, 1, update_w, update_h, &dst_row_pitch, &dst_slice_pitch); - - TRACE("Uploading compressed data, target %#x, level %u, x %u, y %u, z %u, " - "w %u, h %u, d %u, format %#x, image_size %#x, addr %p.\n", - target, level, dst_x, dst_y, dst_z, update_w, update_h, - update_d, internal, dst_slice_pitch, addr); - - if (target == GL_TEXTURE_1D) - { - GL_EXTCALL(glCompressedTexSubImage1D(target, level, dst_x, - update_w, internal, dst_row_pitch, addr)); - } - else - { - unsigned int row, y, slice, slice_count = 1, row_count = 1; - - /* glCompressedTexSubImage2D() ignores pixel store state, so we - * can't use the unpack row length like for glTexSubImage2D. */ - if (dst_row_pitch != src_row_pitch) - { - row_count = (update_h + src_format->block_height - 1) / src_format->block_height; - update_h = src_format->block_height; - wined3d_format_calculate_pitch(src_format, 1, update_w, update_h, - &dst_row_pitch, &dst_slice_pitch); - } - - if (dst_slice_pitch != src_slice_pitch) - { - slice_count = update_d; - update_d = 1; - } - - for (slice = 0; slice < slice_count; ++slice) - { - for (row = 0, y = dst_y; row < row_count; ++row) - { - const BYTE *upload_addr = &addr[slice * src_slice_pitch + row * src_row_pitch]; - - if (target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_3D) - { - GL_EXTCALL(glCompressedTexSubImage3D(target, level, dst_x, y, dst_z + slice, update_w, - update_h, update_d, internal, update_d * dst_slice_pitch, upload_addr)); - } - else - { - GL_EXTCALL(glCompressedTexSubImage2D(target, level, dst_x, y, update_w, - update_h, internal, dst_slice_pitch, upload_addr)); - } - - y += src_format->block_height; - } - } - } - checkGLcall("Upload compressed texture data"); - } - else - { - unsigned int y, y_count, z, z_count; - bool unpacking_rows = false; - - TRACE("Uploading data, target %#x, level %u, x %u, y %u, z %u, " - "w %u, h %u, d %u, format %#x, type %#x, addr %p.\n", - target, level, dst_x, dst_y, dst_z, update_w, update_h, - update_d, format_gl->format, format_gl->type, addr); - - if (src_row_pitch && !(src_row_pitch % src_format->byte_count)) - { - gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_row_pitch / src_format->byte_count); - y_count = 1; - unpacking_rows = true; - } - else - { - y_count = update_h; - update_h = 1; - } - - if (src_slice_pitch && unpacking_rows && !(src_slice_pitch % src_row_pitch)) - { - gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, src_slice_pitch / src_row_pitch); - z_count = 1; - } - else if (src_slice_pitch && !unpacking_rows && !(src_slice_pitch % (update_w * src_format->byte_count))) - { - gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, - src_slice_pitch / (update_w * src_format->byte_count)); - z_count = 1; - } - else - { - z_count = update_d; - update_d = 1; - } - - for (z = 0; z < z_count; ++z) - { - for (y = 0; y < y_count; ++y) - { - const BYTE *upload_addr = &addr[z * src_slice_pitch + y * src_row_pitch]; - if (target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_3D) - { - GL_EXTCALL(glTexSubImage3D(target, level, dst_x, dst_y + y, dst_z + z, update_w, - update_h, update_d, format_gl->format, format_gl->type, upload_addr)); - } - else if (target == GL_TEXTURE_1D) - { - gl_info->gl_ops.gl.p_glTexSubImage1D(target, level, dst_x, - update_w, format_gl->format, format_gl->type, upload_addr); - } - else - { - gl_info->gl_ops.gl.p_glTexSubImage2D(target, level, dst_x, dst_y + y, - update_w, update_h, format_gl->format, format_gl->type, upload_addr); - } - } - } - gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); - checkGLcall("Upload texture data"); - } -} - static const struct d3dfmt_alpha_fixup { enum wined3d_format_id format_id, conv_format_id; @@ -2298,7 +1052,7 @@ formats_src_alpha_fixup[] = {WINED3DFMT_B4G4R4X4_UNORM, WINED3DFMT_B4G4R4A4_UNORM}, };
-static enum wined3d_format_id wined3d_get_alpha_fixup_format(enum wined3d_format_id format_id, +enum wined3d_format_id wined3d_get_alpha_fixup_format(enum wined3d_format_id format_id, const struct wined3d_format *dst_format) { unsigned int i; @@ -2315,7 +1069,7 @@ static enum wined3d_format_id wined3d_get_alpha_fixup_format(enum wined3d_format return WINED3DFMT_UNKNOWN; }
-static void wined3d_fixup_alpha(const struct wined3d_format *format, const uint8_t *src, +void wined3d_fixup_alpha(const struct wined3d_format *format, const uint8_t *src, unsigned int src_row_pitch, uint8_t *dst, unsigned int dst_row_pitch, unsigned int width, unsigned int height) { @@ -2359,4855 +1113,1252 @@ static void wined3d_fixup_alpha(const struct wined3d_format *format, const uint8 } }
-static void wined3d_texture_gl_upload_data(struct wined3d_context *context, - const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *src_format, - const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch, - struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, unsigned int dst_location, - unsigned int dst_x, unsigned int dst_y, unsigned int dst_z) +BOOL wined3d_texture_load_drawable(struct wined3d_texture *texture, + unsigned int sub_resource_idx, struct wined3d_context *context) { - struct wined3d_context_gl *context_gl = wined3d_context_gl(context); - enum wined3d_format_id alpha_fixup_format_id = WINED3DFMT_UNKNOWN; - const struct wined3d_gl_info *gl_info = context_gl->gl_info; - unsigned int update_w = src_box->right - src_box->left; - unsigned int update_h = src_box->bottom - src_box->top; - unsigned int update_d = src_box->back - src_box->front; - struct wined3d_bo_address bo; + struct wined3d_device *device; unsigned int level; - BOOL srgb = FALSE; - BOOL decompress; - GLenum target; - - TRACE("context %p, src_bo_addr %s, src_format %s, src_box %s, src_row_pitch %u, src_slice_pitch %u, " - "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_x %u, dst_y %u, dst_z %u.\n", - context, debug_const_bo_address(src_bo_addr), debug_d3dformat(src_format->id), debug_box(src_box), - src_row_pitch, src_slice_pitch, dst_texture, dst_sub_resource_idx, - wined3d_debug_location(dst_location), dst_x, dst_y, dst_z); - - if (dst_location == WINED3D_LOCATION_TEXTURE_SRGB) - { - srgb = TRUE; - } - else if (dst_location != WINED3D_LOCATION_TEXTURE_RGB) - { - FIXME("Unhandled location %s.\n", wined3d_debug_location(dst_location)); - return; - } - - wined3d_texture_gl_bind_and_dirtify(wined3d_texture_gl(dst_texture), wined3d_context_gl(context), srgb); + RECT r;
- if (dst_texture->sub_resources[dst_sub_resource_idx].map_count) + if (texture->resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL) { - WARN("Uploading a texture that is currently mapped, pinning sysmem.\n"); - dst_texture->resource.pin_sysmem = 1; + DWORD current = texture->sub_resources[sub_resource_idx].locations; + FIXME("Unimplemented copy from %s for depth/stencil buffers.\n", + wined3d_debug_location(current)); + return FALSE; }
- if (src_format->attrs & WINED3D_FORMAT_ATTR_HEIGHT_SCALE) + if (wined3d_resource_is_offscreen(&texture->resource)) { - update_h *= src_format->height_scale.numerator; - update_h /= src_format->height_scale.denominator; + ERR("Trying to load offscreen texture into WINED3D_LOCATION_DRAWABLE.\n"); + return FALSE; }
- target = wined3d_texture_gl_get_sub_resource_target(wined3d_texture_gl(dst_texture), dst_sub_resource_idx); - level = dst_sub_resource_idx % dst_texture->level_count; - - switch (target) - { - case GL_TEXTURE_1D_ARRAY: - dst_y = dst_sub_resource_idx / dst_texture->level_count; - update_h = 1; - break; - case GL_TEXTURE_2D_ARRAY: - dst_z = dst_sub_resource_idx / dst_texture->level_count; - update_d = 1; - break; - case GL_TEXTURE_2D_MULTISAMPLE: - case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: - FIXME("Not supported for multisample textures.\n"); - return; - } + device = texture->resource.device; + level = sub_resource_idx % texture->level_count; + SetRect(&r, 0, 0, wined3d_texture_get_level_width(texture, level), + wined3d_texture_get_level_height(texture, level)); + wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB); + device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_COLOR_BLIT, context, + texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &r, + texture, sub_resource_idx, WINED3D_LOCATION_DRAWABLE, &r, + NULL, WINED3D_TEXF_POINT, NULL);
- bo.buffer_object = src_bo_addr->buffer_object; - bo.addr = (BYTE *)src_bo_addr->addr + src_box->front * src_slice_pitch; - if (dst_texture->resource.format_attrs & WINED3D_FORMAT_ATTR_BLOCKS) - { - bo.addr += (src_box->top / src_format->block_height) * src_row_pitch; - bo.addr += (src_box->left / src_format->block_width) * src_format->block_byte_count; - } - else - { - bo.addr += src_box->top * src_row_pitch; - bo.addr += src_box->left * src_format->byte_count; - } + return TRUE; +}
- decompress = (dst_texture->resource.format_caps & WINED3D_FORMAT_CAP_DECOMPRESS) - || (src_format->decompress && src_format->id != dst_texture->resource.format->id); +struct wined3d_texture * __cdecl wined3d_texture_from_resource(struct wined3d_resource *resource) +{ + return texture_from_resource(resource); +}
- if (src_format->upload || decompress - || (alpha_fixup_format_id = wined3d_get_alpha_fixup_format(src_format->id, - dst_texture->resource.format)) != WINED3DFMT_UNKNOWN) - { - const struct wined3d_format *compressed_format = src_format; - unsigned int dst_row_pitch, dst_slice_pitch; - struct wined3d_format_gl f; - void *converted_mem; - unsigned int z; - BYTE *src_mem; - - if (decompress) - { - src_format = wined3d_resource_get_decompress_format(&dst_texture->resource); - } - else if (alpha_fixup_format_id != WINED3DFMT_UNKNOWN) - { - src_format = wined3d_get_format(context->device->adapter, alpha_fixup_format_id, 0); - assert(!!src_format); - } - else - { - if (dst_texture->resource.format_attrs & WINED3D_FORMAT_ATTR_BLOCKS) - ERR("Converting a block-based format.\n"); +static ULONG texture_resource_incref(struct wined3d_resource *resource) +{ + return wined3d_texture_incref(texture_from_resource(resource)); +}
- f = *wined3d_format_gl(src_format); - f.f.byte_count = src_format->conv_byte_count; - src_format = &f.f; - } +static ULONG texture_resource_decref(struct wined3d_resource *resource) +{ + return wined3d_texture_decref(texture_from_resource(resource)); +}
- wined3d_format_calculate_pitch(src_format, 1, update_w, update_h, &dst_row_pitch, &dst_slice_pitch); +static void texture_resource_preload(struct wined3d_resource *resource) +{ + struct wined3d_texture *texture = texture_from_resource(resource); + struct wined3d_context *context;
- if (!(converted_mem = malloc(dst_slice_pitch))) - { - ERR("Failed to allocate upload buffer.\n"); - return; - } + context = context_acquire(resource->device, NULL, 0); + wined3d_texture_load(texture, context, texture->flags & WINED3D_TEXTURE_IS_SRGB); + context_release(context); +}
- src_mem = wined3d_context_gl_map_bo_address(context_gl, &bo, src_slice_pitch * update_d, WINED3D_MAP_READ); +static void texture_resource_unload(struct wined3d_resource *resource) +{ + struct wined3d_texture *texture = texture_from_resource(resource); + struct wined3d_device *device = resource->device; + unsigned int location = resource->map_binding; + struct wined3d_context *context; + unsigned int sub_count, i;
- GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0)); - checkGLcall("glBindBuffer"); + TRACE("resource %p.\n", resource);
- for (z = 0; z < update_d; ++z, src_mem += src_slice_pitch) - { - if (decompress) - compressed_format->decompress(src_mem, converted_mem, src_row_pitch, src_slice_pitch, - dst_row_pitch, dst_slice_pitch, update_w, update_h, 1); - else if (alpha_fixup_format_id != WINED3DFMT_UNKNOWN) - wined3d_fixup_alpha(src_format, src_mem, src_row_pitch, converted_mem, dst_row_pitch, - update_w, update_h); - else - src_format->upload(src_mem, converted_mem, src_row_pitch, src_slice_pitch, - dst_row_pitch, dst_slice_pitch, update_w, update_h, 1); + /* D3D is not initialised, so no GPU locations should currently exist. + * Moreover, we may not be able to acquire a valid context. */ + if (!device->d3d_initialized) + return;
- wined3d_texture_gl_upload_bo(src_format, target, level, dst_row_pitch, dst_slice_pitch, dst_x, - dst_y, dst_z + z, update_w, update_h, 1, converted_mem, srgb, dst_texture, gl_info); - } + context = context_acquire(device, NULL, 0);
- wined3d_context_gl_unmap_bo_address(context_gl, &bo, 0, NULL); - free(converted_mem); - } - else - { - const uint8_t *offset = bo.addr; + if (location == WINED3D_LOCATION_BUFFER) + location = WINED3D_LOCATION_SYSMEM;
- if (bo.buffer_object) + sub_count = texture->level_count * texture->layer_count; + for (i = 0; i < sub_count; ++i) + { + if (resource->access & WINED3D_RESOURCE_ACCESS_CPU + && wined3d_texture_load_location(texture, i, context, location)) { - GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, wined3d_bo_gl(bo.buffer_object)->id)); - checkGLcall("glBindBuffer"); - offset += bo.buffer_object->buffer_offset; + wined3d_texture_invalidate_location(texture, i, ~location); } else { - GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0)); - checkGLcall("glBindBuffer"); + if (resource->access & WINED3D_RESOURCE_ACCESS_CPU) + ERR("Discarding %s %p sub-resource %u with resource access %s.\n", + debug_d3dresourcetype(resource->type), resource, i, + wined3d_debug_resource_access(resource->access)); + wined3d_texture_validate_location(texture, i, WINED3D_LOCATION_DISCARDED); + wined3d_texture_invalidate_location(texture, i, ~WINED3D_LOCATION_DISCARDED); } + }
- wined3d_texture_gl_upload_bo(src_format, target, level, src_row_pitch, src_slice_pitch, dst_x, - dst_y, dst_z, update_w, update_h, update_d, offset, srgb, dst_texture, gl_info); + wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_BUFFER); + wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_TEXTURE_RGB); + wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_TEXTURE_SRGB); + wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_RB_MULTISAMPLE); + wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_RB_RESOLVED);
- if (bo.buffer_object) - { - GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0)); - wined3d_context_gl_reference_bo(context_gl, wined3d_bo_gl(bo.buffer_object)); - checkGLcall("glBindBuffer"); - } - } + context_release(context);
- if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE) - { - struct wined3d_device *device = dst_texture->resource.device; - unsigned int i; + wined3d_texture_force_reload(texture);
- for (i = 0; i < device->context_count; ++i) - { - wined3d_context_gl_texture_update(wined3d_context_gl(device->contexts[i]), wined3d_texture_gl(dst_texture)); - } - } + if (texture->resource.bind_count && (texture->resource.bind_flags & WINED3D_BIND_SHADER_RESOURCE)) + device_invalidate_state(device, STATE_GRAPHICS_SHADER_RESOURCE_BINDING); + + wined3d_texture_set_dirty(texture); + + resource_unload(&texture->resource); }
-static void wined3d_texture_gl_download_data_slow_path(struct wined3d_texture_gl *texture_gl, - unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl, const struct wined3d_bo_address *data) +static unsigned int texture_resource_get_sub_resource_count(struct wined3d_resource *resource) { - struct wined3d_bo_gl *bo = wined3d_bo_gl(data->buffer_object); - const struct wined3d_gl_info *gl_info = context_gl->gl_info; - struct wined3d_texture_sub_resource *sub_resource; - unsigned int dst_row_pitch, dst_slice_pitch; - unsigned int src_row_pitch, src_slice_pitch; - const struct wined3d_format_gl *format_gl; - BYTE *temporary_mem = NULL; - unsigned int level; - GLenum target; - void *mem; - - format_gl = wined3d_format_gl(texture_gl->t.resource.format); + const struct wined3d_texture *texture = texture_from_resource(resource);
- /* Only support read back of converted P8 textures. */ - if (texture_gl->t.flags & WINED3D_TEXTURE_CONVERTED && format_gl->f.id != WINED3DFMT_P8_UINT - && !format_gl->f.download) - { - ERR("Trying to read back converted texture %p, %u with format %s.\n", - texture_gl, sub_resource_idx, debug_d3dformat(format_gl->f.id)); - return; - } + return texture->level_count * texture->layer_count; +}
- sub_resource = &texture_gl->t.sub_resources[sub_resource_idx]; - target = wined3d_texture_gl_get_sub_resource_target(texture_gl, sub_resource_idx); - level = sub_resource_idx % texture_gl->t.level_count; +static HRESULT texture_resource_sub_resource_get_desc(struct wined3d_resource *resource, + unsigned int sub_resource_idx, struct wined3d_sub_resource_desc *desc) +{ + const struct wined3d_texture *texture = texture_from_resource(resource);
- if (target == GL_TEXTURE_1D_ARRAY || target == GL_TEXTURE_2D_ARRAY) - { - if (format_gl->f.download) - { - FIXME("Reading back converted array texture %p is not supported.\n", texture_gl); - return; - } + return wined3d_texture_get_sub_resource_desc(texture, sub_resource_idx, desc); +}
- WARN_(d3d_perf)("Downloading all miplevel layers to get the data for a single sub-resource.\n"); +static void texture_resource_sub_resource_get_map_pitch(struct wined3d_resource *resource, + unsigned int sub_resource_idx, unsigned int *row_pitch, unsigned int *slice_pitch) +{ + const struct wined3d_texture *texture = texture_from_resource(resource); + unsigned int level = sub_resource_idx % texture->level_count;
- if (!(temporary_mem = calloc(texture_gl->t.layer_count, sub_resource->size))) - { - ERR("Out of memory.\n"); - return; - } + if (resource->format_attrs & WINED3D_FORMAT_ATTR_BROKEN_PITCH) + { + *row_pitch = wined3d_texture_get_level_width(texture, level) * resource->format->byte_count; + *slice_pitch = wined3d_texture_get_level_height(texture, level) * (*row_pitch); } - - if (format_gl->f.download) + else { - struct wined3d_format f; + wined3d_texture_get_pitch(texture, level, row_pitch, slice_pitch); + } +}
- if (bo) - ERR("Converted texture %p uses PBO unexpectedly.\n", texture_gl); +static HRESULT texture_resource_sub_resource_map(struct wined3d_resource *resource, unsigned int sub_resource_idx, + void **map_ptr, const struct wined3d_box *box, uint32_t flags) +{ + struct wined3d_texture_sub_resource *sub_resource; + struct wined3d_device *device = resource->device; + struct wined3d_context *context; + struct wined3d_texture *texture; + struct wined3d_bo_address data; + unsigned int texture_level; + BYTE *base_memory; + BOOL ret = TRUE;
- WARN_(d3d_perf)("Downloading converted texture %p, %u with format %s.\n", - texture_gl, sub_resource_idx, debug_d3dformat(format_gl->f.id)); + TRACE("resource %p, sub_resource_idx %u, map_ptr %p, box %s, flags %#x.\n", + resource, sub_resource_idx, map_ptr, debug_box(box), flags);
- f = format_gl->f; - f.byte_count = format_gl->f.conv_byte_count; - wined3d_texture_get_pitch(&texture_gl->t, level, &dst_row_pitch, &dst_slice_pitch); - wined3d_format_calculate_pitch(&f, texture_gl->t.resource.device->surface_alignment, - wined3d_texture_get_level_width(&texture_gl->t, level), - wined3d_texture_get_level_height(&texture_gl->t, level), - &src_row_pitch, &src_slice_pitch); + texture = texture_from_resource(resource); + sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx);
- if (!(temporary_mem = malloc(src_slice_pitch))) - { - ERR("Failed to allocate memory.\n"); - return; - } - } + texture_level = sub_resource_idx % texture->level_count;
- if (temporary_mem) - { - GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)); - checkGLcall("glBindBuffer"); - mem = temporary_mem; - } - else if (bo) - { - GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, bo->id)); - checkGLcall("glBindBuffer"); - mem = (uint8_t *)data->addr + bo->b.buffer_offset; - } - else + if (texture->flags & WINED3D_TEXTURE_DC_IN_USE) { - GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)); - checkGLcall("glBindBuffer"); - mem = data->addr; + WARN("DC is in use.\n"); + return WINED3DERR_INVALIDCALL; }
- if (texture_gl->t.resource.format_attrs & WINED3D_FORMAT_ATTR_COMPRESSED) + if (sub_resource->map_count) { - TRACE("Downloading compressed texture %p, %u, level %u, format %#x, type %#x, data %p.\n", - texture_gl, sub_resource_idx, level, format_gl->format, format_gl->type, mem); - - GL_EXTCALL(glGetCompressedTexImage(target, level, mem)); - checkGLcall("glGetCompressedTexImage"); + WARN("Sub-resource is already mapped.\n"); + return WINED3DERR_INVALIDCALL; } - else - { - TRACE("Downloading texture %p, %u, level %u, format %#x, type %#x, data %p.\n", - texture_gl, sub_resource_idx, level, format_gl->format, format_gl->type, mem);
- gl_info->gl_ops.gl.p_glGetTexImage(target, level, format_gl->format, format_gl->type, mem); - checkGLcall("glGetTexImage"); - } + context = context_acquire(device, NULL, 0);
- if (format_gl->f.download) + if (flags & WINED3D_MAP_DISCARD) { - format_gl->f.download(mem, data->addr, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch, - wined3d_texture_get_level_width(&texture_gl->t, level), - wined3d_texture_get_level_height(&texture_gl->t, level), 1); + TRACE("WINED3D_MAP_DISCARD flag passed, marking %s as up to date.\n", + wined3d_debug_location(resource->map_binding)); + if ((ret = wined3d_texture_prepare_location(texture, sub_resource_idx, context, resource->map_binding))) + wined3d_texture_validate_location(texture, sub_resource_idx, resource->map_binding); } - else if (temporary_mem) + else { - unsigned int layer = sub_resource_idx / texture_gl->t.level_count; - void *src_data = temporary_mem + layer * sub_resource->size; - if (bo) + if (resource->usage & WINED3DUSAGE_DYNAMIC) + WARN_(d3d_perf)("Mapping a dynamic texture without WINED3D_MAP_DISCARD.\n"); + if (!texture_level) { - GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, bo->id)); - checkGLcall("glBindBuffer"); - GL_EXTCALL(glBufferSubData(GL_PIXEL_PACK_BUFFER, - (GLintptr)data->addr + bo->b.buffer_offset, sub_resource->size, src_data)); - checkGLcall("glBufferSubData"); + unsigned int i; + + for (i = 0; i < texture->level_count; ++i) + { + if (!(ret = wined3d_texture_load_location(texture, sub_resource_idx + i, context, resource->map_binding))) + break; + } } else { - memcpy(data->addr, src_data, sub_resource->size); + ret = wined3d_texture_load_location(texture, sub_resource_idx, context, resource->map_binding); } }
- if (bo) - { - GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)); - wined3d_context_gl_reference_bo(context_gl, bo); - checkGLcall("glBindBuffer"); - } - - free(temporary_mem); -} - -static void wined3d_texture_gl_download_data(struct wined3d_context *context, - struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, unsigned int src_location, - const struct wined3d_box *src_box, const struct wined3d_bo_address *dst_bo_addr, - const struct wined3d_format *dst_format, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, - unsigned int dst_row_pitch, unsigned int dst_slice_pitch) -{ - struct wined3d_texture_gl *src_texture_gl = wined3d_texture_gl(src_texture); - struct wined3d_context_gl *context_gl = wined3d_context_gl(context); - const struct wined3d_gl_info *gl_info = context_gl->gl_info; - unsigned int src_level, src_width, src_height, src_depth; - unsigned int src_row_pitch, src_slice_pitch; - const struct wined3d_format_gl *format_gl; - uint8_t *offset = dst_bo_addr->addr; - struct wined3d_bo *dst_bo; - BOOL srgb = FALSE; - GLenum target; - - TRACE("context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_box %s, dst_bo_addr %s, " - "dst_format %s, dst_x %u, dst_y %u, dst_z %u, dst_row_pitch %u, dst_slice_pitch %u.\n", - context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location), - debug_box(src_box), debug_bo_address(dst_bo_addr), debug_d3dformat(dst_format->id), - dst_x, dst_y, dst_z, dst_row_pitch, dst_slice_pitch); - - if (src_location == WINED3D_LOCATION_TEXTURE_SRGB) - { - srgb = TRUE; - } - else if (src_location != WINED3D_LOCATION_TEXTURE_RGB) + if (!ret) { - FIXME("Unhandled location %s.\n", wined3d_debug_location(src_location)); - return; + ERR("Failed to prepare location.\n"); + context_release(context); + return E_OUTOFMEMORY; }
- src_level = src_sub_resource_idx % src_texture->level_count; - src_width = wined3d_texture_get_level_width(src_texture, src_level); - src_height = wined3d_texture_get_level_height(src_texture, src_level); - src_depth = wined3d_texture_get_level_depth(src_texture, src_level); - if (src_box->left || src_box->top || src_box->right != src_width || src_box->bottom != src_height - || src_box->front || src_box->back != src_depth) - { - FIXME("Unhandled source box %s.\n", debug_box(src_box)); - return; - } + /* We only record dirty regions for the top-most level. */ + if (texture->dirty_regions && flags & WINED3D_MAP_WRITE + && !(flags & WINED3D_MAP_NO_DIRTY_UPDATE) && !texture_level) + wined3d_texture_dirty_region_add(texture, sub_resource_idx / texture->level_count, box);
- if (dst_x || dst_y || dst_z) + if (flags & WINED3D_MAP_WRITE) { - FIXME("Unhandled destination (%u, %u, %u).\n", dst_x, dst_y, dst_z); - return; - } + if (!texture_level) + { + unsigned int i;
- if (dst_format->id != src_texture->resource.format->id) - { - FIXME("Unhandled format conversion (%s -> %s).\n", - debug_d3dformat(src_texture->resource.format->id), - debug_d3dformat(dst_format->id)); - return; + for (i = 0; i < texture->level_count; ++i) + wined3d_texture_invalidate_location(texture, sub_resource_idx + i, ~resource->map_binding); + } + else + { + wined3d_texture_invalidate_location(texture, sub_resource_idx, ~resource->map_binding); + } }
- wined3d_texture_get_pitch(src_texture, src_level, &src_row_pitch, &src_slice_pitch); - if (src_row_pitch != dst_row_pitch || src_slice_pitch != dst_slice_pitch) - { - FIXME("Unhandled destination pitches %u/%u (source pitches %u/%u).\n", - dst_row_pitch, dst_slice_pitch, src_row_pitch, src_slice_pitch); - return; - } + wined3d_texture_get_bo_address(texture, sub_resource_idx, &data, resource->map_binding); + base_memory = wined3d_context_map_bo_address(context, &data, sub_resource->size, flags); + sub_resource->map_flags = flags; + TRACE("Base memory pointer %p.\n", base_memory);
- wined3d_texture_gl_bind_and_dirtify(src_texture_gl, context_gl, srgb); + context_release(context);
- format_gl = wined3d_format_gl(src_texture->resource.format); - target = wined3d_texture_gl_get_sub_resource_target(src_texture_gl, src_sub_resource_idx); + *map_ptr = resource_offset_map_pointer(resource, sub_resource_idx, base_memory, box);
- if ((src_texture->resource.type == WINED3D_RTYPE_TEXTURE_2D - && (target == GL_TEXTURE_2D_ARRAY || format_gl->f.conv_byte_count - || (src_texture->flags & WINED3D_TEXTURE_CONVERTED))) - || target == GL_TEXTURE_1D_ARRAY) + if (texture->swapchain && texture->swapchain->front_buffer == texture) { - wined3d_texture_gl_download_data_slow_path(src_texture_gl, src_sub_resource_idx, context_gl, dst_bo_addr); - return; - } + RECT *r = &texture->swapchain->front_buffer_update;
- if (format_gl->f.conv_byte_count) - { - FIXME("Attempting to download a converted texture, type %s format %s.\n", - debug_d3dresourcetype(src_texture->resource.type), - debug_d3dformat(format_gl->f.id)); - return; + SetRect(r, box->left, box->top, box->right, box->bottom); + TRACE("Mapped front buffer %s.\n", wine_dbgstr_rect(r)); }
- if ((dst_bo = dst_bo_addr->buffer_object)) - { - GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, wined3d_bo_gl(dst_bo)->id)); - checkGLcall("glBindBuffer"); - offset += dst_bo->buffer_offset; - } - else - { - GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)); - checkGLcall("glBindBuffer"); - } - - if (src_texture->resource.format_attrs & WINED3D_FORMAT_ATTR_COMPRESSED) - { - TRACE("Downloading compressed texture %p, %u, level %u, format %#x, type %#x, data %p.\n", - src_texture, src_sub_resource_idx, src_level, format_gl->format, format_gl->type, offset); - - GL_EXTCALL(glGetCompressedTexImage(target, src_level, offset)); - checkGLcall("glGetCompressedTexImage"); - } - else - { - TRACE("Downloading texture %p, %u, level %u, format %#x, type %#x, data %p.\n", - src_texture, src_sub_resource_idx, src_level, format_gl->format, format_gl->type, offset); + ++resource->map_count; + ++sub_resource->map_count;
- gl_info->gl_ops.gl.p_glGetTexImage(target, src_level, format_gl->format, format_gl->type, offset); - checkGLcall("glGetTexImage"); - } + TRACE("Returning memory %p.\n", *map_ptr);
- if (dst_bo) - { - GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)); - wined3d_context_gl_reference_bo(context_gl, wined3d_bo_gl(dst_bo)); - checkGLcall("glBindBuffer"); - } + return WINED3D_OK; }
-/* Context activation is done by the caller. */ -static BOOL wined3d_texture_gl_load_sysmem(struct wined3d_texture_gl *texture_gl, - unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl, DWORD dst_location) +static HRESULT texture_resource_sub_resource_unmap(struct wined3d_resource *resource, unsigned int sub_resource_idx) { struct wined3d_texture_sub_resource *sub_resource; + struct wined3d_device *device = resource->device; + struct wined3d_context *context; + struct wined3d_texture *texture; + struct wined3d_bo_address data; + struct wined3d_range range;
- sub_resource = &texture_gl->t.sub_resources[sub_resource_idx]; - - /* We cannot download data from multisample textures directly. */ - if (wined3d_texture_gl_is_multisample_location(texture_gl, WINED3D_LOCATION_TEXTURE_RGB) - || sub_resource->locations & WINED3D_LOCATION_RB_MULTISAMPLE) - wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, &context_gl->c, WINED3D_LOCATION_RB_RESOLVED); - - if (sub_resource->locations & WINED3D_LOCATION_RB_RESOLVED) - { - texture2d_read_from_framebuffer(&texture_gl->t, sub_resource_idx, &context_gl->c, - WINED3D_LOCATION_RB_RESOLVED, dst_location); - return TRUE; - } + TRACE("resource %p, sub_resource_idx %u.\n", resource, sub_resource_idx);
- if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB)) - { - unsigned int row_pitch, slice_pitch, level; - struct wined3d_bo_address data; - struct wined3d_box src_box; - unsigned int src_location; - - level = sub_resource_idx % texture_gl->t.level_count; - wined3d_texture_get_bo_address(&texture_gl->t, sub_resource_idx, &data, dst_location); - src_location = sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB - ? WINED3D_LOCATION_TEXTURE_RGB : WINED3D_LOCATION_TEXTURE_SRGB; - wined3d_texture_get_level_box(&texture_gl->t, level, &src_box); - wined3d_texture_get_pitch(&texture_gl->t, level, &row_pitch, &slice_pitch); - wined3d_texture_gl_download_data(&context_gl->c, &texture_gl->t, sub_resource_idx, src_location, - &src_box, &data, texture_gl->t.resource.format, 0, 0, 0, row_pitch, slice_pitch); - - ++texture_gl->t.download_count; - return TRUE; - } + texture = texture_from_resource(resource); + if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx))) + return E_INVALIDARG;
- if (sub_resource->locations & WINED3D_LOCATION_DRAWABLE) + if (!sub_resource->map_count) { - texture2d_read_from_framebuffer(&texture_gl->t, sub_resource_idx, &context_gl->c, - texture_gl->t.resource.draw_binding, dst_location); - return TRUE; + WARN("Trying to unmap unmapped sub-resource.\n"); + if (texture->flags & WINED3D_TEXTURE_DC_IN_USE) + return WINED3D_OK; + return WINEDDERR_NOTLOCKED; }
- FIXME("Can't load texture %p, %u with location flags %s into sysmem.\n", - texture_gl, sub_resource_idx, wined3d_debug_location(sub_resource->locations)); - - return FALSE; -} + context = context_acquire(device, NULL, 0);
-static BOOL wined3d_texture_load_drawable(struct wined3d_texture *texture, - unsigned int sub_resource_idx, struct wined3d_context *context) -{ - struct wined3d_device *device; - unsigned int level; - RECT r; + wined3d_texture_get_bo_address(texture, sub_resource_idx, &data, texture->resource.map_binding); + range.offset = 0; + range.size = sub_resource->size; + wined3d_context_unmap_bo_address(context, &data, !!(sub_resource->map_flags & WINED3D_MAP_WRITE), &range);
- if (texture->resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL) - { - DWORD current = texture->sub_resources[sub_resource_idx].locations; - FIXME("Unimplemented copy from %s for depth/stencil buffers.\n", - wined3d_debug_location(current)); - return FALSE; - } + context_release(context);
- if (wined3d_resource_is_offscreen(&texture->resource)) + if (texture->swapchain && texture->swapchain->front_buffer == texture) { - ERR("Trying to load offscreen texture into WINED3D_LOCATION_DRAWABLE.\n"); - return FALSE; + if (!(sub_resource->locations & (WINED3D_LOCATION_DRAWABLE | WINED3D_LOCATION_TEXTURE_RGB))) + texture->swapchain->swapchain_ops->swapchain_frontbuffer_updated(texture->swapchain); }
- device = texture->resource.device; - level = sub_resource_idx % texture->level_count; - SetRect(&r, 0, 0, wined3d_texture_get_level_width(texture, level), - wined3d_texture_get_level_height(texture, level)); - wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB); - device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_COLOR_BLIT, context, - texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &r, - texture, sub_resource_idx, WINED3D_LOCATION_DRAWABLE, &r, - NULL, WINED3D_TEXF_POINT, NULL); + --sub_resource->map_count; + if (!--resource->map_count && texture->update_map_binding) + wined3d_texture_update_map_binding(texture);
- return TRUE; + return WINED3D_OK; }
-static BOOL wined3d_texture_load_renderbuffer(struct wined3d_texture *texture, - unsigned int sub_resource_idx, struct wined3d_context *context, DWORD dst_location) +static const struct wined3d_resource_ops texture_resource_ops = { - unsigned int level = sub_resource_idx % texture->level_count; - const RECT rect = {0, 0, - wined3d_texture_get_level_width(texture, level), - wined3d_texture_get_level_height(texture, level)}; - struct wined3d_texture_sub_resource *sub_resource; - DWORD src_location, locations; - - sub_resource = &texture->sub_resources[sub_resource_idx]; - locations = sub_resource->locations; - if (texture->resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL) - { - FIXME("Unimplemented copy from %s for depth/stencil buffers.\n", - wined3d_debug_location(locations)); - return FALSE; - } - - if (locations & WINED3D_LOCATION_RB_MULTISAMPLE) - src_location = WINED3D_LOCATION_RB_MULTISAMPLE; - else if (locations & WINED3D_LOCATION_RB_RESOLVED) - src_location = WINED3D_LOCATION_RB_RESOLVED; - else if (locations & WINED3D_LOCATION_TEXTURE_SRGB) - src_location = WINED3D_LOCATION_TEXTURE_SRGB; - else if (locations & WINED3D_LOCATION_TEXTURE_RGB) - src_location = WINED3D_LOCATION_TEXTURE_RGB; - else if (locations & WINED3D_LOCATION_DRAWABLE) - src_location = WINED3D_LOCATION_DRAWABLE; - else /* texture2d_blt_fbo() will load the source location if necessary. */ - src_location = WINED3D_LOCATION_TEXTURE_RGB; - - texture2d_blt_fbo(texture->resource.device, context, WINED3D_TEXF_POINT, texture, - sub_resource_idx, src_location, &rect, texture, sub_resource_idx, dst_location, &rect, NULL); - - return TRUE; -} + texture_resource_incref, + texture_resource_decref, + texture_resource_preload, + texture_resource_unload, + texture_resource_get_sub_resource_count, + texture_resource_sub_resource_get_desc, + texture_resource_sub_resource_get_map_pitch, + texture_resource_sub_resource_map, + texture_resource_sub_resource_unmap, +};
-static BOOL wined3d_texture_gl_load_texture(struct wined3d_texture_gl *texture_gl, - unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl, BOOL srgb) +HRESULT wined3d_texture_init(struct wined3d_texture *texture, const struct wined3d_resource_desc *desc, + unsigned int layer_count, unsigned int level_count, uint32_t flags, struct wined3d_device *device, + void *parent, const struct wined3d_parent_ops *parent_ops, void *sub_resources, + const struct wined3d_texture_ops *texture_ops) { - unsigned int width, height, level, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch; - struct wined3d_device *device = texture_gl->t.resource.device; - const struct wined3d_gl_info *gl_info = context_gl->gl_info; - const struct wined3d_color_key_conversion *conversion; - struct wined3d_texture_sub_resource *sub_resource; + const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info; + struct wined3d_device_parent *device_parent = device->device_parent; + unsigned int sub_count, i, j, size, offset = 0; const struct wined3d_format *format; - struct wined3d_bo_address data; - BYTE *src_mem, *dst_mem = NULL; - struct wined3d_box src_box; - DWORD dst_location; - BOOL depth; - - depth = texture_gl->t.resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL; - sub_resource = &texture_gl->t.sub_resources[sub_resource_idx]; - level = sub_resource_idx % texture_gl->t.level_count; - wined3d_texture_get_level_box(&texture_gl->t, level, &src_box); - - if (!depth && sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB) - && (texture_gl->t.resource.format_caps & WINED3D_FORMAT_CAP_FBO_ATTACHABLE_SRGB) - && fbo_blitter_supported(WINED3D_BLIT_OP_COLOR_BLIT, gl_info, - &texture_gl->t.resource, WINED3D_LOCATION_TEXTURE_RGB, - &texture_gl->t.resource, WINED3D_LOCATION_TEXTURE_SRGB)) - { - RECT src_rect; + HRESULT hr;
- SetRect(&src_rect, src_box.left, src_box.top, src_box.right, src_box.bottom); - if (srgb) - texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT, - &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect, - &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect, NULL); - else - texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT, - &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect, - &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect, NULL); + TRACE("texture %p, resource_type %s, format %s, multisample_type %#x, multisample_quality %#x, " + "usage %s, bind_flags %s, access %s, width %u, height %u, depth %u, layer_count %u, level_count %u, " + "flags %#x, device %p, parent %p, parent_ops %p, sub_resources %p, texture_ops %p.\n", + texture, debug_d3dresourcetype(desc->resource_type), debug_d3dformat(desc->format), desc->multisample_type, + desc->multisample_quality, debug_d3dusage(desc->usage), wined3d_debug_bind_flags(desc->bind_flags), + wined3d_debug_resource_access(desc->access), desc->width, desc->height, desc->depth, + layer_count, level_count, flags, device, parent, parent_ops, sub_resources, texture_ops);
- return TRUE; - } + if (!desc->width || !desc->height || !desc->depth) + return WINED3DERR_INVALIDCALL;
- if (!depth && sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED) - && (!srgb || (texture_gl->t.resource.format_caps & WINED3D_FORMAT_CAP_FBO_ATTACHABLE_SRGB))) + if (desc->resource_type == WINED3D_RTYPE_TEXTURE_3D && layer_count != 1) { - DWORD src_location = sub_resource->locations & WINED3D_LOCATION_RB_RESOLVED ? - WINED3D_LOCATION_RB_RESOLVED : WINED3D_LOCATION_RB_MULTISAMPLE; - RECT src_rect; + ERR("Invalid layer count for volume texture.\n"); + return E_INVALIDARG; + }
- SetRect(&src_rect, src_box.left, src_box.top, src_box.right, src_box.bottom); - dst_location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB; - if (fbo_blitter_supported(WINED3D_BLIT_OP_COLOR_BLIT, gl_info, - &texture_gl->t.resource, src_location, &texture_gl->t.resource, dst_location)) - texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT, &texture_gl->t, sub_resource_idx, - src_location, &src_rect, &texture_gl->t, sub_resource_idx, dst_location, &src_rect, NULL); + texture->sub_resources = sub_resources;
- return TRUE; + /* TODO: It should only be possible to create textures for formats + * that are reported as supported. */ + if (WINED3DFMT_UNKNOWN >= desc->format) + { + WARN("Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n"); + return WINED3DERR_INVALIDCALL; } + format = wined3d_get_format(device->adapter, desc->format, desc->bind_flags);
- /* Upload from system memory */ + if ((desc->usage & WINED3DUSAGE_DYNAMIC) && (desc->usage & (WINED3DUSAGE_MANAGED | WINED3DUSAGE_SCRATCH))) + { + WARN("Attempted to create a dynamic texture with usage %s.\n", debug_d3dusage(desc->usage)); + return WINED3DERR_INVALIDCALL; + }
- if (srgb) + if (((desc->width & (desc->width - 1)) || (desc->height & (desc->height - 1)) || (desc->depth & (desc->depth - 1))) + && !d3d_info->unconditional_npot) { - dst_location = WINED3D_LOCATION_TEXTURE_SRGB; - if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | texture_gl->t.resource.map_binding)) - == WINED3D_LOCATION_TEXTURE_RGB) + /* level_count == 0 returns an error as well. */ + if (level_count != 1 || layer_count != 1 || desc->resource_type == WINED3D_RTYPE_TEXTURE_3D) { - FIXME_(d3d_perf)("Downloading RGB texture %p, %u to reload it as sRGB.\n", texture_gl, sub_resource_idx); - wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, - &context_gl->c, texture_gl->t.resource.map_binding); + if (!(desc->usage & WINED3DUSAGE_SCRATCH)) + { + WARN("Attempted to create a mipmapped/cube/array/volume NPOT " + "texture without unconditional NPOT support.\n"); + return WINED3DERR_INVALIDCALL; + } + + WARN("Creating a scratch mipmapped/cube/array NPOT texture despite lack of HW support.\n"); } + texture->flags |= WINED3D_TEXTURE_COND_NP2; } - else + + if ((desc->width > d3d_info->limits.texture_size || desc->height > d3d_info->limits.texture_size) + && (desc->bind_flags & WINED3D_BIND_SHADER_RESOURCE)) { - dst_location = WINED3D_LOCATION_TEXTURE_RGB; - if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | texture_gl->t.resource.map_binding)) - == WINED3D_LOCATION_TEXTURE_SRGB) + /* One of four options: + * 1: Scale the texture. (Any texture ops would require the texture to + * be scaled which is potentially slow.) + * 2: Set the texture to the maximum size (bad idea). + * 3: WARN and return WINED3DERR_NOTAVAILABLE. + * 4: Create the surface, but allow it to be used only for DirectDraw + * Blts. Some apps (e.g. Swat 3) create textures with a height of + * 16 and a width > 3000 and blt 16x16 letter areas from them to + * the render target. */ + if (desc->access & WINED3D_RESOURCE_ACCESS_GPU) { - FIXME_(d3d_perf)("Downloading sRGB texture %p, %u to reload it as RGB.\n", texture_gl, sub_resource_idx); - wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, - &context_gl->c, texture_gl->t.resource.map_binding); + WARN("Dimensions (%ux%u) exceed the maximum texture size.\n", desc->width, desc->height); + return WINED3DERR_NOTAVAILABLE; } - }
- if (!(sub_resource->locations & wined3d_texture_sysmem_locations)) - { - WARN("Trying to load a texture from sysmem, but no simple location is valid.\n"); - /* Lets hope we get it from somewhere... */ - wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, &context_gl->c, WINED3D_LOCATION_SYSMEM); + /* We should never use this surface in combination with OpenGL. */ + TRACE("Creating an oversized (%ux%u) surface.\n", desc->width, desc->height); }
- wined3d_texture_get_pitch(&texture_gl->t, level, &src_row_pitch, &src_slice_pitch); - - format = texture_gl->t.resource.format; - if ((conversion = wined3d_format_get_color_key_conversion(&texture_gl->t, TRUE))) - format = wined3d_get_format(device->adapter, conversion->dst_format, texture_gl->t.resource.bind_flags); - - /* Don't use PBOs for converted surfaces. During PBO conversion we look at - * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is - * getting called. */ - if (conversion && sub_resource->bo) + if ((format->attrs & WINED3D_FORMAT_ATTR_PLANAR) && ((desc->width & 1) || (desc->height & 1))) { - TRACE("Removing the pbo attached to texture %p, %u.\n", texture_gl, sub_resource_idx); - - wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, &context_gl->c, WINED3D_LOCATION_SYSMEM); - wined3d_texture_set_map_binding(&texture_gl->t, WINED3D_LOCATION_SYSMEM); + WARN("Attempt to create a planar texture with unaligned size %ux%u.\n", desc->width, desc->height); + return WINED3DERR_INVALIDCALL; }
- wined3d_texture_get_memory(&texture_gl->t, sub_resource_idx, &context_gl->c, &data); - if (conversion) + for (i = 0; i < layer_count; ++i) { - width = src_box.right - src_box.left; - height = src_box.bottom - src_box.top; - wined3d_format_calculate_pitch(format, device->surface_alignment, - width, height, &dst_row_pitch, &dst_slice_pitch); - - src_mem = wined3d_context_gl_map_bo_address(context_gl, &data, src_slice_pitch, WINED3D_MAP_READ); - if (!(dst_mem = malloc(dst_slice_pitch))) + for (j = 0; j < level_count; ++j) { - ERR("Out of memory (%u).\n", dst_slice_pitch); - return FALSE; + unsigned int idx = i * level_count + j; + + size = wined3d_format_calculate_size(format, device->surface_alignment, + max(1, desc->width >> j), max(1, desc->height >> j), max(1, desc->depth >> j)); + texture->sub_resources[idx].offset = offset; + texture->sub_resources[idx].size = size; + offset += size; } - conversion->convert(src_mem, src_row_pitch, dst_mem, dst_row_pitch, - width, height, &texture_gl->t.async.gl_color_key); - src_row_pitch = dst_row_pitch; - src_slice_pitch = dst_slice_pitch; - wined3d_context_gl_unmap_bo_address(context_gl, &data, 0, NULL); - - data.buffer_object = 0; - data.addr = dst_mem; + offset = (offset + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1); }
- wined3d_texture_gl_upload_data(&context_gl->c, wined3d_const_bo_address(&data), format, &src_box, - src_row_pitch, src_slice_pitch, &texture_gl->t, sub_resource_idx, dst_location, 0, 0, 0); - - free(dst_mem); - - return TRUE; -} - -static BOOL wined3d_texture_gl_prepare_location(struct wined3d_texture *texture, - unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location) -{ - struct wined3d_texture_gl *texture_gl = wined3d_texture_gl(texture); - struct wined3d_context_gl *context_gl = wined3d_context_gl(context); + if (!offset) + return WINED3DERR_INVALIDCALL;
- switch (location) + /* Ensure the last mip-level is at least large enough to hold a single + * compressed block. It is questionable how useful these mip-levels are to + * the application with "broken pitch" formats, but we want to avoid + * memory corruption when loading textures into WINED3D_LOCATION_SYSMEM. */ + if (format->attrs & WINED3D_FORMAT_ATTR_BROKEN_PITCH) { - case WINED3D_LOCATION_SYSMEM: - return texture->sub_resources[sub_resource_idx].user_memory ? TRUE - : wined3d_resource_prepare_sysmem(&texture->resource); - - case WINED3D_LOCATION_BUFFER: - wined3d_texture_gl_prepare_buffer_object(texture_gl, sub_resource_idx, context_gl); - return TRUE; - - case WINED3D_LOCATION_TEXTURE_RGB: - wined3d_texture_gl_prepare_texture(texture_gl, context_gl, FALSE); - return TRUE; - - case WINED3D_LOCATION_TEXTURE_SRGB: - wined3d_texture_gl_prepare_texture(texture_gl, context_gl, TRUE); - return TRUE; + unsigned int min_size;
- case WINED3D_LOCATION_DRAWABLE: - if (!texture->swapchain) - ERR("Texture %p does not have a drawable.\n", texture); - return TRUE; + min_size = texture->sub_resources[level_count * layer_count - 1].offset + format->block_byte_count; + min_size = (min_size + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1); + if (min_size > offset) + offset = min_size; + }
- case WINED3D_LOCATION_RB_MULTISAMPLE: - wined3d_texture_gl_prepare_rb(texture_gl, context_gl->gl_info, TRUE); - return TRUE; + if (FAILED(hr = resource_init(&texture->resource, device, desc->resource_type, format, + desc->multisample_type, desc->multisample_quality, desc->usage, desc->bind_flags, desc->access, + desc->width, desc->height, desc->depth, offset, parent, parent_ops, &texture_resource_ops))) + { + static unsigned int once;
- case WINED3D_LOCATION_RB_RESOLVED: - wined3d_texture_gl_prepare_rb(texture_gl, context_gl->gl_info, FALSE); - return TRUE; + /* DXTn 3D textures are not supported. Do not write the ERR for them. */ + if ((desc->format == WINED3DFMT_DXT1 || desc->format == WINED3DFMT_DXT2 || desc->format == WINED3DFMT_DXT3 + || desc->format == WINED3DFMT_DXT4 || desc->format == WINED3DFMT_DXT5) + && !(format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_TEXTURE) + && desc->resource_type != WINED3D_RTYPE_TEXTURE_3D && !once++) + ERR_(winediag)("The application tried to create a DXTn texture, but the driver does not support them.\n");
- default: - ERR("Invalid location %s.\n", wined3d_debug_location(location)); - return FALSE; + WARN("Failed to initialize resource, returning %#lx\n", hr); + return hr; } -} + wined3d_resource_update_draw_binding(&texture->resource);
-static bool use_ffp_clear(const struct wined3d_texture *texture, unsigned int location) -{ - if (location == WINED3D_LOCATION_DRAWABLE) - return true; + texture->texture_ops = texture_ops;
- if (location == WINED3D_LOCATION_TEXTURE_RGB - && !(texture->resource.format_caps & WINED3D_FORMAT_CAP_FBO_ATTACHABLE)) - return false; - if (location == WINED3D_LOCATION_TEXTURE_SRGB - && !(texture->resource.format_caps & WINED3D_FORMAT_CAP_FBO_ATTACHABLE_SRGB)) - return false; - - return location & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED - | WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB); -} - -static bool wined3d_texture_gl_clear(struct wined3d_texture *texture, - unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl, unsigned int location) -{ - struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx]; - const struct wined3d_format *format = texture->resource.format; - const struct wined3d_gl_info *gl_info = context_gl->gl_info; - struct wined3d_bo_address addr; - - /* The code that delays clears is Vulkan-specific, so here we should only - * encounter WINED3D_LOCATION_CLEARED on newly created resources and thus - * a zero clear value. */ - if (!format->depth_size && !format->stencil_size) + texture->layer_count = layer_count; + texture->level_count = level_count; + texture->lod = 0; + texture->flags |= WINED3D_TEXTURE_DOWNLOADABLE; + if (flags & WINED3D_TEXTURE_CREATE_GET_DC_LENIENT) { - if (sub_resource->clear_value.colour.r || sub_resource->clear_value.colour.g - || sub_resource->clear_value.colour.b || sub_resource->clear_value.colour.a) - { - ERR("Unexpected color clear value r=%08e, g=%08e, b=%08e, a=%08e.\n", - sub_resource->clear_value.colour.r, sub_resource->clear_value.colour.g, - sub_resource->clear_value.colour.b, sub_resource->clear_value.colour.a); - } + texture->flags |= WINED3D_TEXTURE_GET_DC_LENIENT; + texture->resource.pin_sysmem = 1; } - else + if (flags & (WINED3D_TEXTURE_CREATE_GET_DC | WINED3D_TEXTURE_CREATE_GET_DC_LENIENT)) + texture->flags |= WINED3D_TEXTURE_GET_DC; + if (flags & WINED3D_TEXTURE_CREATE_DISCARD) + texture->flags |= WINED3D_TEXTURE_DISCARD; + if (flags & WINED3D_TEXTURE_CREATE_GENERATE_MIPMAPS) { - if (format->depth_size && sub_resource->clear_value.depth) - ERR("Unexpected depth clear value %08e.\n", sub_resource->clear_value.depth); - if (format->stencil_size && sub_resource->clear_value.stencil) - ERR("Unexpected stencil clear value %x.\n", sub_resource->clear_value.stencil); + if (!(texture->resource.format_caps & WINED3D_FORMAT_CAP_GEN_MIPMAP)) + WARN("Format doesn't support mipmaps generation, " + "ignoring WINED3D_TEXTURE_CREATE_GENERATE_MIPMAPS flag.\n"); + else + texture->flags |= WINED3D_TEXTURE_GENERATE_MIPMAPS; }
- if (use_ffp_clear(texture, location)) + if (flags & WINED3D_TEXTURE_CREATE_RECORD_DIRTY_REGIONS) { - GLbitfield clear_mask = 0; + if (!(texture->dirty_regions = calloc(texture->layer_count, sizeof(*texture->dirty_regions)))) + { + wined3d_texture_cleanup_sync(texture); + return E_OUTOFMEMORY; + } + for (i = 0; i < texture->layer_count; ++i) + wined3d_texture_dirty_region_add(texture, i, NULL); + }
- context_gl_apply_texture_draw_state(context_gl, texture, sub_resource_idx, location); + if (wined3d_texture_use_pbo(texture, d3d_info)) + texture->resource.map_binding = WINED3D_LOCATION_BUFFER;
- gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST); - context_invalidate_state(&context_gl->c, STATE_RASTERIZER); + sub_count = level_count * layer_count; + if (sub_count / layer_count != level_count) + { + wined3d_texture_cleanup_sync(texture); + return E_OUTOFMEMORY; + }
- if (format->depth_size) + if (desc->usage & WINED3DUSAGE_OVERLAY) + { + if (!(texture->overlay_info = calloc(sub_count, sizeof(*texture->overlay_info)))) { - gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE); - context_invalidate_state(&context_gl->c, STATE_DEPTH_STENCIL); - - if (gl_info->supported[ARB_ES2_COMPATIBILITY]) - GL_EXTCALL(glClearDepthf(0.0f)); - else - gl_info->gl_ops.gl.p_glClearDepth(0.0); - clear_mask |= GL_DEPTH_BUFFER_BIT; + wined3d_texture_cleanup_sync(texture); + return E_OUTOFMEMORY; }
- if (format->stencil_size) + for (i = 0; i < sub_count; ++i) { - if (gl_info->supported[EXT_STENCIL_TWO_SIDE]) - gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT); - gl_info->gl_ops.gl.p_glStencilMask(~0u); - context_invalidate_state(&context_gl->c, STATE_DEPTH_STENCIL); - gl_info->gl_ops.gl.p_glClearStencil(0); - clear_mask |= GL_STENCIL_BUFFER_BIT; + list_init(&texture->overlay_info[i].entry); + list_init(&texture->overlay_info[i].overlays); } + } + + /* Generate all sub-resources. */ + for (i = 0; i < sub_count; ++i) + { + struct wined3d_texture_sub_resource *sub_resource; + + sub_resource = &texture->sub_resources[i]; + sub_resource->locations = WINED3D_LOCATION_CLEARED;
- if (!format->depth_size && !format->stencil_size) + if (FAILED(hr = device_parent->ops->texture_sub_resource_created(device_parent, + desc->resource_type, texture, i, &sub_resource->parent, &sub_resource->parent_ops))) { - gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - context_invalidate_state(&context_gl->c, STATE_BLEND); - gl_info->gl_ops.gl.p_glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - clear_mask |= GL_COLOR_BUFFER_BIT; + WARN("Failed to create sub-resource parent, hr %#lx.\n", hr); + sub_resource->parent = NULL; + wined3d_texture_cleanup_sync(texture); + return hr; }
- gl_info->gl_ops.gl.p_glClear(clear_mask); - checkGLcall("clear texture"); + TRACE("parent %p, parent_ops %p.\n", sub_resource->parent, sub_resource->parent_ops);
- wined3d_texture_validate_location(texture, sub_resource_idx, location); - return true; + TRACE("Created sub-resource %u (level %u, layer %u).\n", + i, i % texture->level_count, i / texture->level_count); + + if (desc->usage & WINED3DUSAGE_OWNDC) + { + struct wined3d_texture_idx texture_idx = {texture, i}; + + wined3d_cs_init_object(device->cs, wined3d_texture_create_dc, &texture_idx); + wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT); + if (!texture->dc_info || !texture->dc_info[i].dc) + { + wined3d_texture_cleanup_sync(texture); + return WINED3DERR_INVALIDCALL; + } + } }
- if (!wined3d_texture_prepare_location(texture, sub_resource_idx, &context_gl->c, WINED3D_LOCATION_SYSMEM)) - return false; - wined3d_texture_get_bo_address(texture, sub_resource_idx, &addr, WINED3D_LOCATION_SYSMEM); - memset(addr.addr, 0, sub_resource->size); - wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_SYSMEM); - return true; + return WINED3D_OK; }
-/* Context activation is done by the caller. */ -static BOOL wined3d_texture_gl_load_location(struct wined3d_texture *texture, - unsigned int sub_resource_idx, struct wined3d_context *context, uint32_t location) +HRESULT CDECL wined3d_device_context_blt(struct wined3d_device_context *context, + struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, const RECT *dst_rect, + struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, const RECT *src_rect, + unsigned int flags, const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter) { - struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx]; - struct wined3d_texture_gl *texture_gl = wined3d_texture_gl(texture); - struct wined3d_context_gl *context_gl = wined3d_context_gl(context); + struct wined3d_box src_box = {src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1}; + struct wined3d_box dst_box = {dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, 0, 1}; + HRESULT hr;
- TRACE("texture %p, sub_resource_idx %u, context %p, location %s.\n", - texture, sub_resource_idx, context, wined3d_debug_location(location)); + TRACE("context %p, dst_texture %p, dst_sub_resource_idx %u, dst_rect %s, src_texture %p, " + "src_sub_resource_idx %u, src_rect %s, flags %#x, fx %p, filter %s.\n", + context, dst_texture, dst_sub_resource_idx, wine_dbgstr_rect(dst_rect), src_texture, + src_sub_resource_idx, wine_dbgstr_rect(src_rect), flags, fx, debug_d3dtexturefiltertype(filter));
- if (!wined3d_texture_gl_prepare_location(texture, sub_resource_idx, context, location)) - return FALSE; + if (!wined3d_texture_validate_sub_resource_idx(dst_texture, dst_sub_resource_idx) + || dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D) + return WINED3DERR_INVALIDCALL;
- if (sub_resource->locations & WINED3D_LOCATION_CLEARED) - { - if (!wined3d_texture_gl_clear(texture, sub_resource_idx, context_gl, location)) - return FALSE; + if (!wined3d_texture_validate_sub_resource_idx(src_texture, src_sub_resource_idx) + || src_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D) + return WINED3DERR_INVALIDCALL; + + if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT + && filter != WINED3D_TEXF_LINEAR) + return WINED3DERR_INVALIDCALL; + + if (FAILED(hr = wined3d_resource_check_box_dimensions(&dst_texture->resource, dst_sub_resource_idx, &dst_box))) + return hr;
- if (sub_resource->locations & location) - return TRUE; + if (FAILED(hr = wined3d_resource_check_box_dimensions(&src_texture->resource, src_sub_resource_idx, &src_box))) + return hr; + + if (dst_texture->sub_resources[dst_sub_resource_idx].map_count + || src_texture->sub_resources[src_sub_resource_idx].map_count) + { + WARN("Sub-resource is busy, returning WINEDDERR_SURFACEBUSY.\n"); + return WINEDDERR_SURFACEBUSY; }
- switch (location) + if (!src_texture->resource.format->depth_size != !dst_texture->resource.format->depth_size + || !src_texture->resource.format->stencil_size != !dst_texture->resource.format->stencil_size) { - case WINED3D_LOCATION_SYSMEM: - case WINED3D_LOCATION_BUFFER: - return wined3d_texture_gl_load_sysmem(texture_gl, sub_resource_idx, context_gl, location); + WARN("Rejecting depth/stencil blit between incompatible formats.\n"); + return WINED3DERR_INVALIDCALL; + }
- case WINED3D_LOCATION_DRAWABLE: - return wined3d_texture_load_drawable(texture, sub_resource_idx, context); + if (dst_texture->resource.device != src_texture->resource.device) + { + FIXME("Rejecting cross-device blit.\n"); + return E_NOTIMPL; + }
- case WINED3D_LOCATION_RB_RESOLVED: - case WINED3D_LOCATION_RB_MULTISAMPLE: - return wined3d_texture_load_renderbuffer(texture, sub_resource_idx, context, location); + wined3d_device_context_emit_blt_sub_resource(context, &dst_texture->resource, dst_sub_resource_idx, + &dst_box, &src_texture->resource, src_sub_resource_idx, &src_box, flags, fx, filter);
- case WINED3D_LOCATION_TEXTURE_RGB: - case WINED3D_LOCATION_TEXTURE_SRGB: - return wined3d_texture_gl_load_texture(texture_gl, sub_resource_idx, - context_gl, location == WINED3D_LOCATION_TEXTURE_SRGB); + if (dst_texture->dirty_regions) + wined3d_texture_add_dirty_region(dst_texture, dst_sub_resource_idx, &dst_box);
- default: - FIXME("Unhandled %s load from %s.\n", wined3d_debug_location(location), - wined3d_debug_location(texture->sub_resources[sub_resource_idx].locations)); - return FALSE; - } + return WINED3D_OK; }
-static void wined3d_texture_gl_unload_location(struct wined3d_texture *texture, - struct wined3d_context *context, unsigned int location) +HRESULT CDECL wined3d_texture_get_overlay_position(const struct wined3d_texture *texture, + unsigned int sub_resource_idx, LONG *x, LONG *y) { - struct wined3d_texture_gl *texture_gl = wined3d_texture_gl(texture); - struct wined3d_context_gl *context_gl = wined3d_context_gl(context); - struct wined3d_renderbuffer_entry *entry, *entry2; - unsigned int i, sub_count; - - TRACE("texture %p, context %p, location %s.\n", texture, context, wined3d_debug_location(location)); - - switch (location) - { - case WINED3D_LOCATION_BUFFER: - sub_count = texture->level_count * texture->layer_count; - for (i = 0; i < sub_count; ++i) - { - if (texture_gl->t.sub_resources[i].bo) - wined3d_texture_remove_buffer_object(&texture_gl->t, i, context_gl); - } - break; + struct wined3d_overlay_info *overlay;
- case WINED3D_LOCATION_TEXTURE_RGB: - if (texture_gl->texture_rgb.name) - gltexture_delete(texture_gl->t.resource.device, context_gl->gl_info, &texture_gl->texture_rgb); - break; + TRACE("texture %p, sub_resource_idx %u, x %p, y %p.\n", texture, sub_resource_idx, x, y);
- case WINED3D_LOCATION_TEXTURE_SRGB: - if (texture_gl->texture_srgb.name) - gltexture_delete(texture_gl->t.resource.device, context_gl->gl_info, &texture_gl->texture_srgb); - break; + if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY) + || !wined3d_texture_validate_sub_resource_idx(texture, sub_resource_idx)) + return WINEDDERR_NOTAOVERLAYSURFACE;
- case WINED3D_LOCATION_RB_MULTISAMPLE: - if (texture_gl->rb_multisample) - { - TRACE("Deleting multisample renderbuffer %u.\n", texture_gl->rb_multisample); - context_gl_resource_released(texture_gl->t.resource.device, texture_gl->rb_multisample, TRUE); - context_gl->gl_info->fbo_ops.glDeleteRenderbuffers(1, &texture_gl->rb_multisample); - texture_gl->rb_multisample = 0; - } - break; + overlay = &texture->overlay_info[sub_resource_idx]; + if (!overlay->dst_texture) + { + TRACE("Overlay not visible.\n"); + *x = 0; + *y = 0; + return WINEDDERR_OVERLAYNOTVISIBLE; + }
- case WINED3D_LOCATION_RB_RESOLVED: - LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &texture_gl->renderbuffers, - struct wined3d_renderbuffer_entry, entry) - { - context_gl_resource_released(texture_gl->t.resource.device, entry->id, TRUE); - context_gl->gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id); - list_remove(&entry->entry); - free(entry); - } - list_init(&texture_gl->renderbuffers); - texture_gl->current_renderbuffer = NULL; + *x = overlay->dst_rect.left; + *y = overlay->dst_rect.top;
- if (texture_gl->rb_resolved) - { - TRACE("Deleting resolved renderbuffer %u.\n", texture_gl->rb_resolved); - context_gl_resource_released(texture_gl->t.resource.device, texture_gl->rb_resolved, TRUE); - context_gl->gl_info->fbo_ops.glDeleteRenderbuffers(1, &texture_gl->rb_resolved); - texture_gl->rb_resolved = 0; - } - break; + TRACE("Returning position %ld, %ld.\n", *x, *y);
- default: - ERR("Unhandled location %s.\n", wined3d_debug_location(location)); - break; - } + return WINED3D_OK; }
-static const struct wined3d_texture_ops texture_gl_ops = -{ - wined3d_texture_gl_prepare_location, - wined3d_texture_gl_load_location, - wined3d_texture_gl_unload_location, - wined3d_texture_gl_upload_data, - wined3d_texture_gl_download_data, -}; - -struct wined3d_texture * __cdecl wined3d_texture_from_resource(struct wined3d_resource *resource) +HRESULT CDECL wined3d_texture_set_overlay_position(struct wined3d_texture *texture, + unsigned int sub_resource_idx, LONG x, LONG y) { - return texture_from_resource(resource); -} + struct wined3d_overlay_info *overlay; + LONG w, h;
-static ULONG texture_resource_incref(struct wined3d_resource *resource) -{ - return wined3d_texture_incref(texture_from_resource(resource)); -} + TRACE("texture %p, sub_resource_idx %u, x %ld, y %ld.\n", texture, sub_resource_idx, x, y);
-static ULONG texture_resource_decref(struct wined3d_resource *resource) -{ - return wined3d_texture_decref(texture_from_resource(resource)); -} + if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY) + || !wined3d_texture_validate_sub_resource_idx(texture, sub_resource_idx)) + return WINEDDERR_NOTAOVERLAYSURFACE;
-static void texture_resource_preload(struct wined3d_resource *resource) -{ - struct wined3d_texture *texture = texture_from_resource(resource); - struct wined3d_context *context; + overlay = &texture->overlay_info[sub_resource_idx]; + w = overlay->dst_rect.right - overlay->dst_rect.left; + h = overlay->dst_rect.bottom - overlay->dst_rect.top; + SetRect(&overlay->dst_rect, x, y, x + w, y + h);
- context = context_acquire(resource->device, NULL, 0); - wined3d_texture_load(texture, context, texture->flags & WINED3D_TEXTURE_IS_SRGB); - context_release(context); + return WINED3D_OK; }
-static void texture_resource_unload(struct wined3d_resource *resource) +HRESULT CDECL wined3d_texture_update_overlay(struct wined3d_texture *texture, unsigned int sub_resource_idx, + const RECT *src_rect, struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, + const RECT *dst_rect, uint32_t flags) { - struct wined3d_texture *texture = texture_from_resource(resource); - struct wined3d_device *device = resource->device; - unsigned int location = resource->map_binding; - struct wined3d_context *context; - unsigned int sub_count, i; - - TRACE("resource %p.\n", resource); + struct wined3d_overlay_info *overlay; + unsigned int level, dst_level;
- /* D3D is not initialised, so no GPU locations should currently exist. - * Moreover, we may not be able to acquire a valid context. */ - if (!device->d3d_initialized) - return; + TRACE("texture %p, sub_resource_idx %u, src_rect %s, dst_texture %p, " + "dst_sub_resource_idx %u, dst_rect %s, flags %#x.\n", + texture, sub_resource_idx, wine_dbgstr_rect(src_rect), dst_texture, + dst_sub_resource_idx, wine_dbgstr_rect(dst_rect), flags);
- context = context_acquire(device, NULL, 0); + if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY) || texture->resource.type != WINED3D_RTYPE_TEXTURE_2D + || !wined3d_texture_validate_sub_resource_idx(texture, sub_resource_idx)) + return WINEDDERR_NOTAOVERLAYSURFACE;
- if (location == WINED3D_LOCATION_BUFFER) - location = WINED3D_LOCATION_SYSMEM; + if (!dst_texture || dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D + || !wined3d_texture_validate_sub_resource_idx(dst_texture, dst_sub_resource_idx)) + return WINED3DERR_INVALIDCALL;
- sub_count = texture->level_count * texture->layer_count; - for (i = 0; i < sub_count; ++i) + overlay = &texture->overlay_info[sub_resource_idx]; + + level = sub_resource_idx % texture->level_count; + if (src_rect) + overlay->src_rect = *src_rect; + else + SetRect(&overlay->src_rect, 0, 0, + wined3d_texture_get_level_width(texture, level), + wined3d_texture_get_level_height(texture, level)); + + dst_level = dst_sub_resource_idx % dst_texture->level_count; + if (dst_rect) + overlay->dst_rect = *dst_rect; + else + SetRect(&overlay->dst_rect, 0, 0, + wined3d_texture_get_level_width(dst_texture, dst_level), + wined3d_texture_get_level_height(dst_texture, dst_level)); + + if (overlay->dst_texture && (overlay->dst_texture != dst_texture + || overlay->dst_sub_resource_idx != dst_sub_resource_idx || flags & WINEDDOVER_HIDE)) { - if (resource->access & WINED3D_RESOURCE_ACCESS_CPU - && wined3d_texture_load_location(texture, i, context, location)) - { - wined3d_texture_invalidate_location(texture, i, ~location); - } - else + overlay->dst_texture = NULL; + list_remove(&overlay->entry); + } + + if (flags & WINEDDOVER_SHOW) + { + if (overlay->dst_texture != dst_texture || overlay->dst_sub_resource_idx != dst_sub_resource_idx) { - if (resource->access & WINED3D_RESOURCE_ACCESS_CPU) - ERR("Discarding %s %p sub-resource %u with resource access %s.\n", - debug_d3dresourcetype(resource->type), resource, i, - wined3d_debug_resource_access(resource->access)); - wined3d_texture_validate_location(texture, i, WINED3D_LOCATION_DISCARDED); - wined3d_texture_invalidate_location(texture, i, ~WINED3D_LOCATION_DISCARDED); + overlay->dst_texture = dst_texture; + overlay->dst_sub_resource_idx = dst_sub_resource_idx; + list_add_tail(&texture->overlay_info[dst_sub_resource_idx].overlays, &overlay->entry); } } + else if (flags & WINEDDOVER_HIDE) + { + /* Tests show that the rectangles are erased on hide. */ + SetRectEmpty(&overlay->src_rect); + SetRectEmpty(&overlay->dst_rect); + overlay->dst_texture = NULL; + }
- wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_BUFFER); - wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_TEXTURE_RGB); - wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_TEXTURE_SRGB); - wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_RB_MULTISAMPLE); - wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_RB_RESOLVED); - - context_release(context); + return WINED3D_OK; +}
- wined3d_texture_force_reload(texture); +struct wined3d_swapchain * CDECL wined3d_texture_get_swapchain(struct wined3d_texture *texture) +{ + return texture->swapchain; +}
- if (texture->resource.bind_count && (texture->resource.bind_flags & WINED3D_BIND_SHADER_RESOURCE)) - device_invalidate_state(device, STATE_GRAPHICS_SHADER_RESOURCE_BINDING); +void * CDECL wined3d_texture_get_sub_resource_parent(struct wined3d_texture *texture, unsigned int sub_resource_idx) +{ + TRACE("texture %p, sub_resource_idx %u.\n", texture, sub_resource_idx);
- wined3d_texture_set_dirty(texture); + if (!wined3d_texture_validate_sub_resource_idx(texture, sub_resource_idx)) + return NULL;
- resource_unload(&texture->resource); + return texture->sub_resources[sub_resource_idx].parent; }
-static unsigned int texture_resource_get_sub_resource_count(struct wined3d_resource *resource) +void CDECL wined3d_texture_set_sub_resource_parent(struct wined3d_texture *texture, + unsigned int sub_resource_idx, void *parent, const struct wined3d_parent_ops *parent_ops) { - const struct wined3d_texture *texture = texture_from_resource(resource); + TRACE("texture %p, sub_resource_idx %u, parent %p.\n", texture, sub_resource_idx, parent);
- return texture->level_count * texture->layer_count; + if (!wined3d_texture_validate_sub_resource_idx(texture, sub_resource_idx)) + return; + + texture->sub_resources[sub_resource_idx].parent = parent; + texture->sub_resources[sub_resource_idx].parent_ops = parent_ops; }
-static HRESULT texture_resource_sub_resource_get_desc(struct wined3d_resource *resource, +HRESULT CDECL wined3d_texture_get_sub_resource_desc(const struct wined3d_texture *texture, unsigned int sub_resource_idx, struct wined3d_sub_resource_desc *desc) { - const struct wined3d_texture *texture = texture_from_resource(resource); + const struct wined3d_resource *resource; + unsigned int level_idx;
- return wined3d_texture_get_sub_resource_desc(texture, sub_resource_idx, desc); -} + TRACE("texture %p, sub_resource_idx %u, desc %p.\n", texture, sub_resource_idx, desc);
-static void texture_resource_sub_resource_get_map_pitch(struct wined3d_resource *resource, - unsigned int sub_resource_idx, unsigned int *row_pitch, unsigned int *slice_pitch) -{ - const struct wined3d_texture *texture = texture_from_resource(resource); - unsigned int level = sub_resource_idx % texture->level_count; + if (!wined3d_texture_validate_sub_resource_idx(texture, sub_resource_idx)) + return WINED3DERR_INVALIDCALL;
- if (resource->format_attrs & WINED3D_FORMAT_ATTR_BROKEN_PITCH) - { - *row_pitch = wined3d_texture_get_level_width(texture, level) * resource->format->byte_count; - *slice_pitch = wined3d_texture_get_level_height(texture, level) * (*row_pitch); - } - else - { - wined3d_texture_get_pitch(texture, level, row_pitch, slice_pitch); - } -} + resource = &texture->resource; + desc->format = resource->format->id; + desc->multisample_type = resource->multisample_type; + desc->multisample_quality = resource->multisample_quality; + desc->usage = resource->usage; + desc->bind_flags = resource->bind_flags; + desc->access = resource->access;
-static HRESULT texture_resource_sub_resource_map(struct wined3d_resource *resource, unsigned int sub_resource_idx, - void **map_ptr, const struct wined3d_box *box, uint32_t flags) -{ - struct wined3d_texture_sub_resource *sub_resource; - struct wined3d_device *device = resource->device; - struct wined3d_context *context; - struct wined3d_texture *texture; - struct wined3d_bo_address data; - unsigned int texture_level; - BYTE *base_memory; - BOOL ret = TRUE; + level_idx = sub_resource_idx % texture->level_count; + desc->width = wined3d_texture_get_level_width(texture, level_idx); + desc->height = wined3d_texture_get_level_height(texture, level_idx); + desc->depth = wined3d_texture_get_level_depth(texture, level_idx); + desc->size = texture->sub_resources[sub_resource_idx].size;
- TRACE("resource %p, sub_resource_idx %u, map_ptr %p, box %s, flags %#x.\n", - resource, sub_resource_idx, map_ptr, debug_box(box), flags); + return WINED3D_OK; +}
- texture = texture_from_resource(resource); - sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx); +HRESULT CDECL wined3d_texture_create(struct wined3d_device *device, const struct wined3d_resource_desc *desc, + UINT layer_count, UINT level_count, uint32_t flags, const struct wined3d_sub_resource_data *data, + void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture) +{ + unsigned int sub_count = level_count * layer_count; + unsigned int i; + HRESULT hr;
- texture_level = sub_resource_idx % texture->level_count; + TRACE("device %p, desc %p, layer_count %u, level_count %u, flags %#x, data %p, " + "parent %p, parent_ops %p, texture %p.\n", + device, desc, layer_count, level_count, flags, data, parent, parent_ops, texture);
- if (texture->flags & WINED3D_TEXTURE_DC_IN_USE) + if (!layer_count) { - WARN("DC is in use.\n"); - return WINED3DERR_INVALIDCALL; + WARN("Invalid layer count.\n"); + return E_INVALIDARG; } - - if (sub_resource->map_count) + if ((desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP) && layer_count != 6) { - WARN("Sub-resource is already mapped.\n"); - return WINED3DERR_INVALIDCALL; + ERR("Invalid layer count %u for legacy cubemap.\n", layer_count); + layer_count = 6; }
- context = context_acquire(device, NULL, 0); - - if (flags & WINED3D_MAP_DISCARD) + if (!level_count) { - TRACE("WINED3D_MAP_DISCARD flag passed, marking %s as up to date.\n", - wined3d_debug_location(resource->map_binding)); - if ((ret = wined3d_texture_prepare_location(texture, sub_resource_idx, context, resource->map_binding))) - wined3d_texture_validate_location(texture, sub_resource_idx, resource->map_binding); + WARN("Invalid level count.\n"); + return WINED3DERR_INVALIDCALL; } - else + + if (desc->multisample_type != WINED3D_MULTISAMPLE_NONE) { - if (resource->usage & WINED3DUSAGE_DYNAMIC) - WARN_(d3d_perf)("Mapping a dynamic texture without WINED3D_MAP_DISCARD.\n"); - if (!texture_level) - { - unsigned int i; + const struct wined3d_format *format = wined3d_get_format(device->adapter, desc->format, desc->bind_flags);
- for (i = 0; i < texture->level_count; ++i) - { - if (!(ret = wined3d_texture_load_location(texture, sub_resource_idx + i, context, resource->map_binding))) - break; - } + if (desc->multisample_type == WINED3D_MULTISAMPLE_NON_MASKABLE + && desc->multisample_quality >= wined3d_popcount(format->multisample_types)) + { + WARN("Unsupported quality level %u requested for WINED3D_MULTISAMPLE_NON_MASKABLE.\n", + desc->multisample_quality); + return WINED3DERR_NOTAVAILABLE; } - else + if (desc->multisample_type != WINED3D_MULTISAMPLE_NON_MASKABLE + && (!(format->multisample_types & 1u << (desc->multisample_type - 1)) + || (desc->multisample_quality && desc->multisample_quality != WINED3D_STANDARD_MULTISAMPLE_PATTERN))) { - ret = wined3d_texture_load_location(texture, sub_resource_idx, context, resource->map_binding); + WARN("Unsupported multisample type %u quality %u requested.\n", desc->multisample_type, + desc->multisample_quality); + return WINED3DERR_NOTAVAILABLE; } }
- if (!ret) + if (data) { - ERR("Failed to prepare location.\n"); - context_release(context); - return E_OUTOFMEMORY; + for (i = 0; i < sub_count; ++i) + { + if (data[i].data) + continue; + + WARN("Invalid sub-resource data specified for sub-resource %u.\n", i); + return E_INVALIDARG; + } }
- /* We only record dirty regions for the top-most level. */ - if (texture->dirty_regions && flags & WINED3D_MAP_WRITE - && !(flags & WINED3D_MAP_NO_DIRTY_UPDATE) && !texture_level) - wined3d_texture_dirty_region_add(texture, sub_resource_idx / texture->level_count, box); + if (FAILED(hr = device->adapter->adapter_ops->adapter_create_texture(device, desc, + layer_count, level_count, flags, parent, parent_ops, texture))) + return hr;
- if (flags & WINED3D_MAP_WRITE) + /* FIXME: We'd like to avoid ever allocating system memory for the texture + * in this case. */ + if (data) { - if (!texture_level) - { - unsigned int i; + struct wined3d_box box;
- for (i = 0; i < texture->level_count; ++i) - wined3d_texture_invalidate_location(texture, sub_resource_idx + i, ~resource->map_binding); - } - else + for (i = 0; i < sub_count; ++i) { - wined3d_texture_invalidate_location(texture, sub_resource_idx, ~resource->map_binding); + wined3d_texture_get_level_box(*texture, i % (*texture)->level_count, &box); + wined3d_device_context_emit_update_sub_resource(&device->cs->c, &(*texture)->resource, + i, &box, data[i].data, data[i].row_pitch, data[i].slice_pitch); } }
- wined3d_texture_get_bo_address(texture, sub_resource_idx, &data, resource->map_binding); - base_memory = wined3d_context_map_bo_address(context, &data, sub_resource->size, flags); - sub_resource->map_flags = flags; - TRACE("Base memory pointer %p.\n", base_memory); + TRACE("Created texture %p.\n", *texture);
- context_release(context); + return WINED3D_OK; +}
- *map_ptr = resource_offset_map_pointer(resource, sub_resource_idx, base_memory, box); - - if (texture->swapchain && texture->swapchain->front_buffer == texture) - { - RECT *r = &texture->swapchain->front_buffer_update; - - SetRect(r, box->left, box->top, box->right, box->bottom); - TRACE("Mapped front buffer %s.\n", wine_dbgstr_rect(r)); - } - - ++resource->map_count; - ++sub_resource->map_count; - - TRACE("Returning memory %p.\n", *map_ptr); - - return WINED3D_OK; -} - -static HRESULT texture_resource_sub_resource_unmap(struct wined3d_resource *resource, unsigned int sub_resource_idx) -{ - struct wined3d_texture_sub_resource *sub_resource; - struct wined3d_device *device = resource->device; - struct wined3d_context *context; - struct wined3d_texture *texture; - struct wined3d_bo_address data; - struct wined3d_range range; - - TRACE("resource %p, sub_resource_idx %u.\n", resource, sub_resource_idx); - - texture = texture_from_resource(resource); - if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx))) - return E_INVALIDARG; - - if (!sub_resource->map_count) - { - WARN("Trying to unmap unmapped sub-resource.\n"); - if (texture->flags & WINED3D_TEXTURE_DC_IN_USE) - return WINED3D_OK; - return WINEDDERR_NOTLOCKED; - } - - context = context_acquire(device, NULL, 0); - - wined3d_texture_get_bo_address(texture, sub_resource_idx, &data, texture->resource.map_binding); - range.offset = 0; - range.size = sub_resource->size; - wined3d_context_unmap_bo_address(context, &data, !!(sub_resource->map_flags & WINED3D_MAP_WRITE), &range); - - context_release(context); - - if (texture->swapchain && texture->swapchain->front_buffer == texture) - { - if (!(sub_resource->locations & (WINED3D_LOCATION_DRAWABLE | WINED3D_LOCATION_TEXTURE_RGB))) - texture->swapchain->swapchain_ops->swapchain_frontbuffer_updated(texture->swapchain); - } - - --sub_resource->map_count; - if (!--resource->map_count && texture->update_map_binding) - wined3d_texture_update_map_binding(texture); - - return WINED3D_OK; -} - -static const struct wined3d_resource_ops texture_resource_ops = -{ - texture_resource_incref, - texture_resource_decref, - texture_resource_preload, - texture_resource_unload, - texture_resource_get_sub_resource_count, - texture_resource_sub_resource_get_desc, - texture_resource_sub_resource_get_map_pitch, - texture_resource_sub_resource_map, - texture_resource_sub_resource_unmap, -}; - -static HRESULT wined3d_texture_init(struct wined3d_texture *texture, const struct wined3d_resource_desc *desc, - unsigned int layer_count, unsigned int level_count, uint32_t flags, struct wined3d_device *device, - void *parent, const struct wined3d_parent_ops *parent_ops, void *sub_resources, - const struct wined3d_texture_ops *texture_ops) -{ - const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info; - struct wined3d_device_parent *device_parent = device->device_parent; - unsigned int sub_count, i, j, size, offset = 0; - const struct wined3d_format *format; - HRESULT hr; - - TRACE("texture %p, resource_type %s, format %s, multisample_type %#x, multisample_quality %#x, " - "usage %s, bind_flags %s, access %s, width %u, height %u, depth %u, layer_count %u, level_count %u, " - "flags %#x, device %p, parent %p, parent_ops %p, sub_resources %p, texture_ops %p.\n", - texture, debug_d3dresourcetype(desc->resource_type), debug_d3dformat(desc->format), desc->multisample_type, - desc->multisample_quality, debug_d3dusage(desc->usage), wined3d_debug_bind_flags(desc->bind_flags), - wined3d_debug_resource_access(desc->access), desc->width, desc->height, desc->depth, - layer_count, level_count, flags, device, parent, parent_ops, sub_resources, texture_ops); - - if (!desc->width || !desc->height || !desc->depth) - return WINED3DERR_INVALIDCALL; - - if (desc->resource_type == WINED3D_RTYPE_TEXTURE_3D && layer_count != 1) - { - ERR("Invalid layer count for volume texture.\n"); - return E_INVALIDARG; - } - - texture->sub_resources = sub_resources; - - /* TODO: It should only be possible to create textures for formats - * that are reported as supported. */ - if (WINED3DFMT_UNKNOWN >= desc->format) - { - WARN("Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n"); - return WINED3DERR_INVALIDCALL; - } - format = wined3d_get_format(device->adapter, desc->format, desc->bind_flags); - - if ((desc->usage & WINED3DUSAGE_DYNAMIC) && (desc->usage & (WINED3DUSAGE_MANAGED | WINED3DUSAGE_SCRATCH))) - { - WARN("Attempted to create a dynamic texture with usage %s.\n", debug_d3dusage(desc->usage)); - return WINED3DERR_INVALIDCALL; - } - - if (((desc->width & (desc->width - 1)) || (desc->height & (desc->height - 1)) || (desc->depth & (desc->depth - 1))) - && !d3d_info->unconditional_npot) - { - /* level_count == 0 returns an error as well. */ - if (level_count != 1 || layer_count != 1 || desc->resource_type == WINED3D_RTYPE_TEXTURE_3D) - { - if (!(desc->usage & WINED3DUSAGE_SCRATCH)) - { - WARN("Attempted to create a mipmapped/cube/array/volume NPOT " - "texture without unconditional NPOT support.\n"); - return WINED3DERR_INVALIDCALL; - } - - WARN("Creating a scratch mipmapped/cube/array NPOT texture despite lack of HW support.\n"); - } - texture->flags |= WINED3D_TEXTURE_COND_NP2; - } - - if ((desc->width > d3d_info->limits.texture_size || desc->height > d3d_info->limits.texture_size) - && (desc->bind_flags & WINED3D_BIND_SHADER_RESOURCE)) - { - /* One of four options: - * 1: Scale the texture. (Any texture ops would require the texture to - * be scaled which is potentially slow.) - * 2: Set the texture to the maximum size (bad idea). - * 3: WARN and return WINED3DERR_NOTAVAILABLE. - * 4: Create the surface, but allow it to be used only for DirectDraw - * Blts. Some apps (e.g. Swat 3) create textures with a height of - * 16 and a width > 3000 and blt 16x16 letter areas from them to - * the render target. */ - if (desc->access & WINED3D_RESOURCE_ACCESS_GPU) - { - WARN("Dimensions (%ux%u) exceed the maximum texture size.\n", desc->width, desc->height); - return WINED3DERR_NOTAVAILABLE; - } - - /* We should never use this surface in combination with OpenGL. */ - TRACE("Creating an oversized (%ux%u) surface.\n", desc->width, desc->height); - } - - if ((format->attrs & WINED3D_FORMAT_ATTR_PLANAR) && ((desc->width & 1) || (desc->height & 1))) - { - WARN("Attempt to create a planar texture with unaligned size %ux%u.\n", desc->width, desc->height); - return WINED3DERR_INVALIDCALL; - } - - for (i = 0; i < layer_count; ++i) - { - for (j = 0; j < level_count; ++j) - { - unsigned int idx = i * level_count + j; - - size = wined3d_format_calculate_size(format, device->surface_alignment, - max(1, desc->width >> j), max(1, desc->height >> j), max(1, desc->depth >> j)); - texture->sub_resources[idx].offset = offset; - texture->sub_resources[idx].size = size; - offset += size; - } - offset = (offset + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1); - } - - if (!offset) - return WINED3DERR_INVALIDCALL; - - /* Ensure the last mip-level is at least large enough to hold a single - * compressed block. It is questionable how useful these mip-levels are to - * the application with "broken pitch" formats, but we want to avoid - * memory corruption when loading textures into WINED3D_LOCATION_SYSMEM. */ - if (format->attrs & WINED3D_FORMAT_ATTR_BROKEN_PITCH) - { - unsigned int min_size; - - min_size = texture->sub_resources[level_count * layer_count - 1].offset + format->block_byte_count; - min_size = (min_size + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1); - if (min_size > offset) - offset = min_size; - } - - if (FAILED(hr = resource_init(&texture->resource, device, desc->resource_type, format, - desc->multisample_type, desc->multisample_quality, desc->usage, desc->bind_flags, desc->access, - desc->width, desc->height, desc->depth, offset, parent, parent_ops, &texture_resource_ops))) - { - static unsigned int once; - - /* DXTn 3D textures are not supported. Do not write the ERR for them. */ - if ((desc->format == WINED3DFMT_DXT1 || desc->format == WINED3DFMT_DXT2 || desc->format == WINED3DFMT_DXT3 - || desc->format == WINED3DFMT_DXT4 || desc->format == WINED3DFMT_DXT5) - && !(format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_TEXTURE) - && desc->resource_type != WINED3D_RTYPE_TEXTURE_3D && !once++) - ERR_(winediag)("The application tried to create a DXTn texture, but the driver does not support them.\n"); - - WARN("Failed to initialize resource, returning %#lx\n", hr); - return hr; - } - wined3d_resource_update_draw_binding(&texture->resource); - - texture->texture_ops = texture_ops; - - texture->layer_count = layer_count; - texture->level_count = level_count; - texture->lod = 0; - texture->flags |= WINED3D_TEXTURE_DOWNLOADABLE; - if (flags & WINED3D_TEXTURE_CREATE_GET_DC_LENIENT) - { - texture->flags |= WINED3D_TEXTURE_GET_DC_LENIENT; - texture->resource.pin_sysmem = 1; - } - if (flags & (WINED3D_TEXTURE_CREATE_GET_DC | WINED3D_TEXTURE_CREATE_GET_DC_LENIENT)) - texture->flags |= WINED3D_TEXTURE_GET_DC; - if (flags & WINED3D_TEXTURE_CREATE_DISCARD) - texture->flags |= WINED3D_TEXTURE_DISCARD; - if (flags & WINED3D_TEXTURE_CREATE_GENERATE_MIPMAPS) - { - if (!(texture->resource.format_caps & WINED3D_FORMAT_CAP_GEN_MIPMAP)) - WARN("Format doesn't support mipmaps generation, " - "ignoring WINED3D_TEXTURE_CREATE_GENERATE_MIPMAPS flag.\n"); - else - texture->flags |= WINED3D_TEXTURE_GENERATE_MIPMAPS; - } - - if (flags & WINED3D_TEXTURE_CREATE_RECORD_DIRTY_REGIONS) - { - if (!(texture->dirty_regions = calloc(texture->layer_count, sizeof(*texture->dirty_regions)))) - { - wined3d_texture_cleanup_sync(texture); - return E_OUTOFMEMORY; - } - for (i = 0; i < texture->layer_count; ++i) - wined3d_texture_dirty_region_add(texture, i, NULL); - } - - if (wined3d_texture_use_pbo(texture, d3d_info)) - texture->resource.map_binding = WINED3D_LOCATION_BUFFER; - - sub_count = level_count * layer_count; - if (sub_count / layer_count != level_count) - { - wined3d_texture_cleanup_sync(texture); - return E_OUTOFMEMORY; - } - - if (desc->usage & WINED3DUSAGE_OVERLAY) - { - if (!(texture->overlay_info = calloc(sub_count, sizeof(*texture->overlay_info)))) - { - wined3d_texture_cleanup_sync(texture); - return E_OUTOFMEMORY; - } - - for (i = 0; i < sub_count; ++i) - { - list_init(&texture->overlay_info[i].entry); - list_init(&texture->overlay_info[i].overlays); - } - } - - /* Generate all sub-resources. */ - for (i = 0; i < sub_count; ++i) - { - struct wined3d_texture_sub_resource *sub_resource; - - sub_resource = &texture->sub_resources[i]; - sub_resource->locations = WINED3D_LOCATION_CLEARED; - - if (FAILED(hr = device_parent->ops->texture_sub_resource_created(device_parent, - desc->resource_type, texture, i, &sub_resource->parent, &sub_resource->parent_ops))) - { - WARN("Failed to create sub-resource parent, hr %#lx.\n", hr); - sub_resource->parent = NULL; - wined3d_texture_cleanup_sync(texture); - return hr; - } - - TRACE("parent %p, parent_ops %p.\n", sub_resource->parent, sub_resource->parent_ops); - - TRACE("Created sub-resource %u (level %u, layer %u).\n", - i, i % texture->level_count, i / texture->level_count); - - if (desc->usage & WINED3DUSAGE_OWNDC) - { - struct wined3d_texture_idx texture_idx = {texture, i}; - - wined3d_cs_init_object(device->cs, wined3d_texture_create_dc, &texture_idx); - wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT); - if (!texture->dc_info || !texture->dc_info[i].dc) - { - wined3d_texture_cleanup_sync(texture); - return WINED3DERR_INVALIDCALL; - } - } - } - - return WINED3D_OK; -} - -HRESULT CDECL wined3d_device_context_blt(struct wined3d_device_context *context, - struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, const RECT *dst_rect, - struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, const RECT *src_rect, - unsigned int flags, const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter) -{ - struct wined3d_box src_box = {src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1}; - struct wined3d_box dst_box = {dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, 0, 1}; - HRESULT hr; - - TRACE("context %p, dst_texture %p, dst_sub_resource_idx %u, dst_rect %s, src_texture %p, " - "src_sub_resource_idx %u, src_rect %s, flags %#x, fx %p, filter %s.\n", - context, dst_texture, dst_sub_resource_idx, wine_dbgstr_rect(dst_rect), src_texture, - src_sub_resource_idx, wine_dbgstr_rect(src_rect), flags, fx, debug_d3dtexturefiltertype(filter)); - - if (!wined3d_texture_validate_sub_resource_idx(dst_texture, dst_sub_resource_idx) - || dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D) - return WINED3DERR_INVALIDCALL; - - if (!wined3d_texture_validate_sub_resource_idx(src_texture, src_sub_resource_idx) - || src_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D) - return WINED3DERR_INVALIDCALL; - - if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT - && filter != WINED3D_TEXF_LINEAR) - return WINED3DERR_INVALIDCALL; - - if (FAILED(hr = wined3d_resource_check_box_dimensions(&dst_texture->resource, dst_sub_resource_idx, &dst_box))) - return hr; - - if (FAILED(hr = wined3d_resource_check_box_dimensions(&src_texture->resource, src_sub_resource_idx, &src_box))) - return hr; - - if (dst_texture->sub_resources[dst_sub_resource_idx].map_count - || src_texture->sub_resources[src_sub_resource_idx].map_count) - { - WARN("Sub-resource is busy, returning WINEDDERR_SURFACEBUSY.\n"); - return WINEDDERR_SURFACEBUSY; - } - - if (!src_texture->resource.format->depth_size != !dst_texture->resource.format->depth_size - || !src_texture->resource.format->stencil_size != !dst_texture->resource.format->stencil_size) - { - WARN("Rejecting depth/stencil blit between incompatible formats.\n"); - return WINED3DERR_INVALIDCALL; - } - - if (dst_texture->resource.device != src_texture->resource.device) - { - FIXME("Rejecting cross-device blit.\n"); - return E_NOTIMPL; - } - - wined3d_device_context_emit_blt_sub_resource(context, &dst_texture->resource, dst_sub_resource_idx, - &dst_box, &src_texture->resource, src_sub_resource_idx, &src_box, flags, fx, filter); - - if (dst_texture->dirty_regions) - wined3d_texture_add_dirty_region(dst_texture, dst_sub_resource_idx, &dst_box); - - return WINED3D_OK; -} - -HRESULT CDECL wined3d_texture_get_overlay_position(const struct wined3d_texture *texture, - unsigned int sub_resource_idx, LONG *x, LONG *y) -{ - struct wined3d_overlay_info *overlay; - - TRACE("texture %p, sub_resource_idx %u, x %p, y %p.\n", texture, sub_resource_idx, x, y); - - if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY) - || !wined3d_texture_validate_sub_resource_idx(texture, sub_resource_idx)) - return WINEDDERR_NOTAOVERLAYSURFACE; - - overlay = &texture->overlay_info[sub_resource_idx]; - if (!overlay->dst_texture) - { - TRACE("Overlay not visible.\n"); - *x = 0; - *y = 0; - return WINEDDERR_OVERLAYNOTVISIBLE; - } - - *x = overlay->dst_rect.left; - *y = overlay->dst_rect.top; - - TRACE("Returning position %ld, %ld.\n", *x, *y); - - return WINED3D_OK; -} - -HRESULT CDECL wined3d_texture_set_overlay_position(struct wined3d_texture *texture, - unsigned int sub_resource_idx, LONG x, LONG y) -{ - struct wined3d_overlay_info *overlay; - LONG w, h; - - TRACE("texture %p, sub_resource_idx %u, x %ld, y %ld.\n", texture, sub_resource_idx, x, y); - - if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY) - || !wined3d_texture_validate_sub_resource_idx(texture, sub_resource_idx)) - return WINEDDERR_NOTAOVERLAYSURFACE; - - overlay = &texture->overlay_info[sub_resource_idx]; - w = overlay->dst_rect.right - overlay->dst_rect.left; - h = overlay->dst_rect.bottom - overlay->dst_rect.top; - SetRect(&overlay->dst_rect, x, y, x + w, y + h); - - return WINED3D_OK; -} - -HRESULT CDECL wined3d_texture_update_overlay(struct wined3d_texture *texture, unsigned int sub_resource_idx, - const RECT *src_rect, struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, - const RECT *dst_rect, uint32_t flags) -{ - struct wined3d_overlay_info *overlay; - unsigned int level, dst_level; - - TRACE("texture %p, sub_resource_idx %u, src_rect %s, dst_texture %p, " - "dst_sub_resource_idx %u, dst_rect %s, flags %#x.\n", - texture, sub_resource_idx, wine_dbgstr_rect(src_rect), dst_texture, - dst_sub_resource_idx, wine_dbgstr_rect(dst_rect), flags); - - if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY) || texture->resource.type != WINED3D_RTYPE_TEXTURE_2D - || !wined3d_texture_validate_sub_resource_idx(texture, sub_resource_idx)) - return WINEDDERR_NOTAOVERLAYSURFACE; - - if (!dst_texture || dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D - || !wined3d_texture_validate_sub_resource_idx(dst_texture, dst_sub_resource_idx)) - return WINED3DERR_INVALIDCALL; - - overlay = &texture->overlay_info[sub_resource_idx]; - - level = sub_resource_idx % texture->level_count; - if (src_rect) - overlay->src_rect = *src_rect; - else - SetRect(&overlay->src_rect, 0, 0, - wined3d_texture_get_level_width(texture, level), - wined3d_texture_get_level_height(texture, level)); - - dst_level = dst_sub_resource_idx % dst_texture->level_count; - if (dst_rect) - overlay->dst_rect = *dst_rect; - else - SetRect(&overlay->dst_rect, 0, 0, - wined3d_texture_get_level_width(dst_texture, dst_level), - wined3d_texture_get_level_height(dst_texture, dst_level)); - - if (overlay->dst_texture && (overlay->dst_texture != dst_texture - || overlay->dst_sub_resource_idx != dst_sub_resource_idx || flags & WINEDDOVER_HIDE)) - { - overlay->dst_texture = NULL; - list_remove(&overlay->entry); - } - - if (flags & WINEDDOVER_SHOW) - { - if (overlay->dst_texture != dst_texture || overlay->dst_sub_resource_idx != dst_sub_resource_idx) - { - overlay->dst_texture = dst_texture; - overlay->dst_sub_resource_idx = dst_sub_resource_idx; - list_add_tail(&texture->overlay_info[dst_sub_resource_idx].overlays, &overlay->entry); - } - } - else if (flags & WINEDDOVER_HIDE) - { - /* Tests show that the rectangles are erased on hide. */ - SetRectEmpty(&overlay->src_rect); - SetRectEmpty(&overlay->dst_rect); - overlay->dst_texture = NULL; - } - - return WINED3D_OK; -} - -struct wined3d_swapchain * CDECL wined3d_texture_get_swapchain(struct wined3d_texture *texture) -{ - return texture->swapchain; -} - -void * CDECL wined3d_texture_get_sub_resource_parent(struct wined3d_texture *texture, unsigned int sub_resource_idx) -{ - TRACE("texture %p, sub_resource_idx %u.\n", texture, sub_resource_idx); - - if (!wined3d_texture_validate_sub_resource_idx(texture, sub_resource_idx)) - return NULL; - - return texture->sub_resources[sub_resource_idx].parent; -} - -void CDECL wined3d_texture_set_sub_resource_parent(struct wined3d_texture *texture, - unsigned int sub_resource_idx, void *parent, const struct wined3d_parent_ops *parent_ops) -{ - TRACE("texture %p, sub_resource_idx %u, parent %p.\n", texture, sub_resource_idx, parent); - - if (!wined3d_texture_validate_sub_resource_idx(texture, sub_resource_idx)) - return; - - texture->sub_resources[sub_resource_idx].parent = parent; - texture->sub_resources[sub_resource_idx].parent_ops = parent_ops; -} - -HRESULT CDECL wined3d_texture_get_sub_resource_desc(const struct wined3d_texture *texture, - unsigned int sub_resource_idx, struct wined3d_sub_resource_desc *desc) -{ - const struct wined3d_resource *resource; - unsigned int level_idx; - - TRACE("texture %p, sub_resource_idx %u, desc %p.\n", texture, sub_resource_idx, desc); - - if (!wined3d_texture_validate_sub_resource_idx(texture, sub_resource_idx)) - return WINED3DERR_INVALIDCALL; - - resource = &texture->resource; - desc->format = resource->format->id; - desc->multisample_type = resource->multisample_type; - desc->multisample_quality = resource->multisample_quality; - desc->usage = resource->usage; - desc->bind_flags = resource->bind_flags; - desc->access = resource->access; - - level_idx = sub_resource_idx % texture->level_count; - desc->width = wined3d_texture_get_level_width(texture, level_idx); - desc->height = wined3d_texture_get_level_height(texture, level_idx); - desc->depth = wined3d_texture_get_level_depth(texture, level_idx); - desc->size = texture->sub_resources[sub_resource_idx].size; - - return WINED3D_OK; -} - -HRESULT wined3d_texture_gl_init(struct wined3d_texture_gl *texture_gl, struct wined3d_device *device, - const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count, - uint32_t flags, void *parent, const struct wined3d_parent_ops *parent_ops) -{ - const struct wined3d_gl_info *gl_info = &wined3d_adapter_gl(device->adapter)->gl_info; - HRESULT hr; - - TRACE("texture_gl %p, device %p, desc %p, layer_count %u, " - "level_count %u, flags %#x, parent %p, parent_ops %p.\n", - texture_gl, device, desc, layer_count, - level_count, flags, parent, parent_ops); - - if (!(desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP) && layer_count > 1 - && !gl_info->supported[EXT_TEXTURE_ARRAY]) - { - WARN("OpenGL implementation does not support array textures.\n"); - return WINED3DERR_INVALIDCALL; - } - - switch (desc->resource_type) - { - case WINED3D_RTYPE_TEXTURE_1D: - if (layer_count > 1) - texture_gl->target = GL_TEXTURE_1D_ARRAY; - else - texture_gl->target = GL_TEXTURE_1D; - break; - - case WINED3D_RTYPE_TEXTURE_2D: - if (desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP) - { - texture_gl->target = GL_TEXTURE_CUBE_MAP_ARB; - } - else if (desc->multisample_type && gl_info->supported[ARB_TEXTURE_MULTISAMPLE]) - { - if (layer_count > 1) - texture_gl->target = GL_TEXTURE_2D_MULTISAMPLE_ARRAY; - else - texture_gl->target = GL_TEXTURE_2D_MULTISAMPLE; - } - else - { - if (layer_count > 1) - texture_gl->target = GL_TEXTURE_2D_ARRAY; - else - texture_gl->target = GL_TEXTURE_2D; - } - break; - - case WINED3D_RTYPE_TEXTURE_3D: - if (!gl_info->supported[EXT_TEXTURE3D]) - { - WARN("OpenGL implementation does not support 3D textures.\n"); - return WINED3DERR_INVALIDCALL; - } - texture_gl->target = GL_TEXTURE_3D; - break; - - default: - ERR("Invalid resource type %s.\n", debug_d3dresourcetype(desc->resource_type)); - return WINED3DERR_INVALIDCALL; - } - - list_init(&texture_gl->renderbuffers); - - if (FAILED(hr = wined3d_texture_init(&texture_gl->t, desc, layer_count, level_count, - flags, device, parent, parent_ops, &texture_gl[1], &texture_gl_ops))) - return hr; - - if (texture_gl->target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY || texture_gl->target == GL_TEXTURE_2D_MULTISAMPLE) - texture_gl->t.flags &= ~WINED3D_TEXTURE_DOWNLOADABLE; - - return WINED3D_OK; -} - -HRESULT CDECL wined3d_texture_create(struct wined3d_device *device, const struct wined3d_resource_desc *desc, - UINT layer_count, UINT level_count, uint32_t flags, const struct wined3d_sub_resource_data *data, - void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture) -{ - unsigned int sub_count = level_count * layer_count; - unsigned int i; - HRESULT hr; - - TRACE("device %p, desc %p, layer_count %u, level_count %u, flags %#x, data %p, " - "parent %p, parent_ops %p, texture %p.\n", - device, desc, layer_count, level_count, flags, data, parent, parent_ops, texture); - - if (!layer_count) - { - WARN("Invalid layer count.\n"); - return E_INVALIDARG; - } - if ((desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP) && layer_count != 6) - { - ERR("Invalid layer count %u for legacy cubemap.\n", layer_count); - layer_count = 6; - } - - if (!level_count) - { - WARN("Invalid level count.\n"); - return WINED3DERR_INVALIDCALL; - } - - if (desc->multisample_type != WINED3D_MULTISAMPLE_NONE) - { - const struct wined3d_format *format = wined3d_get_format(device->adapter, desc->format, desc->bind_flags); - - if (desc->multisample_type == WINED3D_MULTISAMPLE_NON_MASKABLE - && desc->multisample_quality >= wined3d_popcount(format->multisample_types)) - { - WARN("Unsupported quality level %u requested for WINED3D_MULTISAMPLE_NON_MASKABLE.\n", - desc->multisample_quality); - return WINED3DERR_NOTAVAILABLE; - } - if (desc->multisample_type != WINED3D_MULTISAMPLE_NON_MASKABLE - && (!(format->multisample_types & 1u << (desc->multisample_type - 1)) - || (desc->multisample_quality && desc->multisample_quality != WINED3D_STANDARD_MULTISAMPLE_PATTERN))) - { - WARN("Unsupported multisample type %u quality %u requested.\n", desc->multisample_type, - desc->multisample_quality); - return WINED3DERR_NOTAVAILABLE; - } - } - - if (data) - { - for (i = 0; i < sub_count; ++i) - { - if (data[i].data) - continue; - - WARN("Invalid sub-resource data specified for sub-resource %u.\n", i); - return E_INVALIDARG; - } - } - - if (FAILED(hr = device->adapter->adapter_ops->adapter_create_texture(device, desc, - layer_count, level_count, flags, parent, parent_ops, texture))) - return hr; - - /* FIXME: We'd like to avoid ever allocating system memory for the texture - * in this case. */ - if (data) - { - struct wined3d_box box; - - for (i = 0; i < sub_count; ++i) - { - wined3d_texture_get_level_box(*texture, i % (*texture)->level_count, &box); - wined3d_device_context_emit_update_sub_resource(&device->cs->c, &(*texture)->resource, - i, &box, data[i].data, data[i].row_pitch, data[i].slice_pitch); - } - } - - TRACE("Created texture %p.\n", *texture); - - return WINED3D_OK; -} - -HRESULT CDECL wined3d_texture_get_dc(struct wined3d_texture *texture, unsigned int sub_resource_idx, HDC *dc) -{ - struct wined3d_device *device = texture->resource.device; - struct wined3d_texture_sub_resource *sub_resource; - struct wined3d_dc_info *dc_info; - - TRACE("texture %p, sub_resource_idx %u, dc %p.\n", texture, sub_resource_idx, dc); - - if (!(texture->flags & WINED3D_TEXTURE_GET_DC)) - { - WARN("Texture does not support GetDC\n"); - /* Don't touch the DC */ - return WINED3DERR_INVALIDCALL; - } - - if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx))) - return WINED3DERR_INVALIDCALL; - - if (texture->resource.type != WINED3D_RTYPE_TEXTURE_2D) - { - WARN("Not supported on %s resources.\n", debug_d3dresourcetype(texture->resource.type)); - return WINED3DERR_INVALIDCALL; - } - - if (texture->resource.map_count && !(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT)) - return WINED3DERR_INVALIDCALL; - - if (!(dc_info = texture->dc_info) || !dc_info[sub_resource_idx].dc) - { - struct wined3d_texture_idx texture_idx = {texture, sub_resource_idx}; - - wined3d_cs_init_object(device->cs, wined3d_texture_create_dc, &texture_idx); - wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT); - if (!(dc_info = texture->dc_info) || !dc_info[sub_resource_idx].dc) - return WINED3DERR_INVALIDCALL; - } - - if (!(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT)) - texture->flags |= WINED3D_TEXTURE_DC_IN_USE; - ++texture->resource.map_count; - ++sub_resource->map_count; - - *dc = dc_info[sub_resource_idx].dc; - TRACE("Returning dc %p.\n", *dc); - - return WINED3D_OK; -} - -HRESULT CDECL wined3d_texture_release_dc(struct wined3d_texture *texture, unsigned int sub_resource_idx, HDC dc) -{ - struct wined3d_device *device = texture->resource.device; - struct wined3d_texture_sub_resource *sub_resource; - struct wined3d_dc_info *dc_info; - - TRACE("texture %p, sub_resource_idx %u, dc %p.\n", texture, sub_resource_idx, dc); - - if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx))) - return WINED3DERR_INVALIDCALL; - - if (texture->resource.type != WINED3D_RTYPE_TEXTURE_2D) - { - WARN("Not supported on %s resources.\n", debug_d3dresourcetype(texture->resource.type)); - return WINED3DERR_INVALIDCALL; - } - - if (!(texture->flags & (WINED3D_TEXTURE_GET_DC_LENIENT | WINED3D_TEXTURE_DC_IN_USE))) - return WINED3DERR_INVALIDCALL; - - if (!(dc_info = texture->dc_info) || dc_info[sub_resource_idx].dc != dc) - { - WARN("Application tries to release invalid DC %p, sub-resource DC is %p.\n", - dc, dc_info ? dc_info[sub_resource_idx].dc : NULL); - return WINED3DERR_INVALIDCALL; - } - - if (!(texture->resource.usage & WINED3DUSAGE_OWNDC)) - { - struct wined3d_texture_idx texture_idx = {texture, sub_resource_idx}; - - wined3d_cs_destroy_object(device->cs, wined3d_texture_destroy_dc, &texture_idx); - wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT); - } - - --sub_resource->map_count; - if (!--texture->resource.map_count && texture->update_map_binding) - wined3d_texture_update_map_binding(texture); - if (!(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT)) - texture->flags &= ~WINED3D_TEXTURE_DC_IN_USE; - - return WINED3D_OK; -} - -void wined3d_texture_upload_from_texture(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, - unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, struct wined3d_texture *src_texture, - unsigned int src_sub_resource_idx, const struct wined3d_box *src_box) -{ - unsigned int src_row_pitch, src_slice_pitch; - unsigned int update_w, update_h, update_d; - unsigned int src_level, dst_level; - struct wined3d_context *context; - struct wined3d_bo_address data; - - TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_x %u, dst_y %u, dst_z %u, " - "src_texture %p, src_sub_resource_idx %u, src_box %s.\n", - dst_texture, dst_sub_resource_idx, dst_x, dst_y, dst_z, - src_texture, src_sub_resource_idx, debug_box(src_box)); - - context = context_acquire(dst_texture->resource.device, NULL, 0); - - /* Only load the sub-resource for partial updates. For newly allocated - * textures the texture wouldn't be the current location, and we'd upload - * zeroes just to overwrite them again. */ - update_w = src_box->right - src_box->left; - update_h = src_box->bottom - src_box->top; - update_d = src_box->back - src_box->front; - dst_level = dst_sub_resource_idx % dst_texture->level_count; - if (update_w == wined3d_texture_get_level_width(dst_texture, dst_level) - && update_h == wined3d_texture_get_level_height(dst_texture, dst_level) - && update_d == wined3d_texture_get_level_depth(dst_texture, dst_level)) - wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB); - else - wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB); - - src_level = src_sub_resource_idx % src_texture->level_count; - wined3d_texture_get_memory(src_texture, src_sub_resource_idx, context, &data); - wined3d_texture_get_pitch(src_texture, src_level, &src_row_pitch, &src_slice_pitch); - - dst_texture->texture_ops->texture_upload_data(context, wined3d_const_bo_address(&data), - src_texture->resource.format, src_box, src_row_pitch, src_slice_pitch, dst_texture, - dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, dst_x, dst_y, dst_z); - - context_release(context); - - wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB); - wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB); -} - -/* Partial downloads are not supported. */ -void wined3d_texture_download_from_texture(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, - struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx) -{ - unsigned int src_level, dst_level, dst_row_pitch, dst_slice_pitch; - unsigned int dst_location = dst_texture->resource.map_binding; - struct wined3d_context *context; - struct wined3d_bo_address data; - struct wined3d_box src_box; - unsigned int src_location; - - context = context_acquire(src_texture->resource.device, NULL, 0); - - wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location); - wined3d_texture_get_bo_address(dst_texture, dst_sub_resource_idx, &data, dst_location); - - if (src_texture->sub_resources[src_sub_resource_idx].locations & WINED3D_LOCATION_TEXTURE_RGB) - src_location = WINED3D_LOCATION_TEXTURE_RGB; - else - src_location = WINED3D_LOCATION_TEXTURE_SRGB; - src_level = src_sub_resource_idx % src_texture->level_count; - wined3d_texture_get_level_box(src_texture, src_level, &src_box); - - dst_level = dst_sub_resource_idx % dst_texture->level_count; - wined3d_texture_get_pitch(dst_texture, dst_level, &dst_row_pitch, &dst_slice_pitch); - - src_texture->texture_ops->texture_download_data(context, src_texture, src_sub_resource_idx, src_location, - &src_box, &data, dst_texture->resource.format, 0, 0, 0, dst_row_pitch, dst_slice_pitch); - - context_release(context); - - wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, dst_location); - wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~dst_location); -} - -static void wined3d_texture_set_bo(struct wined3d_texture *texture, - unsigned sub_resource_idx, struct wined3d_context *context, struct wined3d_bo *bo) -{ - struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx]; - struct wined3d_bo *prev_bo = sub_resource->bo; - - TRACE("texture %p, sub_resource_idx %u, context %p, bo %p.\n", texture, sub_resource_idx, context, bo); - - if (prev_bo) - { - struct wined3d_bo_user *bo_user; - - LIST_FOR_EACH_ENTRY(bo_user, &prev_bo->users, struct wined3d_bo_user, entry) - bo_user->valid = false; - list_init(&prev_bo->users); - - assert(list_empty(&bo->users)); - - wined3d_context_destroy_bo(context, prev_bo); - free(prev_bo); - } - - sub_resource->bo = bo; -} - -void wined3d_texture_update_sub_resource(struct wined3d_texture *texture, unsigned int sub_resource_idx, - struct wined3d_context *context, const struct upload_bo *upload_bo, const struct wined3d_box *box, - unsigned int row_pitch, unsigned int slice_pitch) -{ - unsigned int level = sub_resource_idx % texture->level_count; - unsigned int width = wined3d_texture_get_level_width(texture, level); - unsigned int height = wined3d_texture_get_level_height(texture, level); - unsigned int depth = wined3d_texture_get_level_depth(texture, level); - struct wined3d_box src_box; - - if (upload_bo->flags & UPLOAD_BO_RENAME_ON_UNMAP) - { - wined3d_texture_set_bo(texture, sub_resource_idx, context, upload_bo->addr.buffer_object); - wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_BUFFER); - wined3d_texture_invalidate_location(texture, sub_resource_idx, ~WINED3D_LOCATION_BUFFER); - /* Try to free address space if we are not mapping persistently. */ - if (upload_bo->addr.buffer_object->map_ptr) - wined3d_context_unmap_bo_address(context, (const struct wined3d_bo_address *)&upload_bo->addr, 0, NULL); - } - - /* Only load the sub-resource for partial updates. */ - if (!box->left && !box->top && !box->front - && box->right == width && box->bottom == height && box->back == depth) - wined3d_texture_prepare_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB); - else - wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB); - - wined3d_box_set(&src_box, 0, 0, box->right - box->left, box->bottom - box->top, 0, box->back - box->front); - texture->texture_ops->texture_upload_data(context, &upload_bo->addr, texture->resource.format, - &src_box, row_pitch, slice_pitch, texture, sub_resource_idx, - WINED3D_LOCATION_TEXTURE_RGB, box->left, box->top, box->front); - - wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB); - wined3d_texture_invalidate_location(texture, sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB); -} - -struct wined3d_shader_resource_view * CDECL wined3d_texture_acquire_identity_srv(struct wined3d_texture *texture) -{ - struct wined3d_view_desc desc; - HRESULT hr; - - TRACE("texture %p.\n", texture); - - if (texture->identity_srv) - return texture->identity_srv; - - desc.format_id = texture->resource.format->id; - /* The texture owns a reference to the SRV, so we can't have the SRV hold - * a reference to the texture. - * At the same time, a view must be destroyed before its texture, and we - * need a bound SRV to keep the texture alive even if it doesn't have any - * other references. - * In order to achieve this we have the objects share reference counts. - * This means the view doesn't hold a reference to the resource, but any - * references to the view are forwarded to the resource instead. The view - * is destroyed manually when all references are released. */ - desc.flags = WINED3D_VIEW_FORWARD_REFERENCE; - desc.u.texture.level_idx = 0; - desc.u.texture.level_count = texture->level_count; - desc.u.texture.layer_idx = 0; - desc.u.texture.layer_count = texture->layer_count; - if (FAILED(hr = wined3d_shader_resource_view_create(&desc, &texture->resource, - NULL, &wined3d_null_parent_ops, &texture->identity_srv))) - { - ERR("Failed to create shader resource view, hr %#lx.\n", hr); - return NULL; - } - wined3d_shader_resource_view_decref(texture->identity_srv); - - return texture->identity_srv; -} - -static void wined3d_texture_no3d_upload_data(struct wined3d_context *context, - const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *src_format, - const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch, - struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, unsigned int dst_location, - unsigned int dst_x, unsigned int dst_y, unsigned int dst_z) -{ - FIXME("Not implemented.\n"); -} - -static void wined3d_texture_no3d_download_data(struct wined3d_context *context, - struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, unsigned int src_location, - const struct wined3d_box *src_box, const struct wined3d_bo_address *dst_bo_addr, - const struct wined3d_format *dst_format, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, - unsigned int dst_row_pitch, unsigned int dst_slice_pitch) -{ - FIXME("Not implemented.\n"); -} - -static BOOL wined3d_texture_no3d_prepare_location(struct wined3d_texture *texture, - unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location) -{ - if (location == WINED3D_LOCATION_SYSMEM) - return texture->sub_resources[sub_resource_idx].user_memory ? TRUE - : wined3d_resource_prepare_sysmem(&texture->resource); - - FIXME("Unhandled location %s.\n", wined3d_debug_location(location)); - return FALSE; -} - -static BOOL wined3d_texture_no3d_load_location(struct wined3d_texture *texture, - unsigned int sub_resource_idx, struct wined3d_context *context, uint32_t location) -{ - TRACE("texture %p, sub_resource_idx %u, context %p, location %s.\n", - texture, sub_resource_idx, context, wined3d_debug_location(location)); - - if (location == WINED3D_LOCATION_SYSMEM) - return TRUE; - - ERR("Unhandled location %s.\n", wined3d_debug_location(location)); - - return FALSE; -} - -static void wined3d_texture_no3d_unload_location(struct wined3d_texture *texture, - struct wined3d_context *context, unsigned int location) -{ - TRACE("texture %p, context %p, location %s.\n", texture, context, wined3d_debug_location(location)); -} - -static const struct wined3d_texture_ops wined3d_texture_no3d_ops = -{ - wined3d_texture_no3d_prepare_location, - wined3d_texture_no3d_load_location, - wined3d_texture_no3d_unload_location, - wined3d_texture_no3d_upload_data, - wined3d_texture_no3d_download_data, -}; - -HRESULT wined3d_texture_no3d_init(struct wined3d_texture *texture_no3d, struct wined3d_device *device, - const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count, - uint32_t flags, void *parent, const struct wined3d_parent_ops *parent_ops) -{ - TRACE("texture_no3d %p, device %p, desc %p, layer_count %u, " - "level_count %u, flags %#x, parent %p, parent_ops %p.\n", - texture_no3d, device, desc, layer_count, - level_count, flags, parent, parent_ops); - - return wined3d_texture_init(texture_no3d, desc, layer_count, level_count, - flags, device, parent, parent_ops, &texture_no3d[1], &wined3d_texture_no3d_ops); -} - -void wined3d_vk_swizzle_from_color_fixup(VkComponentMapping *mapping, struct color_fixup_desc fixup) -{ - static const VkComponentSwizzle swizzle_source[] = - { - VK_COMPONENT_SWIZZLE_ZERO, /* CHANNEL_SOURCE_ZERO */ - VK_COMPONENT_SWIZZLE_ONE, /* CHANNEL_SOURCE_ONE */ - VK_COMPONENT_SWIZZLE_R, /* CHANNEL_SOURCE_X */ - VK_COMPONENT_SWIZZLE_G, /* CHANNEL_SOURCE_Y */ - VK_COMPONENT_SWIZZLE_B, /* CHANNEL_SOURCE_Z */ - VK_COMPONENT_SWIZZLE_A, /* CHANNEL_SOURCE_W */ - }; - - mapping->r = swizzle_source[fixup.x_source]; - mapping->g = swizzle_source[fixup.y_source]; - mapping->b = swizzle_source[fixup.z_source]; - mapping->a = swizzle_source[fixup.w_source]; -} - -const VkDescriptorImageInfo *wined3d_texture_vk_get_default_image_info(struct wined3d_texture_vk *texture_vk, - struct wined3d_context_vk *context_vk) -{ - const struct wined3d_format_vk *format_vk; - const struct wined3d_vk_info *vk_info; - struct wined3d_device_vk *device_vk; - VkImageViewCreateInfo create_info; - struct color_fixup_desc fixup; - uint32_t flags = 0; - VkResult vr; - - if (texture_vk->default_image_info.imageView) - return &texture_vk->default_image_info; - - format_vk = wined3d_format_vk(texture_vk->t.resource.format); - device_vk = wined3d_device_vk(texture_vk->t.resource.device); - vk_info = context_vk->vk_info; - - if (texture_vk->t.layer_count > 1) - flags |= WINED3D_VIEW_TEXTURE_ARRAY; - - wined3d_texture_vk_prepare_texture(texture_vk, context_vk); - create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - create_info.pNext = NULL; - create_info.flags = 0; - create_info.image = texture_vk->image.vk_image; - create_info.viewType = vk_image_view_type_from_wined3d(texture_vk->t.resource.type, flags); - create_info.format = format_vk->vk_format; - fixup = format_vk->f.color_fixup; - if (is_identity_fixup(fixup) || !can_use_texture_swizzle(context_vk->c.d3d_info, &format_vk->f)) - { - create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - } - else - { - wined3d_vk_swizzle_from_color_fixup(&create_info.components, fixup); - } - create_info.subresourceRange.aspectMask = vk_aspect_mask_from_format(&format_vk->f); - create_info.subresourceRange.baseMipLevel = 0; - create_info.subresourceRange.levelCount = texture_vk->t.level_count; - create_info.subresourceRange.baseArrayLayer = 0; - create_info.subresourceRange.layerCount = texture_vk->t.layer_count; - if ((vr = VK_CALL(vkCreateImageView(device_vk->vk_device, &create_info, - NULL, &texture_vk->default_image_info.imageView))) < 0) - { - ERR("Failed to create Vulkan image view, vr %s.\n", wined3d_debug_vkresult(vr)); - return NULL; - } - - TRACE("Created image view 0x%s.\n", wine_dbgstr_longlong(texture_vk->default_image_info.imageView)); - - texture_vk->default_image_info.sampler = VK_NULL_HANDLE; - - /* The default image view is used for SRVs, UAVs and RTVs when the d3d view encompasses the entire - * resource. Any UAV capable resource will always use VK_IMAGE_LAYOUT_GENERAL, so we can use the - * same image info for SRVs and UAVs. For render targets wined3d_rendertarget_view_vk_get_image_view - * only cares about the VkImageView, not entire image info. So using SHADER_READ_ONLY_OPTIMAL works, - * but relies on what the callers of the function do and don't do with the descriptor we return. - * - * Note that VkWriteDescriptorSet for SRV/UAV use takes a VkDescriptorImageInfo *, so we need a - * place to store the VkDescriptorImageInfo. So returning onlky a VkImageView from this function - * would bring its own problems. */ - if (texture_vk->layout == VK_IMAGE_LAYOUT_GENERAL) - texture_vk->default_image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - else - texture_vk->default_image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - return &texture_vk->default_image_info; -} - -static void wined3d_texture_vk_upload_plane(struct wined3d_context *context, VkImageAspectFlags vk_aspect, - const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *plane_format, - const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch, - struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, - unsigned int dst_x, unsigned int dst_y, unsigned int dst_z) -{ - struct wined3d_texture_vk *dst_texture_vk = wined3d_texture_vk(dst_texture); - struct wined3d_context_vk *context_vk = wined3d_context_vk(context); - unsigned int dst_level, dst_row_pitch, dst_slice_pitch; - struct wined3d_texture_sub_resource *sub_resource; - unsigned int src_width, src_height, src_depth; - struct wined3d_bo_address staging_bo_addr; - VkPipelineStageFlags bo_stage_flags = 0; - const struct wined3d_vk_info *vk_info; - VkCommandBuffer vk_command_buffer; - VkBufferMemoryBarrier vk_barrier; - VkImageSubresourceRange vk_range; - struct wined3d_bo_vk staging_bo; - struct wined3d_bo_vk *src_bo; - struct wined3d_range range; - VkBufferImageCopy region; - size_t src_offset; - void *map_ptr; - - TRACE("context %p, vk_aspect %#x, src_bo_addr %s, plane_format %s, src_box %s, src_row_pitch %u, src_slice_pitch %u, " - "dst_texture %p, dst_sub_resource_idx %u, dst_x %u, dst_y %u, dst_z %u.\n", - context, vk_aspect, debug_const_bo_address(src_bo_addr), debug_d3dformat(plane_format->id), debug_box(src_box), - src_row_pitch, src_slice_pitch, dst_texture, dst_sub_resource_idx, dst_x, dst_y, dst_z); - - dst_level = dst_sub_resource_idx % dst_texture->level_count; - wined3d_texture_get_pitch(dst_texture, dst_level, &dst_row_pitch, &dst_slice_pitch); - if (dst_texture->resource.type == WINED3D_RTYPE_TEXTURE_1D) - src_row_pitch = dst_row_pitch = 0; - if (dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_3D) - src_slice_pitch = dst_slice_pitch = 0; - - sub_resource = &dst_texture_vk->t.sub_resources[dst_sub_resource_idx]; - vk_info = context_vk->vk_info; - - src_width = src_box->right - src_box->left; - src_height = src_box->bottom - src_box->top; - src_depth = src_box->back - src_box->front; - - src_offset = src_box->front * src_slice_pitch - + (src_box->top / plane_format->block_height) * src_row_pitch - + (src_box->left / plane_format->block_width) * plane_format->block_byte_count; - - if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk))) - { - ERR("Failed to get command buffer.\n"); - return; - } - - /* We need to be outside of a render pass for vkCmdPipelineBarrier() and vkCmdCopyBufferToImage() calls below. */ - wined3d_context_vk_end_current_render_pass(context_vk); - if (!src_bo_addr->buffer_object) - { - unsigned int staging_row_pitch, staging_slice_pitch, staging_size; - - wined3d_format_calculate_pitch(plane_format, context->device->surface_alignment, src_width, src_height, - &staging_row_pitch, &staging_slice_pitch); - staging_size = staging_slice_pitch * src_depth; - - if (!wined3d_context_vk_create_bo(context_vk, staging_size, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &staging_bo)) - { - ERR("Failed to create staging bo.\n"); - return; - } - - staging_bo_addr.buffer_object = &staging_bo.b; - staging_bo_addr.addr = NULL; - if (!(map_ptr = wined3d_context_map_bo_address(context, &staging_bo_addr, - staging_size, WINED3D_MAP_DISCARD | WINED3D_MAP_WRITE))) - { - ERR("Failed to map staging bo.\n"); - wined3d_context_vk_destroy_bo(context_vk, &staging_bo); - return; - } - - wined3d_format_copy_data(plane_format, src_bo_addr->addr + src_offset, src_row_pitch, src_slice_pitch, - map_ptr, staging_row_pitch, staging_slice_pitch, src_width, src_height, src_depth); - - range.offset = 0; - range.size = staging_size; - wined3d_context_unmap_bo_address(context, &staging_bo_addr, 1, &range); - - src_bo = &staging_bo; - - src_offset = 0; - src_row_pitch = staging_row_pitch; - src_slice_pitch = staging_slice_pitch; - } - else - { - src_bo = wined3d_bo_vk(src_bo_addr->buffer_object); - - vk_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; - vk_barrier.pNext = NULL; - vk_barrier.srcAccessMask = vk_access_mask_from_buffer_usage(src_bo->usage) & ~WINED3D_READ_ONLY_ACCESS_FLAGS; - vk_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - vk_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - vk_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - vk_barrier.buffer = src_bo->vk_buffer; - vk_barrier.offset = src_bo->b.buffer_offset + (size_t)src_bo_addr->addr; - vk_barrier.size = sub_resource->size; - - src_offset += (size_t)src_bo_addr->addr; - - bo_stage_flags = vk_pipeline_stage_mask_from_buffer_usage(src_bo->usage); - if (vk_barrier.srcAccessMask) - VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, bo_stage_flags, - VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 1, &vk_barrier, 0, NULL)); - } - - vk_range.aspectMask = vk_aspect; - vk_range.baseMipLevel = dst_level; - vk_range.levelCount = 1; - vk_range.baseArrayLayer = dst_sub_resource_idx / dst_texture_vk->t.level_count; - vk_range.layerCount = 1; - - wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, - vk_access_mask_from_bind_flags(dst_texture_vk->t.resource.bind_flags), - VK_ACCESS_TRANSFER_WRITE_BIT, - dst_texture_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - dst_texture_vk->image.vk_image, &vk_range); - - region.bufferOffset = src_bo->b.buffer_offset + src_offset; - region.bufferRowLength = (src_row_pitch / plane_format->block_byte_count) * plane_format->block_width; - if (src_row_pitch) - region.bufferImageHeight = (src_slice_pitch / src_row_pitch) * plane_format->block_height; - else - region.bufferImageHeight = 1; - region.imageSubresource.aspectMask = vk_range.aspectMask; - region.imageSubresource.mipLevel = vk_range.baseMipLevel; - region.imageSubresource.baseArrayLayer = vk_range.baseArrayLayer; - region.imageSubresource.layerCount = vk_range.layerCount; - region.imageOffset.x = dst_x; - region.imageOffset.y = dst_y; - region.imageOffset.z = dst_z; - region.imageExtent.width = src_width; - region.imageExtent.height = src_height; - region.imageExtent.depth = src_depth; - - VK_CALL(vkCmdCopyBufferToImage(vk_command_buffer, src_bo->vk_buffer, - dst_texture_vk->image.vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion)); - - wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_ACCESS_TRANSFER_WRITE_BIT, - vk_access_mask_from_bind_flags(dst_texture_vk->t.resource.bind_flags), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_texture_vk->layout, - dst_texture_vk->image.vk_image, &vk_range); - wined3d_context_vk_reference_texture(context_vk, dst_texture_vk); - wined3d_context_vk_reference_bo(context_vk, src_bo); - - if (src_bo == &staging_bo) - { - wined3d_context_vk_destroy_bo(context_vk, &staging_bo); - } - else if (vk_barrier.srcAccessMask) - { - VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, - bo_stage_flags, 0, 0, NULL, 0, NULL, 0, NULL)); - } -} - -static void wined3d_texture_vk_upload_data(struct wined3d_context *context, - const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *src_format, - const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch, - struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, unsigned int dst_location, - unsigned int dst_x, unsigned int dst_y, unsigned int dst_z) -{ - VkImageAspectFlags aspect_mask; - - TRACE("context %p, src_bo_addr %s, src_format %s, src_box %s, src_row_pitch %u, src_slice_pitch %u, " - "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_x %u, dst_y %u, dst_z %u.\n", - context, debug_const_bo_address(src_bo_addr), debug_d3dformat(src_format->id), debug_box(src_box), - src_row_pitch, src_slice_pitch, dst_texture, dst_sub_resource_idx, - wined3d_debug_location(dst_location), dst_x, dst_y, dst_z); - - if (src_format->id != dst_texture->resource.format->id) - { - FIXME("Unhandled format conversion (%s -> %s).\n", - debug_d3dformat(src_format->id), - debug_d3dformat(dst_texture->resource.format->id)); - return; - } - - if (dst_location != WINED3D_LOCATION_TEXTURE_RGB) - { - FIXME("Unhandled location %s.\n", wined3d_debug_location(dst_location)); - return; - } - - if (wined3d_resource_get_sample_count(&dst_texture->resource) > 1) - { - FIXME("Not supported for multisample textures.\n"); - return; - } - - aspect_mask = vk_aspect_mask_from_format(dst_texture->resource.format); - if (wined3d_popcount(aspect_mask) > 1) - { - FIXME("Unhandled multi-aspect format %s.\n", debug_d3dformat(dst_texture->resource.format->id)); - return; - } - - if (src_format->attrs & WINED3D_FORMAT_ATTR_PLANAR) - { - struct wined3d_const_bo_address uv_bo_addr; - const struct wined3d_format *plane_format; - struct wined3d_box uv_box; - - plane_format = wined3d_get_format(context->device->adapter, src_format->plane_formats[0], 0); - wined3d_texture_vk_upload_plane(context, VK_IMAGE_ASPECT_PLANE_0_BIT, src_bo_addr, plane_format, src_box, - src_row_pitch, src_slice_pitch, dst_texture, dst_sub_resource_idx, dst_x, dst_y, dst_z); - - uv_bo_addr = *src_bo_addr; - uv_bo_addr.addr += src_slice_pitch; - uv_box = *src_box; - uv_box.left /= src_format->uv_width; - uv_box.right /= src_format->uv_width; - uv_box.top /= src_format->uv_height; - uv_box.bottom /= src_format->uv_height; - dst_x /= src_format->uv_width; - dst_y /= src_format->uv_height; - src_row_pitch = src_row_pitch * 2 / src_format->uv_width; - src_slice_pitch = src_slice_pitch * 2 / src_format->uv_width / src_format->uv_height; - - plane_format = wined3d_get_format(context->device->adapter, src_format->plane_formats[1], 0); - wined3d_texture_vk_upload_plane(context, VK_IMAGE_ASPECT_PLANE_1_BIT, &uv_bo_addr, plane_format, &uv_box, - src_row_pitch, src_slice_pitch, dst_texture, dst_sub_resource_idx, dst_x, dst_y, dst_z); - } - else - { - wined3d_texture_vk_upload_plane(context, aspect_mask, src_bo_addr, src_format, src_box, - src_row_pitch, src_slice_pitch, dst_texture, dst_sub_resource_idx, dst_x, dst_y, dst_z); - } -} - -static void wined3d_texture_vk_download_plane(struct wined3d_context *context, VkImageAspectFlags vk_aspect, - struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, - const struct wined3d_box *src_box, const struct wined3d_bo_address *dst_bo_addr, - const struct wined3d_format *plane_format, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, - unsigned int dst_row_pitch, unsigned int dst_slice_pitch) -{ - struct wined3d_texture_vk *src_texture_vk = wined3d_texture_vk(src_texture); - struct wined3d_context_vk *context_vk = wined3d_context_vk(context); - unsigned int src_level, src_width, src_height, src_depth; - struct wined3d_texture_sub_resource *sub_resource; - unsigned int src_row_pitch, src_slice_pitch; - struct wined3d_bo_address staging_bo_addr; - VkPipelineStageFlags bo_stage_flags = 0; - const struct wined3d_vk_info *vk_info; - VkCommandBuffer vk_command_buffer; - VkImageSubresourceRange vk_range; - VkBufferMemoryBarrier vk_barrier; - struct wined3d_bo_vk staging_bo; - struct wined3d_bo_vk *dst_bo; - VkBufferImageCopy region; - size_t dst_offset = 0; - void *map_ptr; - - TRACE("context %p, vk_aspect %#x, src_texture %p, src_sub_resource_idx %u, src_box %s, dst_bo_addr %s, " - "plane_format %s, dst_x %u, dst_y %u, dst_z %u, dst_row_pitch %u, dst_slice_pitch %u.\n", - context, vk_aspect, src_texture, src_sub_resource_idx, - debug_box(src_box), debug_bo_address(dst_bo_addr), debug_d3dformat(plane_format->id), - dst_x, dst_y, dst_z, dst_row_pitch, dst_slice_pitch); - - src_level = src_sub_resource_idx % src_texture->level_count; - wined3d_texture_get_pitch(src_texture, src_level, &src_row_pitch, &src_slice_pitch); - if (src_texture->resource.type == WINED3D_RTYPE_TEXTURE_1D) - src_row_pitch = dst_row_pitch = 0; - if (src_texture->resource.type != WINED3D_RTYPE_TEXTURE_3D) - src_slice_pitch = dst_slice_pitch = 0; - - sub_resource = &src_texture_vk->t.sub_resources[src_sub_resource_idx]; - vk_info = context_vk->vk_info; - - src_width = src_box->right - src_box->left; - src_height = src_box->bottom - src_box->top; - src_depth = src_box->back - src_box->front; - - if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk))) - { - ERR("Failed to get command buffer.\n"); - return; - } - - /* We need to be outside of a render pass for vkCmdPipelineBarrier() and vkCmdCopyImageToBuffer() calls below. */ - wined3d_context_vk_end_current_render_pass(context_vk); - - if (!dst_bo_addr->buffer_object) - { - if (!wined3d_context_vk_create_bo(context_vk, sub_resource->size, - VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &staging_bo)) - { - ERR("Failed to create staging bo.\n"); - return; - } - - dst_bo = &staging_bo; - - region.bufferRowLength = (src_row_pitch / plane_format->block_byte_count) * plane_format->block_width; - if (src_row_pitch) - region.bufferImageHeight = (src_slice_pitch / src_row_pitch) * plane_format->block_height; - else - region.bufferImageHeight = 1; - - if (src_row_pitch % plane_format->byte_count) - { - FIXME("Row pitch %u is not a multiple of byte count %u.\n", src_row_pitch, plane_format->byte_count); - return; - } - if (src_row_pitch && src_slice_pitch % src_row_pitch) - { - FIXME("Slice pitch %u is not a multiple of row pitch %u.\n", src_slice_pitch, src_row_pitch); - return; - } - } - else - { - dst_bo = wined3d_bo_vk(dst_bo_addr->buffer_object); - - region.bufferRowLength = (dst_row_pitch / plane_format->block_byte_count) * plane_format->block_width; - if (dst_row_pitch) - region.bufferImageHeight = (dst_slice_pitch / dst_row_pitch) * plane_format->block_height; - else - region.bufferImageHeight = 1; - - if (dst_row_pitch % plane_format->byte_count) - { - FIXME("Row pitch %u is not a multiple of byte count %u.\n", dst_row_pitch, plane_format->byte_count); - return; - } - if (dst_row_pitch && dst_slice_pitch % dst_row_pitch) - { - FIXME("Slice pitch %u is not a multiple of row pitch %u.\n", dst_slice_pitch, dst_row_pitch); - return; - } - - vk_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; - vk_barrier.pNext = NULL; - vk_barrier.srcAccessMask = vk_access_mask_from_buffer_usage(dst_bo->usage); - vk_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - vk_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - vk_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - vk_barrier.buffer = dst_bo->vk_buffer; - vk_barrier.offset = dst_bo->b.buffer_offset + (size_t)dst_bo_addr->addr; - vk_barrier.size = sub_resource->size; - - bo_stage_flags = vk_pipeline_stage_mask_from_buffer_usage(dst_bo->usage); - dst_offset = (size_t)dst_bo_addr->addr; - - VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, bo_stage_flags, - VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 1, &vk_barrier, 0, NULL)); - } - - vk_range.aspectMask = vk_aspect; - vk_range.baseMipLevel = src_level; - vk_range.levelCount = 1; - vk_range.baseArrayLayer = src_sub_resource_idx / src_texture_vk->t.level_count; - vk_range.layerCount = 1; - - wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, - vk_access_mask_from_bind_flags(src_texture_vk->t.resource.bind_flags), - VK_ACCESS_TRANSFER_READ_BIT, - src_texture_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - src_texture_vk->image.vk_image, &vk_range); - - region.bufferOffset = dst_bo->b.buffer_offset + dst_offset; - region.imageSubresource.aspectMask = vk_range.aspectMask; - region.imageSubresource.mipLevel = vk_range.baseMipLevel; - region.imageSubresource.baseArrayLayer = vk_range.baseArrayLayer; - region.imageSubresource.layerCount = vk_range.layerCount; - region.imageOffset.x = 0; - region.imageOffset.y = 0; - region.imageOffset.z = 0; - region.imageExtent.width = src_width; - region.imageExtent.height = src_height; - region.imageExtent.depth = src_depth; - - VK_CALL(vkCmdCopyImageToBuffer(vk_command_buffer, src_texture_vk->image.vk_image, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_bo->vk_buffer, 1, ®ion)); - - wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_ACCESS_TRANSFER_READ_BIT, - vk_access_mask_from_bind_flags(src_texture_vk->t.resource.bind_flags), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, src_texture_vk->layout, - src_texture_vk->image.vk_image, &vk_range); - - wined3d_context_vk_reference_texture(context_vk, src_texture_vk); - wined3d_context_vk_reference_bo(context_vk, dst_bo); - - if (dst_bo == &staging_bo) - { - wined3d_context_vk_submit_command_buffer(context_vk, 0, NULL, NULL, 0, NULL); - wined3d_context_vk_wait_command_buffer(context_vk, src_texture_vk->image.command_buffer_id); - - staging_bo_addr.buffer_object = &staging_bo.b; - staging_bo_addr.addr = NULL; - if (!(map_ptr = wined3d_context_map_bo_address(context, &staging_bo_addr, - sub_resource->size, WINED3D_MAP_READ))) - { - ERR("Failed to map staging bo.\n"); - wined3d_context_vk_destroy_bo(context_vk, &staging_bo); - return; - } - - wined3d_format_copy_data(plane_format, map_ptr, src_row_pitch, src_slice_pitch, - dst_bo_addr->addr, dst_row_pitch, dst_slice_pitch, src_box->right - src_box->left, - src_box->bottom - src_box->top, src_box->back - src_box->front); - - wined3d_context_unmap_bo_address(context, &staging_bo_addr, 0, NULL); - wined3d_context_vk_destroy_bo(context_vk, &staging_bo); - } - else - { - vk_barrier.dstAccessMask = vk_barrier.srcAccessMask; - vk_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - - if (dst_bo->host_synced) - { - vk_barrier.dstAccessMask |= VK_ACCESS_HOST_READ_BIT; - bo_stage_flags |= VK_PIPELINE_STAGE_HOST_BIT; - } - - VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, - bo_stage_flags, 0, 0, NULL, 1, &vk_barrier, 0, NULL)); - /* Start the download so we don't stall waiting for the result. */ - wined3d_context_vk_submit_command_buffer(context_vk, 0, NULL, NULL, 0, NULL); - } -} - -static void wined3d_texture_vk_download_data(struct wined3d_context *context, - struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, unsigned int src_location, - const struct wined3d_box *src_box, const struct wined3d_bo_address *dst_bo_addr, - const struct wined3d_format *dst_format, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, - unsigned int dst_row_pitch, unsigned int dst_slice_pitch) -{ - unsigned int src_level, src_width, src_height, src_depth; - VkImageAspectFlags aspect_mask; - - TRACE("context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_box %s, dst_bo_addr %s, " - "dst_format %s, dst_x %u, dst_y %u, dst_z %u, dst_row_pitch %u, dst_slice_pitch %u.\n", - context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location), - debug_box(src_box), debug_bo_address(dst_bo_addr), debug_d3dformat(dst_format->id), - dst_x, dst_y, dst_z, dst_row_pitch, dst_slice_pitch); - - if (src_location != WINED3D_LOCATION_TEXTURE_RGB) - { - FIXME("Unhandled location %s.\n", wined3d_debug_location(src_location)); - return; - } - - src_level = src_sub_resource_idx % src_texture->level_count; - src_width = wined3d_texture_get_level_width(src_texture, src_level); - src_height = wined3d_texture_get_level_height(src_texture, src_level); - src_depth = wined3d_texture_get_level_depth(src_texture, src_level); - if (src_box->left || src_box->top || src_box->right != src_width || src_box->bottom != src_height - || src_box->front || src_box->back != src_depth) - { - FIXME("Unhandled source box %s.\n", debug_box(src_box)); - return; - } - - src_level = src_sub_resource_idx % src_texture->level_count; - src_width = wined3d_texture_get_level_width(src_texture, src_level); - src_height = wined3d_texture_get_level_height(src_texture, src_level); - src_depth = wined3d_texture_get_level_depth(src_texture, src_level); - if (src_box->left || src_box->top || src_box->right != src_width || src_box->bottom != src_height - || src_box->front || src_box->back != src_depth) - { - FIXME("Unhandled source box %s.\n", debug_box(src_box)); - return; - } - - if (dst_format->id != src_texture->resource.format->id) - { - FIXME("Unhandled format conversion (%s -> %s).\n", - debug_d3dformat(src_texture->resource.format->id), - debug_d3dformat(dst_format->id)); - return; - } - - if (dst_x || dst_y || dst_z) - { - FIXME("Unhandled destination (%u, %u, %u).\n", dst_x, dst_y, dst_z); - return; - } - - if (wined3d_resource_get_sample_count(&src_texture->resource) > 1) - { - FIXME("Not supported for multisample textures.\n"); - return; - } - - aspect_mask = vk_aspect_mask_from_format(src_texture->resource.format); - if (wined3d_popcount(aspect_mask) > 1) - { - FIXME("Unhandled multi-aspect format %s.\n", debug_d3dformat(src_texture->resource.format->id)); - return; - } - - if (dst_format->attrs & WINED3D_FORMAT_ATTR_PLANAR) - { - const struct wined3d_format *plane_format; - struct wined3d_bo_address uv_bo_addr; - struct wined3d_box uv_box; - - plane_format = wined3d_get_format(context->device->adapter, dst_format->plane_formats[0], 0); - wined3d_texture_vk_download_plane(context, VK_IMAGE_ASPECT_PLANE_0_BIT, src_texture, src_sub_resource_idx, - src_box, dst_bo_addr, plane_format, dst_x, dst_y, dst_z, dst_row_pitch, dst_slice_pitch); - - uv_bo_addr = *dst_bo_addr; - uv_bo_addr.addr += dst_slice_pitch; - uv_box = *src_box; - uv_box.left /= dst_format->uv_width; - uv_box.right /= dst_format->uv_width; - uv_box.top /= dst_format->uv_height; - uv_box.bottom /= dst_format->uv_height; - dst_x /= dst_format->uv_width; - dst_y /= dst_format->uv_height; - dst_row_pitch = dst_row_pitch * 2 / dst_format->uv_width; - dst_slice_pitch = dst_slice_pitch * 2 / dst_format->uv_width / dst_format->uv_height; - - plane_format = wined3d_get_format(context->device->adapter, dst_format->plane_formats[1], 0); - wined3d_texture_vk_download_plane(context, VK_IMAGE_ASPECT_PLANE_1_BIT, src_texture, src_sub_resource_idx, - &uv_box, &uv_bo_addr, plane_format, dst_x, dst_y, dst_z, dst_row_pitch, dst_slice_pitch); - } - else - { - wined3d_texture_vk_download_plane(context, aspect_mask, src_texture, src_sub_resource_idx, - src_box, dst_bo_addr, dst_format, dst_x, dst_y, dst_z, dst_row_pitch, dst_slice_pitch); - } -} - -static bool wined3d_texture_vk_clear(struct wined3d_texture_vk *texture_vk, - unsigned int sub_resource_idx, struct wined3d_context *context) -{ - struct wined3d_texture_sub_resource *sub_resource = &texture_vk->t.sub_resources[sub_resource_idx]; - struct wined3d_context_vk *context_vk = wined3d_context_vk(context); - const struct wined3d_format *format = texture_vk->t.resource.format; - const struct wined3d_vk_info *vk_info = context_vk->vk_info; - VkClearDepthStencilValue depth_value; - VkCommandBuffer vk_command_buffer; - VkImageSubresourceRange vk_range; - VkClearColorValue colour_value; - VkImageAspectFlags aspect_mask; - VkImage vk_image; - - if (texture_vk->t.resource.format_attrs & WINED3D_FORMAT_ATTR_COMPRESSED) - { - struct wined3d_bo_address addr; - struct wined3d_color *c = &sub_resource->clear_value.colour; - - if (c->r || c->g || c-> b || c->a) - FIXME("Compressed resource %p is cleared to a non-zero color.\n", &texture_vk->t); - - if (!wined3d_texture_prepare_location(&texture_vk->t, sub_resource_idx, context, WINED3D_LOCATION_SYSMEM)) - return false; - wined3d_texture_get_bo_address(&texture_vk->t, sub_resource_idx, &addr, WINED3D_LOCATION_SYSMEM); - memset(addr.addr, 0, sub_resource->size); - wined3d_texture_validate_location(&texture_vk->t, sub_resource_idx, WINED3D_LOCATION_SYSMEM); - return true; - } - - vk_image = texture_vk->image.vk_image; - - if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk))) - { - ERR("Failed to get command buffer.\n"); - return false; - } - - aspect_mask = vk_aspect_mask_from_format(format); - - vk_range.aspectMask = aspect_mask; - vk_range.baseMipLevel = sub_resource_idx % texture_vk->t.level_count; - vk_range.levelCount = 1; - vk_range.baseArrayLayer = sub_resource_idx / texture_vk->t.level_count; - vk_range.layerCount = 1; - - wined3d_context_vk_end_current_render_pass(context_vk); - - wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, - vk_access_mask_from_bind_flags(texture_vk->t.resource.bind_flags), VK_ACCESS_TRANSFER_WRITE_BIT, - texture_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, vk_image, &vk_range); - - if (format->depth_size || format->stencil_size) - { - depth_value.depth = sub_resource->clear_value.depth; - depth_value.stencil = sub_resource->clear_value.stencil; - VK_CALL(vkCmdClearDepthStencilImage(vk_command_buffer, vk_image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &depth_value, 1, &vk_range)); - } - else - { - wined3d_format_colour_to_vk(format, &sub_resource->clear_value.colour, &colour_value); - VK_CALL(vkCmdClearColorImage(vk_command_buffer, vk_image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &colour_value, 1, &vk_range)); - } - - wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_ACCESS_TRANSFER_WRITE_BIT, vk_access_mask_from_bind_flags(texture_vk->t.resource.bind_flags), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_vk->layout, vk_image, &vk_range); - wined3d_context_vk_reference_texture(context_vk, texture_vk); - - wined3d_texture_validate_location(&texture_vk->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB); - return true; -} - -static BOOL wined3d_texture_vk_load_texture(struct wined3d_texture_vk *texture_vk, - unsigned int sub_resource_idx, struct wined3d_context *context) -{ - struct wined3d_texture_sub_resource *sub_resource; - unsigned int level, row_pitch, slice_pitch; - struct wined3d_bo_address data; - struct wined3d_box src_box; - - sub_resource = &texture_vk->t.sub_resources[sub_resource_idx]; - - if (sub_resource->locations & WINED3D_LOCATION_CLEARED) - { - if (!wined3d_texture_vk_clear(texture_vk, sub_resource_idx, context)) - return FALSE; - - if (sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB) - return TRUE; - } - - if (!(sub_resource->locations & wined3d_texture_sysmem_locations)) - { - ERR("Unimplemented load from %s.\n", wined3d_debug_location(sub_resource->locations)); - return FALSE; - } - - level = sub_resource_idx % texture_vk->t.level_count; - wined3d_texture_get_memory(&texture_vk->t, sub_resource_idx, context, &data); - wined3d_texture_get_level_box(&texture_vk->t, level, &src_box); - wined3d_texture_get_pitch(&texture_vk->t, level, &row_pitch, &slice_pitch); - wined3d_texture_vk_upload_data(context, wined3d_const_bo_address(&data), texture_vk->t.resource.format, - &src_box, row_pitch, slice_pitch, &texture_vk->t, sub_resource_idx, - WINED3D_LOCATION_TEXTURE_RGB, 0, 0, 0); - - return TRUE; -} - -static BOOL wined3d_texture_vk_load_sysmem(struct wined3d_texture_vk *texture_vk, - unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location) -{ - struct wined3d_texture_sub_resource *sub_resource; - unsigned int level, row_pitch, slice_pitch; - struct wined3d_bo_address data; - struct wined3d_box src_box; - - sub_resource = &texture_vk->t.sub_resources[sub_resource_idx]; - if (!(sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB)) - { - ERR("Unimplemented load from %s.\n", wined3d_debug_location(sub_resource->locations)); - return FALSE; - } - - level = sub_resource_idx % texture_vk->t.level_count; - wined3d_texture_get_bo_address(&texture_vk->t, sub_resource_idx, &data, location); - wined3d_texture_get_level_box(&texture_vk->t, level, &src_box); - wined3d_texture_get_pitch(&texture_vk->t, level, &row_pitch, &slice_pitch); - wined3d_texture_vk_download_data(context, &texture_vk->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, - &src_box, &data, texture_vk->t.resource.format, 0, 0, 0, row_pitch, slice_pitch); - - return TRUE; -} - -BOOL wined3d_texture_vk_prepare_texture(struct wined3d_texture_vk *texture_vk, - struct wined3d_context_vk *context_vk) -{ - const struct wined3d_format_vk *format_vk; - struct wined3d_resource *resource; - VkCommandBuffer vk_command_buffer; - VkImageSubresourceRange vk_range; - VkImageUsageFlags vk_usage; - VkImageType vk_image_type; - unsigned int flags = 0; - - if (texture_vk->t.flags & WINED3D_TEXTURE_RGB_ALLOCATED) - return TRUE; - - if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk))) - { - ERR("Failed to get command buffer.\n"); - return FALSE; - } - - resource = &texture_vk->t.resource; - format_vk = wined3d_format_vk(resource->format); - - if (wined3d_format_is_typeless(&format_vk->f) || texture_vk->t.swapchain - || (texture_vk->t.resource.bind_flags & WINED3D_BIND_UNORDERED_ACCESS) - || (format_vk->f.attrs & WINED3D_FORMAT_ATTR_PLANAR)) - { - /* For UAVs, we need this in case a clear necessitates creation of a new view - * with a different format. */ - flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; - } - - switch (resource->type) - { - case WINED3D_RTYPE_TEXTURE_1D: - vk_image_type = VK_IMAGE_TYPE_1D; - break; - case WINED3D_RTYPE_TEXTURE_2D: - vk_image_type = VK_IMAGE_TYPE_2D; - if (texture_vk->t.layer_count >= 6 && resource->width == resource->height) - flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; - break; - case WINED3D_RTYPE_TEXTURE_3D: - vk_image_type = VK_IMAGE_TYPE_3D; - if (resource->bind_flags & (WINED3D_BIND_RENDER_TARGET | WINED3D_BIND_UNORDERED_ACCESS)) - flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; - break; - default: - ERR("Invalid resource type %s.\n", debug_d3dresourcetype(resource->type)); - vk_image_type = VK_IMAGE_TYPE_2D; - break; - } - - vk_usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - if (resource->bind_flags & WINED3D_BIND_SHADER_RESOURCE) - vk_usage |= VK_IMAGE_USAGE_SAMPLED_BIT; - if (resource->bind_flags & WINED3D_BIND_RENDER_TARGET) - vk_usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - if (resource->bind_flags & WINED3D_BIND_DEPTH_STENCIL) - vk_usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - if (resource->bind_flags & WINED3D_BIND_UNORDERED_ACCESS) - vk_usage |= VK_IMAGE_USAGE_STORAGE_BIT; - - if (resource->bind_flags & WINED3D_BIND_UNORDERED_ACCESS) - texture_vk->layout = VK_IMAGE_LAYOUT_GENERAL; - else if (resource->bind_flags & WINED3D_BIND_RENDER_TARGET) - texture_vk->layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - else if (resource->bind_flags & WINED3D_BIND_DEPTH_STENCIL) - texture_vk->layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - else if (resource->bind_flags & WINED3D_BIND_SHADER_RESOURCE) - texture_vk->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - else if (resource->bind_flags & WINED3D_BIND_DECODER_OUTPUT) - texture_vk->layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - else - { - FIXME("unexpected bind flags %s, using VK_IMAGE_LAYOUT_GENERAL\n", wined3d_debug_bind_flags(resource->bind_flags)); - texture_vk->layout = VK_IMAGE_LAYOUT_GENERAL; - } - - if (!wined3d_context_vk_create_image(context_vk, vk_image_type, vk_usage, format_vk->vk_format, - resource->width, resource->height, resource->depth, max(1, wined3d_resource_get_sample_count(resource)), - texture_vk->t.level_count, texture_vk->t.layer_count, flags, NULL, &texture_vk->image)) - { - return FALSE; - } - - /* We can't use a zero src access mask without synchronization2. Set the last-used bind mask to something - * non-zero to avoid this. */ - texture_vk->bind_mask = resource->bind_flags; - - vk_range.aspectMask = vk_aspect_mask_from_format(&format_vk->f); - vk_range.baseMipLevel = 0; - vk_range.levelCount = VK_REMAINING_MIP_LEVELS; - vk_range.baseArrayLayer = 0; - vk_range.layerCount = VK_REMAINING_ARRAY_LAYERS; - - wined3d_context_vk_reference_texture(context_vk, texture_vk); - wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, - 0, 0, - VK_IMAGE_LAYOUT_UNDEFINED, texture_vk->layout, - texture_vk->image.vk_image, &vk_range); - - texture_vk->t.flags |= WINED3D_TEXTURE_RGB_ALLOCATED; - - TRACE("Created image 0x%s, memory 0x%s for texture %p.\n", - wine_dbgstr_longlong(texture_vk->image.vk_image), wine_dbgstr_longlong(texture_vk->image.vk_memory), texture_vk); - - return TRUE; -} - -static BOOL wined3d_texture_vk_prepare_buffer_object(struct wined3d_texture_vk *texture_vk, - unsigned int sub_resource_idx, struct wined3d_context_vk *context_vk) -{ - struct wined3d_texture_sub_resource *sub_resource; - struct wined3d_bo_vk *bo; - - sub_resource = &texture_vk->t.sub_resources[sub_resource_idx]; - if (sub_resource->bo) - return TRUE; - - if (!(bo = malloc(sizeof(*bo)))) - return FALSE; - - if (!wined3d_context_vk_create_bo(context_vk, sub_resource->size, - VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, bo)) - { - free(bo); - return FALSE; - } - - /* Texture buffer objects receive a barrier to HOST_READ in wined3d_texture_vk_download_data(), - * so they don't need it when they are mapped for reading. */ - bo->host_synced = true; - sub_resource->bo = &bo->b; - TRACE("Created buffer object %p for texture %p, sub-resource %u.\n", bo, texture_vk, sub_resource_idx); - return TRUE; -} - -static BOOL wined3d_texture_vk_prepare_location(struct wined3d_texture *texture, - unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location) -{ - switch (location) - { - case WINED3D_LOCATION_SYSMEM: - return texture->sub_resources[sub_resource_idx].user_memory ? TRUE - : wined3d_resource_prepare_sysmem(&texture->resource); - - case WINED3D_LOCATION_TEXTURE_RGB: - return wined3d_texture_vk_prepare_texture(wined3d_texture_vk(texture), wined3d_context_vk(context)); - - case WINED3D_LOCATION_BUFFER: - return wined3d_texture_vk_prepare_buffer_object(wined3d_texture_vk(texture), sub_resource_idx, - wined3d_context_vk(context)); - - default: - FIXME("Unhandled location %s.\n", wined3d_debug_location(location)); - return FALSE; - } -} - -static BOOL wined3d_texture_vk_load_location(struct wined3d_texture *texture, - unsigned int sub_resource_idx, struct wined3d_context *context, uint32_t location) -{ - if (!wined3d_texture_vk_prepare_location(texture, sub_resource_idx, context, location)) - return FALSE; - - switch (location) - { - case WINED3D_LOCATION_TEXTURE_RGB: - return wined3d_texture_vk_load_texture(wined3d_texture_vk(texture), sub_resource_idx, context); - - case WINED3D_LOCATION_SYSMEM: - case WINED3D_LOCATION_BUFFER: - return wined3d_texture_vk_load_sysmem(wined3d_texture_vk(texture), sub_resource_idx, context, location); - - default: - FIXME("Unimplemented location %s.\n", wined3d_debug_location(location)); - return FALSE; - } -} - -static void wined3d_texture_vk_unload_location(struct wined3d_texture *texture, - struct wined3d_context *context, unsigned int location) -{ - struct wined3d_texture_vk *texture_vk = wined3d_texture_vk(texture); - struct wined3d_context_vk *context_vk = wined3d_context_vk(context); - unsigned int i, sub_count; - - TRACE("texture %p, context %p, location %s.\n", texture, context, wined3d_debug_location(location)); - - switch (location) - { - case WINED3D_LOCATION_TEXTURE_RGB: - if (texture_vk->default_image_info.imageView) - { - wined3d_context_vk_destroy_vk_image_view(context_vk, - texture_vk->default_image_info.imageView, texture_vk->image.command_buffer_id); - texture_vk->default_image_info.imageView = VK_NULL_HANDLE; - } - - if (texture_vk->image.vk_image) - wined3d_context_vk_destroy_image(context_vk, &texture_vk->image); - break; - - case WINED3D_LOCATION_BUFFER: - sub_count = texture->level_count * texture->layer_count; - for (i = 0; i < sub_count; ++i) - { - struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[i]; - - if (sub_resource->bo) - { - struct wined3d_bo_vk *bo_vk = wined3d_bo_vk(sub_resource->bo); - - wined3d_context_vk_destroy_bo(context_vk, bo_vk); - free(bo_vk); - sub_resource->bo = NULL; - } - } - break; - - case WINED3D_LOCATION_TEXTURE_SRGB: - case WINED3D_LOCATION_RB_MULTISAMPLE: - case WINED3D_LOCATION_RB_RESOLVED: - break; - - default: - ERR("Unhandled location %s.\n", wined3d_debug_location(location)); - break; - } -} - -static const struct wined3d_texture_ops wined3d_texture_vk_ops = -{ - wined3d_texture_vk_prepare_location, - wined3d_texture_vk_load_location, - wined3d_texture_vk_unload_location, - wined3d_texture_vk_upload_data, - wined3d_texture_vk_download_data, -}; - -HRESULT wined3d_texture_vk_init(struct wined3d_texture_vk *texture_vk, struct wined3d_device *device, - const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count, - uint32_t flags, void *parent, const struct wined3d_parent_ops *parent_ops) -{ - TRACE("texture_vk %p, device %p, desc %p, layer_count %u, " - "level_count %u, flags %#x, parent %p, parent_ops %p.\n", - texture_vk, device, desc, layer_count, - level_count, flags, parent, parent_ops); - - return wined3d_texture_init(&texture_vk->t, desc, layer_count, level_count, - flags, device, parent, parent_ops, &texture_vk[1], &wined3d_texture_vk_ops); -} - -enum VkImageLayout wined3d_layout_from_bind_mask(const struct wined3d_texture_vk *texture_vk, const uint32_t bind_mask) -{ - assert(wined3d_popcount(bind_mask) == 1); - - /* We want to avoid switching between LAYOUT_GENERAL and other layouts. In Radeon GPUs (and presumably - * others), this will trigger decompressing and recompressing the texture. We also hardcode the layout - * into views when they are created. */ - if (texture_vk->layout == VK_IMAGE_LAYOUT_GENERAL) - return VK_IMAGE_LAYOUT_GENERAL; - - switch (bind_mask) - { - case WINED3D_BIND_RENDER_TARGET: - return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - case WINED3D_BIND_DEPTH_STENCIL: - return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - case WINED3D_BIND_SHADER_RESOURCE: - return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - default: - ERR("Unexpected bind mask %s.\n", wined3d_debug_bind_flags(bind_mask)); - return VK_IMAGE_LAYOUT_GENERAL; - } -} - -void wined3d_texture_vk_barrier(struct wined3d_texture_vk *texture_vk, - struct wined3d_context_vk *context_vk, uint32_t bind_mask) -{ - enum VkImageLayout new_layout; - uint32_t src_bind_mask = 0; - - TRACE("texture_vk %p, context_vk %p, bind_mask %s.\n", - texture_vk, context_vk, wined3d_debug_bind_flags(bind_mask)); - - new_layout = wined3d_layout_from_bind_mask(texture_vk, bind_mask); - - /* A layout transition is potentially a read-write operation, so even if we - * prepare the texture to e.g. read only shader resource mode, we have to wait - * for past operations to finish. */ - if (bind_mask & ~WINED3D_READ_ONLY_BIND_MASK || new_layout != texture_vk->layout) - { - src_bind_mask = texture_vk->bind_mask & WINED3D_READ_ONLY_BIND_MASK; - if (!src_bind_mask) - src_bind_mask = texture_vk->bind_mask; - - texture_vk->bind_mask = bind_mask; - } - else if ((texture_vk->bind_mask & bind_mask) != bind_mask) - { - src_bind_mask = texture_vk->bind_mask & ~WINED3D_READ_ONLY_BIND_MASK; - texture_vk->bind_mask |= bind_mask; - } - - if (src_bind_mask) - { - VkImageSubresourceRange vk_range; - - TRACE(" %s(%x) -> %s(%x).\n", - wined3d_debug_bind_flags(src_bind_mask), texture_vk->layout, - wined3d_debug_bind_flags(bind_mask), new_layout); - - vk_range.aspectMask = vk_aspect_mask_from_format(texture_vk->t.resource.format); - vk_range.baseMipLevel = 0; - vk_range.levelCount = VK_REMAINING_MIP_LEVELS; - vk_range.baseArrayLayer = 0; - vk_range.layerCount = VK_REMAINING_ARRAY_LAYERS; - - wined3d_context_vk_image_barrier(context_vk, wined3d_context_vk_get_command_buffer(context_vk), - vk_pipeline_stage_mask_from_bind_flags(src_bind_mask), - vk_pipeline_stage_mask_from_bind_flags(bind_mask), - vk_access_mask_from_bind_flags(src_bind_mask), vk_access_mask_from_bind_flags(bind_mask), - texture_vk->layout, new_layout, texture_vk->image.vk_image, &vk_range); - - texture_vk->layout = new_layout; - } -} - -/* This is called when a texture is used as render target and shader resource - * or depth stencil and shader resource at the same time. This can either be - * read-only simultaneos use as depth stencil, but also for rendering to one - * subresource while reading from another. Without tracking of barriers and - * layouts per subresource VK_IMAGE_LAYOUT_GENERAL is the only thing we can do. */ -void wined3d_texture_vk_make_generic(struct wined3d_texture_vk *texture_vk, - struct wined3d_context_vk *context_vk) -{ - VkImageSubresourceRange vk_range; - - if (texture_vk->layout == VK_IMAGE_LAYOUT_GENERAL) - return; - - vk_range.aspectMask = vk_aspect_mask_from_format(texture_vk->t.resource.format); - vk_range.baseMipLevel = 0; - vk_range.levelCount = VK_REMAINING_MIP_LEVELS; - vk_range.baseArrayLayer = 0; - vk_range.layerCount = VK_REMAINING_ARRAY_LAYERS; - - wined3d_context_vk_image_barrier(context_vk, wined3d_context_vk_get_command_buffer(context_vk), - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, - 0, 0, - texture_vk->layout, VK_IMAGE_LAYOUT_GENERAL, texture_vk->image.vk_image, &vk_range); - - texture_vk->layout = VK_IMAGE_LAYOUT_GENERAL; - texture_vk->default_image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; -} - -static void ffp_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context) -{ - struct wined3d_blitter *next; - - if ((next = blitter->next)) - next->ops->blitter_destroy(next, context); - - free(blitter); -} - -static bool is_full_clear(const struct wined3d_rendertarget_view *rtv, const RECT *draw_rect, const RECT *clear_rect) -{ - unsigned int height = rtv->height; - unsigned int width = rtv->width; - - /* partial draw rect */ - if (draw_rect->left || draw_rect->top || draw_rect->right < width || draw_rect->bottom < height) - return false; - - /* partial clear rect */ - if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0 - || clear_rect->right < width || clear_rect->bottom < height)) - return false; - - return true; -} - -static void ffp_blitter_clear_rendertargets(struct wined3d_device *device, unsigned int rt_count, - const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rect, const RECT *draw_rect, - uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int stencil) -{ - struct wined3d_rendertarget_view *rtv = rt_count ? fb->render_targets[0] : NULL; - struct wined3d_rendertarget_view *dsv = fb->depth_stencil; - const struct wined3d_state *state = &device->cs->state; - struct wined3d_texture *depth_stencil = NULL; - unsigned int drawable_width, drawable_height; - const struct wined3d_gl_info *gl_info; - struct wined3d_context_gl *context_gl; - struct wined3d_texture *target = NULL; - struct wined3d_color colour_srgb; - struct wined3d_context *context; - GLbitfield clear_mask = 0; - bool render_offscreen; - unsigned int i; - - if (rtv && rtv->resource->type != WINED3D_RTYPE_BUFFER) - { - target = texture_from_resource(rtv->resource); - context = context_acquire(device, target, rtv->sub_resource_idx); - } - else - { - context = context_acquire(device, NULL, 0); - } - context_gl = wined3d_context_gl(context); - - if (dsv && dsv->resource->type != WINED3D_RTYPE_BUFFER) - depth_stencil = texture_from_resource(dsv->resource); - - if (!context_gl->valid) - { - context_release(context); - WARN("Invalid context, skipping clear.\n"); - return; - } - gl_info = context_gl->gl_info; - - /* When we're clearing parts of the drawable, make sure that the target - * surface is well up to date in the drawable. After the clear we'll mark - * the drawable up to date, so we have to make sure that this is true for - * the cleared parts, and the untouched parts. - * - * If we're clearing the whole target there is no need to copy it into the - * drawable, it will be overwritten anyway. If we're not clearing the - * colour buffer we don't have to copy either since we're not going to set - * the drawable up to date. We have to check all settings that limit the - * clear area though. Do not bother checking all this if the destination - * surface is in the drawable anyway. */ - for (i = 0; i < rt_count; ++i) - { - struct wined3d_rendertarget_view *rtv = fb->render_targets[i]; - - if (rtv && rtv->format->id != WINED3DFMT_NULL) - { - if (flags & WINED3DCLEAR_TARGET && !is_full_clear(rtv, draw_rect, rect_count ? clear_rect : NULL)) - wined3d_rendertarget_view_load_location(rtv, context, rtv->resource->draw_binding); - else - wined3d_rendertarget_view_prepare_location(rtv, context, rtv->resource->draw_binding); - } - } - - if (target) - { - render_offscreen = wined3d_resource_is_offscreen(&target->resource); - wined3d_rendertarget_view_get_drawable_size(rtv, context, &drawable_width, &drawable_height); - } - else - { - unsigned int ds_level = dsv->sub_resource_idx % depth_stencil->level_count; - - render_offscreen = true; - drawable_width = wined3d_texture_get_level_width(depth_stencil, ds_level); - drawable_height = wined3d_texture_get_level_height(depth_stencil, ds_level); - } - - if (depth_stencil) - { - DWORD ds_location = render_offscreen ? dsv->resource->draw_binding : WINED3D_LOCATION_DRAWABLE; - - if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) - && !is_full_clear(dsv, draw_rect, rect_count ? clear_rect : NULL)) - wined3d_rendertarget_view_load_location(dsv, context, ds_location); - else - wined3d_rendertarget_view_prepare_location(dsv, context, ds_location); - - if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) - { - wined3d_rendertarget_view_validate_location(dsv, ds_location); - wined3d_rendertarget_view_invalidate_location(dsv, ~ds_location); - } - } - - if (!wined3d_context_gl_apply_clear_state(context_gl, state, rt_count, fb)) - { - context_release(context); - WARN("Failed to apply clear state, skipping clear.\n"); - return; - } - - /* Only set the values up once, as they are not changing. */ - if (flags & WINED3DCLEAR_STENCIL) - { - if (gl_info->supported[EXT_STENCIL_TWO_SIDE]) - gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT); - gl_info->gl_ops.gl.p_glStencilMask(~0u); - context_invalidate_state(context, STATE_DEPTH_STENCIL); - gl_info->gl_ops.gl.p_glClearStencil(stencil); - checkGLcall("glClearStencil"); - clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT; - } - - if (flags & WINED3DCLEAR_ZBUFFER) - { - gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE); - context_invalidate_state(context, STATE_DEPTH_STENCIL); - if (gl_info->supported[ARB_ES2_COMPATIBILITY]) - GL_EXTCALL(glClearDepthf(depth)); - else - gl_info->gl_ops.gl.p_glClearDepth(depth); - checkGLcall("glClearDepth"); - clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT; - } - - if (flags & WINED3DCLEAR_TARGET) - { - for (i = 0; i < rt_count; ++i) - { - struct wined3d_rendertarget_view *rtv = fb->render_targets[i]; - - if (!rtv) - continue; - - if (rtv->resource->type == WINED3D_RTYPE_BUFFER) - { - FIXME("Not supported on buffer resources.\n"); - continue; - } - - wined3d_rendertarget_view_validate_location(rtv, rtv->resource->draw_binding); - wined3d_rendertarget_view_invalidate_location(rtv, ~rtv->resource->draw_binding); - } - - if (!gl_info->supported[ARB_FRAMEBUFFER_SRGB] && needs_srgb_write(context->d3d_info, state, fb)) - { - if (rt_count > 1) - WARN("Clearing multiple sRGB render targets without GL_ARB_framebuffer_sRGB " - "support, this might cause graphical issues.\n"); - - wined3d_colour_srgb_from_linear(&colour_srgb, colour); - colour = &colour_srgb; - } - - gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - context_invalidate_state(context, STATE_BLEND); - gl_info->gl_ops.gl.p_glClearColor(colour->r, colour->g, colour->b, colour->a); - checkGLcall("glClearColor"); - clear_mask = clear_mask | GL_COLOR_BUFFER_BIT; - } - - if (!rect_count) - { - if (render_offscreen) - { - gl_info->gl_ops.gl.p_glScissor(draw_rect->left, draw_rect->top, - draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top); - } - else - { - gl_info->gl_ops.gl.p_glScissor(draw_rect->left, drawable_height - draw_rect->bottom, - draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top); - } - gl_info->gl_ops.gl.p_glClear(clear_mask); - } - else - { - RECT current_rect; - - /* Now process each rect in turn. */ - for (i = 0; i < rect_count; ++i) - { - /* Note that GL uses lower left, width/height. */ - IntersectRect(¤t_rect, draw_rect, &clear_rect[i]); - - TRACE("clear_rect[%u] %s, current_rect %s.\n", i, - wine_dbgstr_rect(&clear_rect[i]), - wine_dbgstr_rect(¤t_rect)); - - /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored - * silently. The rectangle is not cleared, no error is returned, - * but further rectangles are still cleared if they are valid. */ - if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom) - { - TRACE("Rectangle with negative dimensions, ignoring.\n"); - continue; - } - - if (render_offscreen) - { - gl_info->gl_ops.gl.p_glScissor(current_rect.left, current_rect.top, - current_rect.right - current_rect.left, current_rect.bottom - current_rect.top); - } - else - { - gl_info->gl_ops.gl.p_glScissor(current_rect.left, drawable_height - current_rect.bottom, - current_rect.right - current_rect.left, current_rect.bottom - current_rect.top); - } - gl_info->gl_ops.gl.p_glClear(clear_mask); - } - } - context->scissor_rect_count = WINED3D_MAX_VIEWPORTS; - checkGLcall("clear"); - - if (flags & WINED3DCLEAR_TARGET && target->swapchain && target->swapchain->front_buffer == target) - gl_info->gl_ops.gl.p_glFlush(); - - context_release(context); -} - -static bool blitter_use_cpu_clear(struct wined3d_rendertarget_view *view) -{ - struct wined3d_resource *resource; - struct wined3d_texture *texture; - DWORD locations; - - resource = view->resource; - if (resource->type == WINED3D_RTYPE_BUFFER) - return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU); - - texture = texture_from_resource(resource); - locations = texture->sub_resources[view->sub_resource_idx].locations; - if (locations & (resource->map_binding | WINED3D_LOCATION_DISCARDED)) - return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU) - || texture->resource.pin_sysmem; - - return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU) - && !(texture->flags & WINED3D_TEXTURE_CONVERTED); -} - -static void ffp_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device, - unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects, - const RECT *draw_rect, uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int stencil) +HRESULT CDECL wined3d_texture_get_dc(struct wined3d_texture *texture, unsigned int sub_resource_idx, HDC *dc) { - struct wined3d_rendertarget_view *view, *previous = NULL; - bool have_identical_size = TRUE; - struct wined3d_fb_state tmp_fb; - unsigned int next_rt_count = 0; - struct wined3d_blitter *next; - DWORD next_flags = 0; - unsigned int i; - - if (flags & WINED3DCLEAR_TARGET) - { - for (i = 0; i < rt_count; ++i) - { - if (!(view = fb->render_targets[i])) - continue; - - if (blitter_use_cpu_clear(view) - || (!(view->resource->bind_flags & WINED3D_BIND_RENDER_TARGET) - && !(view->format_caps & WINED3D_FORMAT_CAP_FBO_ATTACHABLE))) - { - next_flags |= WINED3DCLEAR_TARGET; - flags &= ~WINED3DCLEAR_TARGET; - next_rt_count = rt_count; - rt_count = 0; - break; - } - - /* FIXME: We should reject colour fills on formats with fixups, - * but this would break P8 colour fills for example. */ - } - } - - if ((flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) && (view = fb->depth_stencil) - && (!view->format->depth_size || (flags & WINED3DCLEAR_ZBUFFER)) - && (!view->format->stencil_size || (flags & WINED3DCLEAR_STENCIL)) - && blitter_use_cpu_clear(view)) - { - next_flags |= flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL); - flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL); - } - - if (flags) - { - for (i = 0; i < rt_count; ++i) - { - if (!(view = fb->render_targets[i])) - continue; - - if (previous && (previous->width != view->width || previous->height != view->height)) - have_identical_size = false; - previous = view; - } - if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) - { - view = fb->depth_stencil; - - if (previous && (previous->width != view->width || previous->height != view->height)) - have_identical_size = false; - } - - if (have_identical_size) - { - ffp_blitter_clear_rendertargets(device, rt_count, fb, rect_count, - clear_rects, draw_rect, flags, colour, depth, stencil); - } - else - { - for (i = 0; i < rt_count; ++i) - { - if (!(view = fb->render_targets[i])) - continue; - - tmp_fb.render_targets[0] = view; - tmp_fb.depth_stencil = NULL; - ffp_blitter_clear_rendertargets(device, 1, &tmp_fb, rect_count, - clear_rects, draw_rect, WINED3DCLEAR_TARGET, colour, depth, stencil); - } - if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) - { - tmp_fb.render_targets[0] = NULL; - tmp_fb.depth_stencil = fb->depth_stencil; - ffp_blitter_clear_rendertargets(device, 0, &tmp_fb, rect_count, - clear_rects, draw_rect, flags & ~WINED3DCLEAR_TARGET, colour, depth, stencil); - } - } - } - - if (next_flags && (next = blitter->next)) - next->ops->blitter_clear(next, device, next_rt_count, fb, rect_count, - clear_rects, draw_rect, next_flags, colour, depth, stencil); -} + struct wined3d_device *device = texture->resource.device; + struct wined3d_texture_sub_resource *sub_resource; + struct wined3d_dc_info *dc_info;
-static DWORD ffp_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op, - struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, - DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture, - unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect, - const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter, - const struct wined3d_format *resolve_format) -{ - struct wined3d_blitter *next; + TRACE("texture %p, sub_resource_idx %u, dc %p.\n", texture, sub_resource_idx, dc);
- if (!(next = blitter->next)) + if (!(texture->flags & WINED3D_TEXTURE_GET_DC)) { - ERR("No blitter to handle blit op %#x.\n", op); - return dst_location; + WARN("Texture does not support GetDC\n"); + /* Don't touch the DC */ + return WINED3DERR_INVALIDCALL; }
- return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location, - src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter, - resolve_format); -} - -static const struct wined3d_blitter_ops ffp_blitter_ops = -{ - ffp_blitter_destroy, - ffp_blitter_clear, - ffp_blitter_blit, -}; - -void wined3d_ffp_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info) -{ - struct wined3d_blitter *blitter; - - if (!(blitter = malloc(sizeof(*blitter)))) - return; - - TRACE("Created blitter %p.\n", blitter); - - blitter->ops = &ffp_blitter_ops; - blitter->next = *next; - *next = blitter; -} - -static void fbo_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context) -{ - struct wined3d_blitter *next; - - if ((next = blitter->next)) - next->ops->blitter_destroy(next, context); - - free(blitter); -} - -static void fbo_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device, - unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects, - const RECT *draw_rect, uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int stencil) -{ - struct wined3d_blitter *next; - - if ((next = blitter->next)) - next->ops->blitter_clear(next, device, rt_count, fb, rect_count, - clear_rects, draw_rect, flags, colour, depth, stencil); -} - -static DWORD fbo_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op, - struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, - DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture, - unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect, - const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter, - const struct wined3d_format *resolve_format) -{ - struct wined3d_context_gl *context_gl = wined3d_context_gl(context); - struct wined3d_resource *src_resource, *dst_resource; - enum wined3d_blit_op blit_op = op; - struct wined3d_device *device; - struct wined3d_blitter *next; - - TRACE("blitter %p, op %#x, context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, " - "src_rect %s, dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s, " - "colour_key %p, filter %s, resolve_format %p.\n", - blitter, op, context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location), - wine_dbgstr_rect(src_rect), dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location), - wine_dbgstr_rect(dst_rect), colour_key, debug_d3dtexturefiltertype(filter), resolve_format); - - src_resource = &src_texture->resource; - dst_resource = &dst_texture->resource; - - device = dst_resource->device; + if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx))) + return WINED3DERR_INVALIDCALL;
- if (blit_op == WINED3D_BLIT_OP_RAW_BLIT && dst_resource->format->id == src_resource->format->id) + if (texture->resource.type != WINED3D_RTYPE_TEXTURE_2D) { - if (dst_resource->format->depth_size || dst_resource->format->stencil_size) - blit_op = WINED3D_BLIT_OP_DEPTH_BLIT; - else - blit_op = WINED3D_BLIT_OP_COLOR_BLIT; + WARN("Not supported on %s resources.\n", debug_d3dresourcetype(texture->resource.type)); + return WINED3DERR_INVALIDCALL; }
- if (!fbo_blitter_supported(blit_op, context_gl->gl_info, - src_resource, src_location, dst_resource, dst_location)) - { - if (!(next = blitter->next)) - { - ERR("No blitter to handle blit op %#x.\n", op); - return dst_location; - } - - TRACE("Forwarding to blitter %p.\n", next); - return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location, - src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter, - resolve_format); - } + if (texture->resource.map_count && !(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT)) + return WINED3DERR_INVALIDCALL;
- if (blit_op == WINED3D_BLIT_OP_COLOR_BLIT) + if (!(dc_info = texture->dc_info) || !dc_info[sub_resource_idx].dc) { - TRACE("Colour blit.\n"); - texture2d_blt_fbo(device, context, filter, src_texture, src_sub_resource_idx, src_location, - src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, resolve_format); - return dst_location; - } + struct wined3d_texture_idx texture_idx = {texture, sub_resource_idx};
- if (blit_op == WINED3D_BLIT_OP_DEPTH_BLIT) - { - TRACE("Depth/stencil blit.\n"); - texture2d_depth_blt_fbo(device, context, src_texture, src_sub_resource_idx, src_location, - src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect); - return dst_location; + wined3d_cs_init_object(device->cs, wined3d_texture_create_dc, &texture_idx); + wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT); + if (!(dc_info = texture->dc_info) || !dc_info[sub_resource_idx].dc) + return WINED3DERR_INVALIDCALL; }
- ERR("This blitter does not implement blit op %#x.\n", blit_op); - return dst_location; -} - -static const struct wined3d_blitter_ops fbo_blitter_ops = -{ - fbo_blitter_destroy, - fbo_blitter_clear, - fbo_blitter_blit, -}; - -void wined3d_fbo_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info) -{ - struct wined3d_blitter *blitter; - - if (!(blitter = malloc(sizeof(*blitter)))) - return; + if (!(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT)) + texture->flags |= WINED3D_TEXTURE_DC_IN_USE; + ++texture->resource.map_count; + ++sub_resource->map_count;
- TRACE("Created blitter %p.\n", blitter); + *dc = dc_info[sub_resource_idx].dc; + TRACE("Returning dc %p.\n", *dc);
- blitter->ops = &fbo_blitter_ops; - blitter->next = *next; - *next = blitter; + return WINED3D_OK; }
-static void raw_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context) +HRESULT CDECL wined3d_texture_release_dc(struct wined3d_texture *texture, unsigned int sub_resource_idx, HDC dc) { - struct wined3d_blitter *next; - - if ((next = blitter->next)) - next->ops->blitter_destroy(next, context); + struct wined3d_device *device = texture->resource.device; + struct wined3d_texture_sub_resource *sub_resource; + struct wined3d_dc_info *dc_info;
- free(blitter); -} + TRACE("texture %p, sub_resource_idx %u, dc %p.\n", texture, sub_resource_idx, dc);
-static void raw_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device, - unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects, - const RECT *draw_rect, uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int stencil) -{ - struct wined3d_blitter *next; + if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx))) + return WINED3DERR_INVALIDCALL;
- if (!(next = blitter->next)) + if (texture->resource.type != WINED3D_RTYPE_TEXTURE_2D) { - ERR("No blitter to handle clear.\n"); - return; + WARN("Not supported on %s resources.\n", debug_d3dresourcetype(texture->resource.type)); + return WINED3DERR_INVALIDCALL; }
- TRACE("Forwarding to blitter %p.\n", next); - next->ops->blitter_clear(next, device, rt_count, fb, rect_count, - clear_rects, draw_rect, flags, colour, depth, stencil); -} - -static bool gl_formats_compatible(struct wined3d_texture *src_texture, DWORD src_location, - struct wined3d_texture *dst_texture, DWORD dst_location) -{ - GLuint src_internal, dst_internal; - bool src_ds, dst_ds; - - src_ds = src_texture->resource.format->depth_size || src_texture->resource.format->stencil_size; - dst_ds = dst_texture->resource.format->depth_size || dst_texture->resource.format->stencil_size; - if (src_ds == dst_ds) - return true; - /* Also check the internal format because, e.g. WINED3DFMT_D24_UNORM_S8_UINT has nonzero depth and stencil - * sizes as does WINED3DFMT_R24G8_TYPELESS when bound with flag WINED3D_BIND_DEPTH_STENCIL, but these share - * the same internal format with WINED3DFMT_R24_UNORM_X8_TYPELESS. */ - src_internal = wined3d_gl_get_internal_format(&src_texture->resource, - wined3d_format_gl(src_texture->resource.format), src_location == WINED3D_LOCATION_TEXTURE_SRGB); - dst_internal = wined3d_gl_get_internal_format(&dst_texture->resource, - wined3d_format_gl(dst_texture->resource.format), dst_location == WINED3D_LOCATION_TEXTURE_SRGB); - return src_internal == dst_internal; -} + if (!(texture->flags & (WINED3D_TEXTURE_GET_DC_LENIENT | WINED3D_TEXTURE_DC_IN_USE))) + return WINED3DERR_INVALIDCALL;
-static DWORD raw_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op, - struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, - DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture, - unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect, - const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter, - const struct wined3d_format *resolve_format) -{ - struct wined3d_texture_gl *src_texture_gl = wined3d_texture_gl(src_texture); - struct wined3d_texture_gl *dst_texture_gl = wined3d_texture_gl(dst_texture); - struct wined3d_context_gl *context_gl = wined3d_context_gl(context); - const struct wined3d_gl_info *gl_info = context_gl->gl_info; - unsigned int src_level, src_layer, dst_level, dst_layer; - struct wined3d_blitter *next; - GLuint src_name, dst_name; - DWORD location; - - /* If we would need to copy from a renderbuffer or drawable, we'd probably - * be better off using the FBO blitter directly, since we'd need to use it - * to copy the resource contents to the texture anyway. - * - * We also can't copy between depth/stencil and colour resources, since - * the formats are considered incompatible in OpenGL. */ - if (op != WINED3D_BLIT_OP_RAW_BLIT || !gl_formats_compatible(src_texture, src_location, dst_texture, dst_location) - || ((src_texture->resource.format_attrs | dst_texture->resource.format_attrs) - & WINED3D_FORMAT_ATTR_HEIGHT_SCALE) - || (src_texture->resource.format->id == dst_texture->resource.format->id - && (!(src_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB)) - || !(dst_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))))) + if (!(dc_info = texture->dc_info) || dc_info[sub_resource_idx].dc != dc) { - if (!(next = blitter->next)) - { - ERR("No blitter to handle blit op %#x.\n", op); - return dst_location; - } - - TRACE("Forwarding to blitter %p.\n", next); - return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location, - src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter, - resolve_format); + WARN("Application tries to release invalid DC %p, sub-resource DC is %p.\n", + dc, dc_info ? dc_info[sub_resource_idx].dc : NULL); + return WINED3DERR_INVALIDCALL; }
- TRACE("Blit using ARB_copy_image.\n"); - - src_level = src_sub_resource_idx % src_texture->level_count; - src_layer = src_sub_resource_idx / src_texture->level_count; - - dst_level = dst_sub_resource_idx % dst_texture->level_count; - dst_layer = dst_sub_resource_idx / dst_texture->level_count; - - location = src_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB); - if (!location) - location = src_texture->flags & WINED3D_TEXTURE_IS_SRGB - ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB; - if (!wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, location)) - ERR("Failed to load the source sub-resource into %s.\n", wined3d_debug_location(location)); - src_name = wined3d_texture_gl_get_texture_name(src_texture_gl, - context, location == WINED3D_LOCATION_TEXTURE_SRGB); - - location = dst_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB); - if (!location) - location = dst_texture->flags & WINED3D_TEXTURE_IS_SRGB - ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB; - if (wined3d_texture_is_full_rect(dst_texture, dst_level, dst_rect)) - { - if (!wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, location)) - ERR("Failed to prepare the destination sub-resource into %s.\n", wined3d_debug_location(location)); - } - else + if (!(texture->resource.usage & WINED3DUSAGE_OWNDC)) { - if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, location)) - ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(location)); - } - dst_name = wined3d_texture_gl_get_texture_name(dst_texture_gl, - context, location == WINED3D_LOCATION_TEXTURE_SRGB); - - GL_EXTCALL(glCopyImageSubData(src_name, src_texture_gl->target, src_level, - src_rect->left, src_rect->top, src_layer, dst_name, dst_texture_gl->target, dst_level, - dst_rect->left, dst_rect->top, dst_layer, src_rect->right - src_rect->left, - src_rect->bottom - src_rect->top, 1)); - checkGLcall("copy image data"); - - wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, location); - wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~location); - if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location)) - ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(dst_location)); - - return dst_location | location; -} - -static const struct wined3d_blitter_ops raw_blitter_ops = -{ - raw_blitter_destroy, - raw_blitter_clear, - raw_blitter_blit, -}; - -void wined3d_raw_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info) -{ - struct wined3d_blitter *blitter; - - if (!gl_info->supported[ARB_COPY_IMAGE]) - return; - - if (!(blitter = malloc(sizeof(*blitter)))) - return; - - TRACE("Created blitter %p.\n", blitter); - - blitter->ops = &raw_blitter_ops; - blitter->next = *next; - *next = blitter; -} - -static void vk_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context) -{ - struct wined3d_blitter *next; + struct wined3d_texture_idx texture_idx = {texture, sub_resource_idx};
- TRACE("blitter %p, context %p.\n", blitter, context); + wined3d_cs_destroy_object(device->cs, wined3d_texture_destroy_dc, &texture_idx); + wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT); + }
- if ((next = blitter->next)) - next->ops->blitter_destroy(next, context); + --sub_resource->map_count; + if (!--texture->resource.map_count && texture->update_map_binding) + wined3d_texture_update_map_binding(texture); + if (!(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT)) + texture->flags &= ~WINED3D_TEXTURE_DC_IN_USE;
- free(blitter); + return WINED3D_OK; }
-static void vk_blitter_clear_rendertargets(struct wined3d_context_vk *context_vk, unsigned int rt_count, - const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects, const RECT *draw_rect, - uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int stencil) +void wined3d_texture_upload_from_texture(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, + unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, struct wined3d_texture *src_texture, + unsigned int src_sub_resource_idx, const struct wined3d_box *src_box) { - unsigned int i, attachment_count, immediate_rt_count = 0, delay_count = 0; - VkClearValue clear_values[WINED3D_MAX_RENDER_TARGETS + 1]; - VkImageView views[WINED3D_MAX_RENDER_TARGETS + 1]; - struct wined3d_rendertarget_view_vk *rtv_vk; - struct wined3d_rendertarget_view *view; - const struct wined3d_vk_info *vk_info; - struct wined3d_fb_state immediate_fb; - struct wined3d_device_vk *device_vk; - VkCommandBuffer vk_command_buffer; - VkRenderPassBeginInfo begin_desc; - VkFramebufferCreateInfo fb_desc; - VkFramebuffer vk_framebuffer; - VkRenderPass vk_render_pass; - bool depth_stencil = false; - unsigned int layer_count; - VkClearColorValue *c; - VkResult vr; - RECT r; - - TRACE("context_vk %p, rt_count %u, fb %p, rect_count %u, clear_rects %p, " - "draw_rect %s, flags %#x, colour %s, depth %.8e, stencil %#x.\n", - context_vk, rt_count, fb, rect_count, clear_rects, - wine_dbgstr_rect(draw_rect), flags, debug_color(colour), depth, stencil); - - device_vk = wined3d_device_vk(context_vk->c.device); - vk_info = context_vk->vk_info; - - if (!(flags & WINED3DCLEAR_TARGET)) - rt_count = 0; - - for (i = 0, attachment_count = 0, layer_count = 1; i < rt_count; ++i) - { - if (!(view = fb->render_targets[i])) - continue; - - /* Don't delay typeless clears because the data written into the resource depends on the - * view format. Except all-zero clears, those should result in zeros in either case. - * - * We could store the clear format along with the clear value, but then we'd have to - * create a matching RTV at draw time, which would need its own render pass, thus mooting - * the point of the delayed clear. (Unless we are lucky enough that the application - * draws with the same RTV as it clears.) */ - if (is_full_clear(view, draw_rect, clear_rects) - && (!wined3d_format_is_typeless(view->resource->format) || (!colour->r && !colour->g - && !colour->b && !colour->a))) - { - struct wined3d_texture *texture = texture_from_resource(view->resource); - wined3d_rendertarget_view_validate_location(view, WINED3D_LOCATION_CLEARED); - wined3d_rendertarget_view_invalidate_location(view, ~WINED3D_LOCATION_CLEARED); - texture->sub_resources[view->sub_resource_idx].clear_value.colour = *colour; - delay_count++; - continue; - } - else - { - wined3d_rendertarget_view_load_location(view, &context_vk->c, view->resource->draw_binding); - } - wined3d_rendertarget_view_validate_location(view, view->resource->draw_binding); - wined3d_rendertarget_view_invalidate_location(view, ~view->resource->draw_binding); - - immediate_fb.render_targets[immediate_rt_count++] = view; - rtv_vk = wined3d_rendertarget_view_vk(view); - views[attachment_count] = wined3d_rendertarget_view_vk_get_image_view(rtv_vk, context_vk); - wined3d_rendertarget_view_vk_barrier(rtv_vk, context_vk, WINED3D_BIND_RENDER_TARGET); - - c = &clear_values[attachment_count].color; - wined3d_format_colour_to_vk(view->format, colour, c); - - if (view->layer_count > layer_count) - layer_count = view->layer_count; - - ++attachment_count; - } - - if (!attachment_count) - flags &= ~WINED3DCLEAR_TARGET; - - if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && (view = fb->depth_stencil)) - { - DWORD full_flags = 0; - - /* Vulkan can clear only depth or stencil, but at the moment we can't put the depth and - * stencil parts in separate locations. It isn't easy to do either, as such a half-cleared - * texture would need to be handled not just as a DS target but also when used as a shader - * resource or accessed on sysmem. */ - if (view->format->depth_size) - full_flags = WINED3DCLEAR_ZBUFFER; - if (view->format->stencil_size) - full_flags |= WINED3DCLEAR_STENCIL; - - if (!is_full_clear(view, draw_rect, clear_rects) || (flags & full_flags) != full_flags - || (wined3d_format_is_typeless(view->resource->format) && (depth || stencil))) - { - wined3d_rendertarget_view_load_location(view, &context_vk->c, view->resource->draw_binding); - wined3d_rendertarget_view_validate_location(view, view->resource->draw_binding); - wined3d_rendertarget_view_invalidate_location(view, ~view->resource->draw_binding); - - immediate_fb.depth_stencil = view; - rtv_vk = wined3d_rendertarget_view_vk(view); - views[attachment_count] = wined3d_rendertarget_view_vk_get_image_view(rtv_vk, context_vk); - wined3d_rendertarget_view_vk_barrier(rtv_vk, context_vk, WINED3D_BIND_DEPTH_STENCIL); - - clear_values[attachment_count].depthStencil.depth = depth; - clear_values[attachment_count].depthStencil.stencil = stencil; - - if (view->layer_count > layer_count) - layer_count = view->layer_count; - - depth_stencil = true; - ++attachment_count; - } - else - { - struct wined3d_texture *texture = texture_from_resource(view->resource); - texture->sub_resources[view->sub_resource_idx].clear_value.depth = depth; - texture->sub_resources[view->sub_resource_idx].clear_value.stencil = stencil; - wined3d_rendertarget_view_validate_location(view, WINED3D_LOCATION_CLEARED); - wined3d_rendertarget_view_invalidate_location(view, ~WINED3D_LOCATION_CLEARED); - flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL); - delay_count++; - } - } - - if (!attachment_count) - { - TRACE("The clear has been delayed until draw time.\n"); - return; - } - - TRACE("Doing an immediate clear of %u attachments.\n", attachment_count); - if (delay_count) - TRACE_(d3d_perf)("Partial clear: %u immediate, %u delayed.\n", attachment_count, delay_count); - - if (!(vk_render_pass = wined3d_context_vk_get_render_pass(context_vk, &immediate_fb, - immediate_rt_count, flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL), flags))) - { - ERR("Failed to get render pass.\n"); - return; - } - - if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk))) - { - ERR("Failed to get command buffer.\n"); - return; - } + unsigned int src_row_pitch, src_slice_pitch; + unsigned int update_w, update_h, update_d; + unsigned int src_level, dst_level; + struct wined3d_context *context; + struct wined3d_bo_address data;
- fb_desc.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - fb_desc.pNext = NULL; - fb_desc.flags = 0; - fb_desc.renderPass = vk_render_pass; - fb_desc.attachmentCount = attachment_count; - fb_desc.pAttachments = views; - fb_desc.width = draw_rect->right - draw_rect->left; - fb_desc.height = draw_rect->bottom - draw_rect->top; - fb_desc.layers = layer_count; - if ((vr = VK_CALL(vkCreateFramebuffer(device_vk->vk_device, &fb_desc, NULL, &vk_framebuffer))) < 0) - { - ERR("Failed to create Vulkan framebuffer, vr %s.\n", wined3d_debug_vkresult(vr)); - return; - } + TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_x %u, dst_y %u, dst_z %u, " + "src_texture %p, src_sub_resource_idx %u, src_box %s.\n", + dst_texture, dst_sub_resource_idx, dst_x, dst_y, dst_z, + src_texture, src_sub_resource_idx, debug_box(src_box));
- begin_desc.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - begin_desc.pNext = NULL; - begin_desc.renderPass = vk_render_pass; - begin_desc.framebuffer = vk_framebuffer; - begin_desc.clearValueCount = attachment_count; - begin_desc.pClearValues = clear_values; + context = context_acquire(dst_texture->resource.device, NULL, 0);
- wined3d_context_vk_end_current_render_pass(context_vk); + /* Only load the sub-resource for partial updates. For newly allocated + * textures the texture wouldn't be the current location, and we'd upload + * zeroes just to overwrite them again. */ + update_w = src_box->right - src_box->left; + update_h = src_box->bottom - src_box->top; + update_d = src_box->back - src_box->front; + dst_level = dst_sub_resource_idx % dst_texture->level_count; + if (update_w == wined3d_texture_get_level_width(dst_texture, dst_level) + && update_h == wined3d_texture_get_level_height(dst_texture, dst_level) + && update_d == wined3d_texture_get_level_depth(dst_texture, dst_level)) + wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB); + else + wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
- for (i = 0; i < rect_count; ++i) - { - r.left = max(clear_rects[i].left, draw_rect->left); - r.top = max(clear_rects[i].top, draw_rect->top); - r.right = min(clear_rects[i].right, draw_rect->right); - r.bottom = min(clear_rects[i].bottom, draw_rect->bottom); - - if (r.left >= r.right || r.top >= r.bottom) - continue; - - begin_desc.renderArea.offset.x = r.left; - begin_desc.renderArea.offset.y = r.top; - begin_desc.renderArea.extent.width = r.right - r.left; - begin_desc.renderArea.extent.height = r.bottom - r.top; - VK_CALL(vkCmdBeginRenderPass(vk_command_buffer, &begin_desc, VK_SUBPASS_CONTENTS_INLINE)); - VK_CALL(vkCmdEndRenderPass(vk_command_buffer)); - } + src_level = src_sub_resource_idx % src_texture->level_count; + wined3d_texture_get_memory(src_texture, src_sub_resource_idx, context, &data); + wined3d_texture_get_pitch(src_texture, src_level, &src_row_pitch, &src_slice_pitch);
- wined3d_context_vk_destroy_vk_framebuffer(context_vk, vk_framebuffer, context_vk->current_command_buffer.id); + dst_texture->texture_ops->texture_upload_data(context, wined3d_const_bo_address(&data), + src_texture->resource.format, src_box, src_row_pitch, src_slice_pitch, dst_texture, + dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, dst_x, dst_y, dst_z);
- for (i = 0; i < immediate_rt_count; ++i) - wined3d_context_vk_reference_rendertarget_view(context_vk, - wined3d_rendertarget_view_vk(immediate_fb.render_targets[i])); + context_release(context);
- if (depth_stencil) - wined3d_context_vk_reference_rendertarget_view(context_vk, - wined3d_rendertarget_view_vk(immediate_fb.depth_stencil)); + wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB); + wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB); }
-static void vk_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device, - unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects, - const RECT *draw_rect, uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int stencil) +/* Partial downloads are not supported. */ +void wined3d_texture_download_from_texture(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, + struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx) { - struct wined3d_device_vk *device_vk = wined3d_device_vk(device); - struct wined3d_rendertarget_view *view, *previous = NULL; - struct wined3d_context_vk *context_vk; - bool have_identical_size = true; - struct wined3d_fb_state tmp_fb; - unsigned int next_rt_count = 0; - struct wined3d_blitter *next; - uint32_t next_flags = 0; - unsigned int i; - - TRACE("blitter %p, device %p, rt_count %u, fb %p, rect_count %u, clear_rects %p, " - "draw_rect %s, flags %#x, colour %s, depth %.8e, stencil %#x.\n", - blitter, device, rt_count, fb, rect_count, clear_rects, - wine_dbgstr_rect(draw_rect), flags, debug_color(colour), depth, stencil); + unsigned int src_level, dst_level, dst_row_pitch, dst_slice_pitch; + unsigned int dst_location = dst_texture->resource.map_binding; + struct wined3d_context *context; + struct wined3d_bo_address data; + struct wined3d_box src_box; + unsigned int src_location;
- if (!rect_count) - { - rect_count = 1; - clear_rects = draw_rect; - } + context = context_acquire(src_texture->resource.device, NULL, 0);
- if (flags & WINED3DCLEAR_TARGET) - { - for (i = 0; i < rt_count; ++i) - { - if (!(view = fb->render_targets[i])) - continue; + wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location); + wined3d_texture_get_bo_address(dst_texture, dst_sub_resource_idx, &data, dst_location);
- if (blitter_use_cpu_clear(view)) - { - next_flags |= WINED3DCLEAR_TARGET; - flags &= ~WINED3DCLEAR_TARGET; - next_rt_count = rt_count; - rt_count = 0; - break; - } - } - } + if (src_texture->sub_resources[src_sub_resource_idx].locations & WINED3D_LOCATION_TEXTURE_RGB) + src_location = WINED3D_LOCATION_TEXTURE_RGB; + else + src_location = WINED3D_LOCATION_TEXTURE_SRGB; + src_level = src_sub_resource_idx % src_texture->level_count; + wined3d_texture_get_level_box(src_texture, src_level, &src_box);
- if ((flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) && (view = fb->depth_stencil) - && (!view->format->depth_size || (flags & WINED3DCLEAR_ZBUFFER)) - && (!view->format->stencil_size || (flags & WINED3DCLEAR_STENCIL)) - && blitter_use_cpu_clear(view)) - { - next_flags |= flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL); - flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL); - } + dst_level = dst_sub_resource_idx % dst_texture->level_count; + wined3d_texture_get_pitch(dst_texture, dst_level, &dst_row_pitch, &dst_slice_pitch);
- if (flags) - { - context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0)); + src_texture->texture_ops->texture_download_data(context, src_texture, src_sub_resource_idx, src_location, + &src_box, &data, dst_texture->resource.format, 0, 0, 0, dst_row_pitch, dst_slice_pitch);
- for (i = 0; i < rt_count; ++i) - { - if (!(view = fb->render_targets[i])) - continue; + context_release(context);
- if (previous && (previous->width != view->width || previous->height != view->height)) - have_identical_size = false; - previous = view; - } - if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) - { - view = fb->depth_stencil; + wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, dst_location); + wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~dst_location); +}
- if (previous && (previous->width != view->width || previous->height != view->height)) - have_identical_size = false; - } +static void wined3d_texture_set_bo(struct wined3d_texture *texture, + unsigned sub_resource_idx, struct wined3d_context *context, struct wined3d_bo *bo) +{ + struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx]; + struct wined3d_bo *prev_bo = sub_resource->bo;
- if (have_identical_size) - { - vk_blitter_clear_rendertargets(context_vk, rt_count, fb, rect_count, - clear_rects, draw_rect, flags, colour, depth, stencil); - } - else - { - for (i = 0; i < rt_count; ++i) - { - if (!(view = fb->render_targets[i])) - continue; + TRACE("texture %p, sub_resource_idx %u, context %p, bo %p.\n", texture, sub_resource_idx, context, bo);
- tmp_fb.render_targets[0] = view; - tmp_fb.depth_stencil = NULL; - vk_blitter_clear_rendertargets(context_vk, 1, &tmp_fb, rect_count, - clear_rects, draw_rect, WINED3DCLEAR_TARGET, colour, depth, stencil); - } - if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) - { - tmp_fb.render_targets[0] = NULL; - tmp_fb.depth_stencil = fb->depth_stencil; - vk_blitter_clear_rendertargets(context_vk, 0, &tmp_fb, rect_count, - clear_rects, draw_rect, flags & ~WINED3DCLEAR_TARGET, colour, depth, stencil); - } - } + if (prev_bo) + { + struct wined3d_bo_user *bo_user;
- context_release(&context_vk->c); - } + LIST_FOR_EACH_ENTRY(bo_user, &prev_bo->users, struct wined3d_bo_user, entry) + bo_user->valid = false; + list_init(&prev_bo->users);
- if (!next_flags) - return; + assert(list_empty(&bo->users));
- if (!(next = blitter->next)) - { - ERR("No blitter to handle clear.\n"); - return; + wined3d_context_destroy_bo(context, prev_bo); + free(prev_bo); }
- TRACE("Forwarding to blitter %p.\n", next); - next->ops->blitter_clear(next, device, next_rt_count, fb, rect_count, - clear_rects, draw_rect, next_flags, colour, depth, stencil); + sub_resource->bo = bo; }
-static bool vk_blitter_blit_supported(enum wined3d_blit_op op, const struct wined3d_context *context, - const struct wined3d_resource *src_resource, const RECT *src_rect, - const struct wined3d_resource *dst_resource, const RECT *dst_rect, const struct wined3d_format *resolve_format) +void wined3d_texture_update_sub_resource(struct wined3d_texture *texture, unsigned int sub_resource_idx, + struct wined3d_context *context, const struct upload_bo *upload_bo, const struct wined3d_box *box, + unsigned int row_pitch, unsigned int slice_pitch) { - const struct wined3d_format *src_format = src_resource->format; - const struct wined3d_format *dst_format = dst_resource->format; - - if (!(dst_resource->access & WINED3D_RESOURCE_ACCESS_GPU)) - { - TRACE("Destination resource does not have GPU access.\n"); - return false; - } + unsigned int level = sub_resource_idx % texture->level_count; + unsigned int width = wined3d_texture_get_level_width(texture, level); + unsigned int height = wined3d_texture_get_level_height(texture, level); + unsigned int depth = wined3d_texture_get_level_depth(texture, level); + struct wined3d_box src_box;
- if (!(src_resource->access & WINED3D_RESOURCE_ACCESS_GPU)) + if (upload_bo->flags & UPLOAD_BO_RENAME_ON_UNMAP) { - TRACE("Source resource does not have GPU access.\n"); - return false; + wined3d_texture_set_bo(texture, sub_resource_idx, context, upload_bo->addr.buffer_object); + wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_BUFFER); + wined3d_texture_invalidate_location(texture, sub_resource_idx, ~WINED3D_LOCATION_BUFFER); + /* Try to free address space if we are not mapping persistently. */ + if (upload_bo->addr.buffer_object->map_ptr) + wined3d_context_unmap_bo_address(context, (const struct wined3d_bo_address *)&upload_bo->addr, 0, NULL); }
- if (dst_format->id != src_format->id) - { - if (!is_identity_fixup(dst_format->color_fixup)) - { - TRACE("Destination fixups are not supported.\n"); - return false; - } - - if (!is_identity_fixup(src_format->color_fixup)) - { - TRACE("Source fixups are not supported.\n"); - return false; - } + /* Only load the sub-resource for partial updates. */ + if (!box->left && !box->top && !box->front + && box->right == width && box->bottom == height && box->back == depth) + wined3d_texture_prepare_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB); + else + wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
- if (op != WINED3D_BLIT_OP_RAW_BLIT - && wined3d_format_vk(src_format)->vk_format != wined3d_format_vk(dst_format)->vk_format - && ((!wined3d_format_is_typeless(src_format) && !wined3d_format_is_typeless(dst_format)) - || !resolve_format)) - { - TRACE("Format conversion not supported.\n"); - return false; - } + wined3d_box_set(&src_box, 0, 0, box->right - box->left, box->bottom - box->top, 0, box->back - box->front); + texture->texture_ops->texture_upload_data(context, &upload_bo->addr, texture->resource.format, + &src_box, row_pitch, slice_pitch, texture, sub_resource_idx, + WINED3D_LOCATION_TEXTURE_RGB, box->left, box->top, box->front);
- if ((src_format->attrs | dst_format->attrs) & WINED3D_FORMAT_ATTR_PLANAR) - { - TRACE("Planar format conversion is not supported.\n"); - return false; - } - } + wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB); + wined3d_texture_invalidate_location(texture, sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB); +}
- if (wined3d_resource_get_sample_count(dst_resource) > 1) - { - TRACE("Multi-sample destination resource not supported.\n"); - return false; - } +struct wined3d_shader_resource_view * CDECL wined3d_texture_acquire_identity_srv(struct wined3d_texture *texture) +{ + struct wined3d_view_desc desc; + HRESULT hr;
- if (op == WINED3D_BLIT_OP_RAW_BLIT) - return true; + TRACE("texture %p.\n", texture);
- if (op != WINED3D_BLIT_OP_COLOR_BLIT) - { - TRACE("Unsupported blit operation %#x.\n", op); - return false; - } + if (texture->identity_srv) + return texture->identity_srv;
- if ((src_rect->right - src_rect->left != dst_rect->right - dst_rect->left) - || (src_rect->bottom - src_rect->top != dst_rect->bottom - dst_rect->top)) + desc.format_id = texture->resource.format->id; + /* The texture owns a reference to the SRV, so we can't have the SRV hold + * a reference to the texture. + * At the same time, a view must be destroyed before its texture, and we + * need a bound SRV to keep the texture alive even if it doesn't have any + * other references. + * In order to achieve this we have the objects share reference counts. + * This means the view doesn't hold a reference to the resource, but any + * references to the view are forwarded to the resource instead. The view + * is destroyed manually when all references are released. */ + desc.flags = WINED3D_VIEW_FORWARD_REFERENCE; + desc.u.texture.level_idx = 0; + desc.u.texture.level_count = texture->level_count; + desc.u.texture.layer_idx = 0; + desc.u.texture.layer_count = texture->layer_count; + if (FAILED(hr = wined3d_shader_resource_view_create(&desc, &texture->resource, + NULL, &wined3d_null_parent_ops, &texture->identity_srv))) { - TRACE("Scaling not supported.\n"); - return false; + ERR("Failed to create shader resource view, hr %#lx.\n", hr); + return NULL; } + wined3d_shader_resource_view_decref(texture->identity_srv);
- return true; + return texture->identity_srv; }
-static DWORD vk_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op, - struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, - DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture, - unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect, - const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter, - const struct wined3d_format *resolve_format) +static void wined3d_texture_no3d_upload_data(struct wined3d_context *context, + const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *src_format, + const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch, + struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, unsigned int dst_location, + unsigned int dst_x, unsigned int dst_y, unsigned int dst_z) { - struct wined3d_texture_vk *src_texture_vk = wined3d_texture_vk(src_texture); - struct wined3d_texture_vk *dst_texture_vk = wined3d_texture_vk(dst_texture); - struct wined3d_context_vk *context_vk = wined3d_context_vk(context); - const struct wined3d_vk_info *vk_info = context_vk->vk_info; - VkImageSubresourceRange vk_src_range, vk_dst_range; - VkImageLayout src_layout, dst_layout; - VkCommandBuffer vk_command_buffer; - struct wined3d_blitter *next; - unsigned src_sample_count; - bool resolve = false; - - TRACE("blitter %p, op %#x, context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, " - "src_rect %s, dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s, " - "colour_key %p, filter %s, resolve format %p.\n", - blitter, op, context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location), - wine_dbgstr_rect(src_rect), dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location), - wine_dbgstr_rect(dst_rect), colour_key, debug_d3dtexturefiltertype(filter), resolve_format); - - if (!vk_blitter_blit_supported(op, context, &src_texture->resource, src_rect, &dst_texture->resource, dst_rect, - resolve_format)) - goto next; - - src_sample_count = wined3d_resource_get_sample_count(&src_texture_vk->t.resource); - if (src_sample_count > 1) - resolve = true; - - vk_src_range.aspectMask = vk_aspect_mask_from_format(src_texture_vk->t.resource.format); - vk_src_range.baseMipLevel = src_sub_resource_idx % src_texture->level_count; - vk_src_range.levelCount = 1; - vk_src_range.baseArrayLayer = src_sub_resource_idx / src_texture->level_count; - vk_src_range.layerCount = 1; - - vk_dst_range.aspectMask = vk_aspect_mask_from_format(dst_texture_vk->t.resource.format); - vk_dst_range.baseMipLevel = dst_sub_resource_idx % dst_texture->level_count; - vk_dst_range.levelCount = 1; - vk_dst_range.baseArrayLayer = dst_sub_resource_idx / dst_texture->level_count; - vk_dst_range.layerCount = 1; - - if (!wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB)) - ERR("Failed to load the source sub-resource.\n"); - - if (wined3d_texture_is_full_rect(dst_texture, vk_dst_range.baseMipLevel, dst_rect)) - { - if (!wined3d_texture_prepare_location(dst_texture, - dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB)) - { - ERR("Failed to prepare the destination sub-resource.\n"); - goto next; - } - } - else - { - if (!wined3d_texture_load_location(dst_texture, - dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB)) - { - ERR("Failed to load the destination sub-resource.\n"); - goto next; - } - } + FIXME("Not implemented.\n"); +}
- if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk))) - { - ERR("Failed to get command buffer.\n"); - goto next; - } +static void wined3d_texture_no3d_download_data(struct wined3d_context *context, + struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, unsigned int src_location, + const struct wined3d_box *src_box, const struct wined3d_bo_address *dst_bo_addr, + const struct wined3d_format *dst_format, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, + unsigned int dst_row_pitch, unsigned int dst_slice_pitch) +{ + FIXME("Not implemented.\n"); +}
- if (src_texture_vk->layout == VK_IMAGE_LAYOUT_GENERAL) - src_layout = VK_IMAGE_LAYOUT_GENERAL; - else - src_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; +static BOOL wined3d_texture_no3d_prepare_location(struct wined3d_texture *texture, + unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location) +{ + if (location == WINED3D_LOCATION_SYSMEM) + return texture->sub_resources[sub_resource_idx].user_memory ? TRUE + : wined3d_resource_prepare_sysmem(&texture->resource);
- if (dst_texture_vk->layout == VK_IMAGE_LAYOUT_GENERAL) - dst_layout = VK_IMAGE_LAYOUT_GENERAL; - else - dst_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - - wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, - vk_access_mask_from_bind_flags(src_texture_vk->t.resource.bind_flags), - VK_ACCESS_TRANSFER_READ_BIT, src_texture_vk->layout, src_layout, - src_texture_vk->image.vk_image, &vk_src_range); - wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, - vk_access_mask_from_bind_flags(dst_texture_vk->t.resource.bind_flags), - VK_ACCESS_TRANSFER_WRITE_BIT, dst_texture_vk->layout, dst_layout, - dst_texture_vk->image.vk_image, &vk_dst_range); - - if (resolve) - { - const struct wined3d_format_vk *src_format_vk = wined3d_format_vk(src_texture->resource.format); - const struct wined3d_format_vk *dst_format_vk = wined3d_format_vk(dst_texture->resource.format); - const unsigned int usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT - | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - VkImageLayout resolve_src_layout, resolve_dst_layout; - VkImage src_vk_image, dst_vk_image; - VkImageSubresourceRange vk_range; - VkImageResolve resolve_region; - VkImageType vk_image_type; - VkImageCopy copy_region; - VkFormat vk_format; - - if (resolve_format) - { - vk_format = wined3d_format_vk(resolve_format)->vk_format; - } - else if (!wined3d_format_is_typeless(src_texture->resource.format)) - { - vk_format = src_format_vk->vk_format; - } - else - { - vk_format = dst_format_vk->vk_format; - } + FIXME("Unhandled location %s.\n", wined3d_debug_location(location)); + return FALSE; +}
- switch (src_texture->resource.type) - { - case WINED3D_RTYPE_TEXTURE_1D: - vk_image_type = VK_IMAGE_TYPE_1D; - break; - case WINED3D_RTYPE_TEXTURE_2D: - vk_image_type = VK_IMAGE_TYPE_2D; - break; - case WINED3D_RTYPE_TEXTURE_3D: - vk_image_type = VK_IMAGE_TYPE_3D; - break; - default: - ERR("Unexpected resource type: %s\n", debug_d3dresourcetype(src_texture->resource.type)); - goto barrier_next; - } +static BOOL wined3d_texture_no3d_load_location(struct wined3d_texture *texture, + unsigned int sub_resource_idx, struct wined3d_context *context, uint32_t location) +{ + TRACE("texture %p, sub_resource_idx %u, context %p, location %s.\n", + texture, sub_resource_idx, context, wined3d_debug_location(location));
- vk_range.baseMipLevel = 0; - vk_range.levelCount = 1; - vk_range.baseArrayLayer = 0; - vk_range.layerCount = 1; - - resolve_region.srcSubresource.aspectMask = vk_src_range.aspectMask; - resolve_region.dstSubresource.aspectMask = vk_dst_range.aspectMask; - resolve_region.extent.width = src_rect->right - src_rect->left; - resolve_region.extent.height = src_rect->bottom - src_rect->top; - resolve_region.extent.depth = 1; - - /* In case of typeless resolve the texture type may not match the resolve type. - * To handle that, allocate intermediate texture(s) to resolve from/to. - * A possible performance improvement would be to resolve using a shader instead. */ - if (src_format_vk->vk_format != vk_format) - { - struct wined3d_image_vk src_image; - - if (!wined3d_context_vk_create_image(context_vk, vk_image_type, usage, vk_format, - resolve_region.extent.width, resolve_region.extent.height, 1, - src_sample_count, 1, 1, 0, NULL, &src_image)) - goto barrier_next; - - wined3d_context_vk_reference_image(context_vk, &src_image); - src_vk_image = src_image.vk_image; - wined3d_context_vk_destroy_image(context_vk, &src_image); - - vk_range.aspectMask = vk_src_range.aspectMask; - - wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, src_vk_image, &vk_range); - - copy_region.srcSubresource.aspectMask = vk_src_range.aspectMask; - copy_region.srcSubresource.mipLevel = vk_src_range.baseMipLevel; - copy_region.srcSubresource.baseArrayLayer = vk_src_range.baseArrayLayer; - copy_region.srcSubresource.layerCount = 1; - copy_region.srcOffset.x = src_rect->left; - copy_region.srcOffset.y = src_rect->top; - copy_region.srcOffset.z = 0; - copy_region.dstSubresource.aspectMask = vk_src_range.aspectMask; - copy_region.dstSubresource.mipLevel = 0; - copy_region.dstSubresource.baseArrayLayer = 0; - copy_region.dstSubresource.layerCount = 1; - copy_region.dstOffset.x = 0; - copy_region.dstOffset.y = 0; - copy_region.dstOffset.z = 0; - copy_region.extent.width = resolve_region.extent.width; - copy_region.extent.height = resolve_region.extent.height; - copy_region.extent.depth = 1; - - VK_CALL(vkCmdCopyImage(vk_command_buffer, src_texture_vk->image.vk_image, - src_layout, src_vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, ©_region)); - - wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - src_vk_image, &vk_range); - resolve_src_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - - resolve_region.srcSubresource.mipLevel = 0; - resolve_region.srcSubresource.baseArrayLayer = 0; - resolve_region.srcSubresource.layerCount = 1; - resolve_region.srcOffset.x = 0; - resolve_region.srcOffset.y = 0; - resolve_region.srcOffset.z = 0; - } - else - { - src_vk_image = src_texture_vk->image.vk_image; - resolve_src_layout = src_layout; - - resolve_region.srcSubresource.mipLevel = vk_src_range.baseMipLevel; - resolve_region.srcSubresource.baseArrayLayer = vk_src_range.baseArrayLayer; - resolve_region.srcSubresource.layerCount = 1; - resolve_region.srcOffset.x = src_rect->left; - resolve_region.srcOffset.y = src_rect->top; - resolve_region.srcOffset.z = 0; - } + if (location == WINED3D_LOCATION_SYSMEM) + return TRUE;
- if (dst_format_vk->vk_format != vk_format) - { - struct wined3d_image_vk dst_image; - - if (!wined3d_context_vk_create_image(context_vk, vk_image_type, usage, vk_format, - resolve_region.extent.width, resolve_region.extent.height, 1, - VK_SAMPLE_COUNT_1_BIT, 1, 1, 0, NULL, &dst_image)) - goto barrier_next; - - wined3d_context_vk_reference_image(context_vk, &dst_image); - dst_vk_image = dst_image.vk_image; - wined3d_context_vk_destroy_image(context_vk, &dst_image); - - vk_range.aspectMask = vk_dst_range.aspectMask; - wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_WRITE_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_vk_image, &vk_range); - resolve_dst_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - - resolve_region.dstSubresource.mipLevel = 0; - resolve_region.dstSubresource.baseArrayLayer = 0; - resolve_region.dstSubresource.layerCount = 1; - resolve_region.dstOffset.x = 0; - resolve_region.dstOffset.y = 0; - resolve_region.dstOffset.z = 0; - } - else - { - dst_vk_image = dst_texture_vk->image.vk_image; - resolve_dst_layout = dst_layout; - - resolve_region.dstSubresource.mipLevel = vk_dst_range.baseMipLevel; - resolve_region.dstSubresource.baseArrayLayer = vk_dst_range.baseArrayLayer; - resolve_region.dstSubresource.layerCount = 1; - resolve_region.dstOffset.x = dst_rect->left; - resolve_region.dstOffset.y = dst_rect->top; - resolve_region.dstOffset.z = 0; - } + ERR("Unhandled location %s.\n", wined3d_debug_location(location));
- VK_CALL(vkCmdResolveImage(vk_command_buffer, src_vk_image, resolve_src_layout, - dst_vk_image, resolve_dst_layout, 1, &resolve_region)); + return FALSE; +}
- if (dst_vk_image != dst_texture_vk->image.vk_image) - { - wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, - resolve_dst_layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - dst_vk_image, &vk_range); - - copy_region.srcSubresource.aspectMask = vk_dst_range.aspectMask; - copy_region.srcSubresource.mipLevel = 0; - copy_region.srcSubresource.baseArrayLayer = 0; - copy_region.srcSubresource.layerCount = 1; - copy_region.srcOffset.x = 0; - copy_region.srcOffset.y = 0; - copy_region.srcOffset.z = 0; - copy_region.dstSubresource.aspectMask = vk_dst_range.aspectMask; - copy_region.dstSubresource.mipLevel = vk_dst_range.baseMipLevel; - copy_region.dstSubresource.baseArrayLayer = vk_dst_range.baseArrayLayer; - copy_region.dstSubresource.layerCount = 1; - copy_region.dstOffset.x = dst_rect->left; - copy_region.dstOffset.y = dst_rect->top; - copy_region.dstOffset.z = 0; - copy_region.extent.width = resolve_region.extent.width; - copy_region.extent.height = resolve_region.extent.height; - copy_region.extent.depth = 1; - - VK_CALL(vkCmdCopyImage(vk_command_buffer, dst_vk_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - dst_texture_vk->image.vk_image, dst_layout, 1, ©_region)); - } - } - else - { - const struct wined3d_format *src_format = src_texture_vk->t.resource.format; - VkImageCopy region; - - region.srcSubresource.aspectMask = vk_src_range.aspectMask; - region.srcSubresource.mipLevel = vk_src_range.baseMipLevel; - region.srcSubresource.baseArrayLayer = vk_src_range.baseArrayLayer; - region.srcSubresource.layerCount = vk_src_range.layerCount; - region.srcOffset.x = src_rect->left; - region.srcOffset.y = src_rect->top; - region.srcOffset.z = 0; - region.dstSubresource.aspectMask = vk_dst_range.aspectMask; - region.dstSubresource.mipLevel = vk_dst_range.baseMipLevel; - region.dstSubresource.baseArrayLayer = vk_dst_range.baseArrayLayer; - region.dstSubresource.layerCount = vk_dst_range.layerCount; - region.dstOffset.x = dst_rect->left; - region.dstOffset.y = dst_rect->top; - region.dstOffset.z = 0; - region.extent.width = src_rect->right - src_rect->left; - region.extent.height = src_rect->bottom - src_rect->top; - region.extent.depth = 1; - - if (src_format->attrs & WINED3D_FORMAT_ATTR_PLANAR) - { - region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT; - region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT; - VK_CALL(vkCmdCopyImage(vk_command_buffer, src_texture_vk->image.vk_image, src_layout, - dst_texture_vk->image.vk_image, dst_layout, 1, ®ion)); - region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT; - region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT; - region.srcOffset.x /= src_format->uv_width; - region.srcOffset.y /= src_format->uv_height; - region.dstOffset.x /= src_format->uv_width; - region.dstOffset.y /= src_format->uv_height; - region.extent.width /= src_format->uv_width; - region.extent.height /= src_format->uv_height; - VK_CALL(vkCmdCopyImage(vk_command_buffer, src_texture_vk->image.vk_image, src_layout, - dst_texture_vk->image.vk_image, dst_layout, 1, ®ion)); - } - else - { - VK_CALL(vkCmdCopyImage(vk_command_buffer, src_texture_vk->image.vk_image, src_layout, - dst_texture_vk->image.vk_image, dst_layout, 1, ®ion)); - } - } +static void wined3d_texture_no3d_unload_location(struct wined3d_texture *texture, + struct wined3d_context *context, unsigned int location) +{ + TRACE("texture %p, context %p, location %s.\n", texture, context, wined3d_debug_location(location)); +}
- wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_ACCESS_TRANSFER_WRITE_BIT, - vk_access_mask_from_bind_flags(dst_texture_vk->t.resource.bind_flags), - dst_layout, dst_texture_vk->layout, dst_texture_vk->image.vk_image, &vk_dst_range); - wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_ACCESS_TRANSFER_READ_BIT, - vk_access_mask_from_bind_flags(src_texture_vk->t.resource.bind_flags), - src_layout, src_texture_vk->layout, src_texture_vk->image.vk_image, &vk_src_range); +static const struct wined3d_texture_ops wined3d_texture_no3d_ops = +{ + wined3d_texture_no3d_prepare_location, + wined3d_texture_no3d_load_location, + wined3d_texture_no3d_unload_location, + wined3d_texture_no3d_upload_data, + wined3d_texture_no3d_download_data, +};
- wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB); - wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB); - if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location)) - ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(dst_location)); - - wined3d_context_vk_reference_texture(context_vk, src_texture_vk); - wined3d_context_vk_reference_texture(context_vk, dst_texture_vk); - - return dst_location | WINED3D_LOCATION_TEXTURE_RGB; - -barrier_next: - wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_ACCESS_TRANSFER_WRITE_BIT, - vk_access_mask_from_bind_flags(dst_texture_vk->t.resource.bind_flags), - dst_layout, dst_texture_vk->layout, dst_texture_vk->image.vk_image, &vk_dst_range); - wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_ACCESS_TRANSFER_READ_BIT, - vk_access_mask_from_bind_flags(src_texture_vk->t.resource.bind_flags), - src_layout, src_texture_vk->layout, src_texture_vk->image.vk_image, &vk_src_range); - -next: - if (!(next = blitter->next)) - { - ERR("No blitter to handle blit op %#x.\n", op); - return dst_location; - } +HRESULT wined3d_texture_no3d_init(struct wined3d_texture *texture_no3d, struct wined3d_device *device, + const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count, + uint32_t flags, void *parent, const struct wined3d_parent_ops *parent_ops) +{ + TRACE("texture_no3d %p, device %p, desc %p, layer_count %u, " + "level_count %u, flags %#x, parent %p, parent_ops %p.\n", + texture_no3d, device, desc, layer_count, + level_count, flags, parent, parent_ops);
- TRACE("Forwarding to blitter %p.\n", next); - return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location, - src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter, resolve_format); + return wined3d_texture_init(texture_no3d, desc, layer_count, level_count, + flags, device, parent, parent_ops, &texture_no3d[1], &wined3d_texture_no3d_ops); }
-static const struct wined3d_blitter_ops vk_blitter_ops = +bool is_full_clear(const struct wined3d_rendertarget_view *rtv, const RECT *draw_rect, const RECT *clear_rect) { - .blitter_destroy = vk_blitter_destroy, - .blitter_clear = vk_blitter_clear, - .blitter_blit = vk_blitter_blit, -}; + unsigned int height = rtv->height; + unsigned int width = rtv->width; + + /* partial draw rect */ + if (draw_rect->left || draw_rect->top || draw_rect->right < width || draw_rect->bottom < height) + return false; + + /* partial clear rect */ + if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0 + || clear_rect->right < width || clear_rect->bottom < height)) + return false; + + return true; +}
-void wined3d_vk_blitter_create(struct wined3d_blitter **next) +bool blitter_use_cpu_clear(struct wined3d_rendertarget_view *view) { - struct wined3d_blitter *blitter; + struct wined3d_resource *resource; + struct wined3d_texture *texture; + DWORD locations;
- if (!(blitter = malloc(sizeof(*blitter)))) - return; + resource = view->resource; + if (resource->type == WINED3D_RTYPE_BUFFER) + return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU);
- TRACE("Created blitter %p.\n", blitter); + texture = texture_from_resource(resource); + locations = texture->sub_resources[view->sub_resource_idx].locations; + if (locations & (resource->map_binding | WINED3D_LOCATION_DISCARDED)) + return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU) + || texture->resource.pin_sysmem;
- blitter->ops = &vk_blitter_ops; - blitter->next = *next; - *next = blitter; + return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU) + && !(texture->flags & WINED3D_TEXTURE_CONVERTED); } diff --git a/dlls/wined3d/texture_gl.c b/dlls/wined3d/texture_gl.c new file mode 100644 index 00000000000..a6262dfaf7e --- /dev/null +++ b/dlls/wined3d/texture_gl.c @@ -0,0 +1,2893 @@ +#include "wined3d_private.h" +#include "wined3d_gl.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d); +WINE_DECLARE_DEBUG_CHANNEL(d3d_perf); +WINE_DECLARE_DEBUG_CHANNEL(winediag); + +static const struct wined3d_texture_ops texture_gl_ops; + +static BOOL wined3d_texture_use_immutable_storage(const struct wined3d_texture *texture, + const struct wined3d_gl_info *gl_info) +{ + /* We don't expect to create texture views for textures with height-scaled formats. + * Besides, ARB_texture_storage doesn't allow specifying exact sizes for all levels. */ + return gl_info->supported[ARB_TEXTURE_STORAGE] + && !(texture->resource.format_attrs & WINED3D_FORMAT_ATTR_HEIGHT_SCALE); +} + +GLenum wined3d_texture_get_gl_buffer(const struct wined3d_texture *texture) +{ + const struct wined3d_swapchain *swapchain = texture->swapchain; + + TRACE("texture %p.\n", texture); + + if (!swapchain) + { + ERR("Texture %p is not part of a swapchain.\n", texture); + return GL_NONE; + } + + if (texture == swapchain->front_buffer) + { + TRACE("Returning GL_FRONT.\n"); + return GL_FRONT; + } + + if (texture == swapchain->back_buffers[0]) + { + TRACE("Returning GL_BACK.\n"); + return GL_BACK; + } + + FIXME("Higher back buffer, returning GL_BACK.\n"); + return GL_BACK; +} + +void texture2d_get_blt_info(const struct wined3d_texture_gl *texture_gl, + unsigned int sub_resource_idx, const RECT *rect, struct wined3d_blt_info *info) +{ + struct wined3d_vec3 *coords = info->texcoords; + struct wined3d_rect_f f; + unsigned int level; + GLenum target; + GLsizei w, h; + + level = sub_resource_idx % texture_gl->t.level_count; + w = wined3d_texture_get_level_width(&texture_gl->t, level); + h = wined3d_texture_get_level_height(&texture_gl->t, level); + target = wined3d_texture_gl_get_sub_resource_target(texture_gl, sub_resource_idx); + + switch (target) + { + default: + FIXME("Unsupported texture target %#x.\n", target); + /* Fall back to GL_TEXTURE_2D */ + case GL_TEXTURE_2D: + info->bind_target = GL_TEXTURE_2D; + coords[0].x = (float)rect->left / w; + coords[0].y = (float)rect->top / h; + coords[0].z = 0.0f; + + coords[1].x = (float)rect->right / w; + coords[1].y = (float)rect->top / h; + coords[1].z = 0.0f; + + coords[2].x = (float)rect->left / w; + coords[2].y = (float)rect->bottom / h; + coords[2].z = 0.0f; + + coords[3].x = (float)rect->right / w; + coords[3].y = (float)rect->bottom / h; + coords[3].z = 0.0f; + break; + + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; + cube_coords_float(rect, w, h, &f); + + coords[0].x = 1.0f; coords[0].y = -f.t; coords[0].z = -f.l; + coords[1].x = 1.0f; coords[1].y = -f.t; coords[1].z = -f.r; + coords[2].x = 1.0f; coords[2].y = -f.b; coords[2].z = -f.l; + coords[3].x = 1.0f; coords[3].y = -f.b; coords[3].z = -f.r; + break; + + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; + cube_coords_float(rect, w, h, &f); + + coords[0].x = -1.0f; coords[0].y = -f.t; coords[0].z = f.l; + coords[1].x = -1.0f; coords[1].y = -f.t; coords[1].z = f.r; + coords[2].x = -1.0f; coords[2].y = -f.b; coords[2].z = f.l; + coords[3].x = -1.0f; coords[3].y = -f.b; coords[3].z = f.r; + break; + + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; + cube_coords_float(rect, w, h, &f); + + coords[0].x = f.l; coords[0].y = 1.0f; coords[0].z = f.t; + coords[1].x = f.r; coords[1].y = 1.0f; coords[1].z = f.t; + coords[2].x = f.l; coords[2].y = 1.0f; coords[2].z = f.b; + coords[3].x = f.r; coords[3].y = 1.0f; coords[3].z = f.b; + break; + + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; + cube_coords_float(rect, w, h, &f); + + coords[0].x = f.l; coords[0].y = -1.0f; coords[0].z = -f.t; + coords[1].x = f.r; coords[1].y = -1.0f; coords[1].z = -f.t; + coords[2].x = f.l; coords[2].y = -1.0f; coords[2].z = -f.b; + coords[3].x = f.r; coords[3].y = -1.0f; coords[3].z = -f.b; + break; + + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; + cube_coords_float(rect, w, h, &f); + + coords[0].x = f.l; coords[0].y = -f.t; coords[0].z = 1.0f; + coords[1].x = f.r; coords[1].y = -f.t; coords[1].z = 1.0f; + coords[2].x = f.l; coords[2].y = -f.b; coords[2].z = 1.0f; + coords[3].x = f.r; coords[3].y = -f.b; coords[3].z = 1.0f; + break; + + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; + cube_coords_float(rect, w, h, &f); + + coords[0].x = -f.l; coords[0].y = -f.t; coords[0].z = -1.0f; + coords[1].x = -f.r; coords[1].y = -f.t; coords[1].z = -1.0f; + coords[2].x = -f.l; coords[2].y = -f.b; coords[2].z = -1.0f; + coords[3].x = -f.r; coords[3].y = -f.b; coords[3].z = -1.0f; + break; + } +} + +static bool fbo_blitter_supported(enum wined3d_blit_op blit_op, const struct wined3d_gl_info *gl_info, + const struct wined3d_resource *src_resource, DWORD src_location, + const struct wined3d_resource *dst_resource, DWORD dst_location) +{ + const struct wined3d_format *src_format = src_resource->format; + const struct wined3d_format *dst_format = dst_resource->format; + bool src_ds, dst_ds; + + if ((src_resource->format_attrs | dst_resource->format_attrs) & WINED3D_FORMAT_ATTR_HEIGHT_SCALE) + return false; + + /* Source and/or destination need to be on the GL side. */ + if (!(src_resource->access & dst_resource->access & WINED3D_RESOURCE_ACCESS_GPU)) + return false; + + if (src_resource->type != WINED3D_RTYPE_TEXTURE_2D) + return false; + + /* We can't copy between depth/stencil and colour attachments. One notable + * way we can end up here is when copying between typeless resources with + * formats like R16_TYPELESS, which can end up using either a + * depth/stencil or a colour format on the OpenGL side, depending on the + * resource's bind flags. */ + src_ds = src_format->depth_size || src_format->stencil_size; + dst_ds = dst_format->depth_size || dst_format->stencil_size; + if (src_ds != dst_ds) + return false; + + switch (blit_op) + { + case WINED3D_BLIT_OP_COLOR_BLIT: + if (!((src_format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_FBO_ATTACHABLE) + || (src_resource->bind_flags & WINED3D_BIND_RENDER_TARGET))) + return false; + if (!((dst_format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_FBO_ATTACHABLE) + || (dst_resource->bind_flags & WINED3D_BIND_RENDER_TARGET))) + return false; + if ((src_format->id != dst_format->id || dst_location == WINED3D_LOCATION_DRAWABLE) + && (!is_identity_fixup(src_format->color_fixup) || !is_identity_fixup(dst_format->color_fixup))) + return false; + break; + + case WINED3D_BLIT_OP_DEPTH_BLIT: + if (!(src_format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_DEPTH_STENCIL)) + return false; + if (!(dst_format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_DEPTH_STENCIL)) + return false; + /* Accept pure swizzle fixups for depth formats. In general we + * ignore the stencil component (if present) at the moment and the + * swizzle is not relevant with just the depth component. */ + if (is_complex_fixup(src_format->color_fixup) || is_complex_fixup(dst_format->color_fixup) + || is_scaling_fixup(src_format->color_fixup) || is_scaling_fixup(dst_format->color_fixup)) + return false; + break; + + default: + return false; + } + + return true; +} + +/* Blit between surface locations. Onscreen on different swapchains is not supported. + * Depth / stencil is not supported. Context activation is done by the caller. */ +static void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_context *context, + enum wined3d_texture_filter_type filter, struct wined3d_texture *src_texture, + unsigned int src_sub_resource_idx, DWORD src_location, const RECT *src_rect, + struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, DWORD dst_location, + const RECT *dst_rect, const struct wined3d_format *resolve_format) +{ + struct wined3d_texture *required_texture, *restore_texture, *dst_save_texture = dst_texture; + unsigned int restore_idx, dst_save_sub_resource_idx = dst_sub_resource_idx; + bool resolve, scaled_resolve, restore_context = false; + struct wined3d_texture *src_staging_texture = NULL; + const struct wined3d_gl_info *gl_info; + struct wined3d_context_gl * context_gl; + GLenum gl_filter; + GLenum buffer; + RECT s, d; + + TRACE("device %p, context %p, filter %s, src_texture %p, src_sub_resource_idx %u, src_location %s, " + "src_rect %s, dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s, resolve format %p.\n", + device, context, debug_d3dtexturefiltertype(filter), src_texture, src_sub_resource_idx, + wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect), dst_texture, + dst_sub_resource_idx, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect), resolve_format); + + resolve = wined3d_texture_gl_is_multisample_location(wined3d_texture_gl(src_texture), src_location); + scaled_resolve = resolve + && (abs(src_rect->bottom - src_rect->top) != abs(dst_rect->bottom - dst_rect->top) + || abs(src_rect->right - src_rect->left) != abs(dst_rect->right - dst_rect->left)); + + if (filter == WINED3D_TEXF_LINEAR) + gl_filter = scaled_resolve ? GL_SCALED_RESOLVE_NICEST_EXT : GL_LINEAR; + else + gl_filter = scaled_resolve ? GL_SCALED_RESOLVE_FASTEST_EXT : GL_NEAREST; + + if (resolve) + { + GLint resolve_internal, src_internal, dst_internal; + enum wined3d_format_id resolve_format_id; + + src_internal = wined3d_gl_get_internal_format(&src_texture->resource, + wined3d_format_gl(src_texture->resource.format), src_location == WINED3D_LOCATION_TEXTURE_SRGB); + dst_internal = wined3d_gl_get_internal_format(&dst_texture->resource, + wined3d_format_gl(dst_texture->resource.format), dst_location == WINED3D_LOCATION_TEXTURE_SRGB); + + if (resolve_format) + { + resolve_internal = wined3d_format_gl(resolve_format)->internal; + resolve_format_id = resolve_format->id; + } + else if (!wined3d_format_is_typeless(src_texture->resource.format)) + { + resolve_internal = src_internal; + resolve_format_id = src_texture->resource.format->id; + } + else + { + resolve_internal = dst_internal; + resolve_format_id = dst_texture->resource.format->id; + } + + /* In case of typeless resolve the texture type may not match the resolve type. + * To handle that, allocate intermediate texture(s) to resolve from/to. + * A possible performance improvement would be to resolve using a shader instead. */ + if (src_internal != resolve_internal) + { + struct wined3d_resource_desc desc; + unsigned src_level; + HRESULT hr; + + src_level = src_sub_resource_idx % src_texture->level_count; + desc.resource_type = WINED3D_RTYPE_TEXTURE_2D; + desc.format = resolve_format_id; + desc.multisample_type = src_texture->resource.multisample_type; + desc.multisample_quality = src_texture->resource.multisample_quality; + desc.usage = WINED3DUSAGE_CS; + desc.bind_flags = 0; + desc.access = WINED3D_RESOURCE_ACCESS_GPU; + desc.width = wined3d_texture_get_level_width(src_texture, src_level); + desc.height = wined3d_texture_get_level_height(src_texture, src_level); + desc.depth = 1; + desc.size = 0; + + hr = wined3d_texture_create(device, &desc, 1, 1, 0, NULL, NULL, &wined3d_null_parent_ops, + &src_staging_texture); + if (FAILED(hr)) + { + ERR("Failed to create staging texture, hr %#lx.\n", hr); + goto done; + } + + if (src_location == WINED3D_LOCATION_DRAWABLE) + FIXME("WINED3D_LOCATION_DRAWABLE not supported for the source of a typeless resolve.\n"); + + device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_RAW_BLIT, context, + src_texture, src_sub_resource_idx, src_location, src_rect, + src_staging_texture, 0, src_location, src_rect, + NULL, WINED3D_TEXF_NONE, NULL); + + src_texture = src_staging_texture; + src_sub_resource_idx = 0; + } + + if (dst_internal != resolve_internal) + { + struct wined3d_resource_desc desc; + unsigned dst_level; + HRESULT hr; + + dst_level = dst_sub_resource_idx % dst_texture->level_count; + desc.resource_type = WINED3D_RTYPE_TEXTURE_2D; + desc.format = resolve_format_id; + desc.multisample_type = dst_texture->resource.multisample_type; + desc.multisample_quality = dst_texture->resource.multisample_quality; + desc.usage = WINED3DUSAGE_CS; + desc.bind_flags = 0; + desc.access = WINED3D_RESOURCE_ACCESS_GPU; + desc.width = wined3d_texture_get_level_width(dst_texture, dst_level); + desc.height = wined3d_texture_get_level_height(dst_texture, dst_level); + desc.depth = 1; + desc.size = 0; + + hr = wined3d_texture_create(device, &desc, 1, 1, 0, NULL, NULL, &wined3d_null_parent_ops, + &dst_texture); + if (FAILED(hr)) + { + ERR("Failed to create staging texture, hr %#lx.\n", hr); + goto done; + } + + wined3d_texture_load_location(dst_texture, 0, context, dst_location); + dst_sub_resource_idx = 0; + } + } + + /* Make sure the locations are up-to-date. Loading the destination + * surface isn't required if the entire surface is overwritten. (And is + * in fact harmful if we're being called by surface_load_location() with + * the purpose of loading the destination surface.) */ + wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, src_location); + if (!wined3d_texture_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, dst_rect)) + wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location); + else + wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location); + + /* Acquire a context for the front-buffer, even though we may be blitting + * to/from a back-buffer. Since context_acquire() doesn't take the + * resource location into account, it may consider the back-buffer to be + * offscreen. */ + if (src_location == WINED3D_LOCATION_DRAWABLE) + required_texture = src_texture->swapchain->front_buffer; + else if (dst_location == WINED3D_LOCATION_DRAWABLE) + required_texture = dst_texture->swapchain->front_buffer; + else + required_texture = NULL; + + restore_texture = context->current_rt.texture; + restore_idx = context->current_rt.sub_resource_idx; + if (restore_texture != required_texture) + { + context = context_acquire(device, required_texture, 0); + restore_context = true; + } + + context_gl = wined3d_context_gl(context); + if (!context_gl->valid) + { + context_release(context); + WARN("Invalid context, skipping blit.\n"); + restore_context = false; + goto done; + } + + gl_info = context_gl->gl_info; + + if (src_location == WINED3D_LOCATION_DRAWABLE) + { + TRACE("Source texture %p is onscreen.\n", src_texture); + buffer = wined3d_texture_get_gl_buffer(src_texture); + s = *src_rect; + wined3d_texture_translate_drawable_coords(src_texture, context_gl->window, &s); + src_rect = &s; + } + else + { + TRACE("Source texture %p is offscreen.\n", src_texture); + buffer = GL_COLOR_ATTACHMENT0; + } + + wined3d_context_gl_apply_fbo_state_explicit(context_gl, GL_READ_FRAMEBUFFER, + &src_texture->resource, src_sub_resource_idx, NULL, 0, src_location); + gl_info->gl_ops.gl.p_glReadBuffer(buffer); + checkGLcall("glReadBuffer()"); + wined3d_context_gl_check_fbo_status(context_gl, GL_READ_FRAMEBUFFER); + + context_gl_apply_texture_draw_state(context_gl, dst_texture, dst_sub_resource_idx, dst_location); + + if (dst_location == WINED3D_LOCATION_DRAWABLE) + { + d = *dst_rect; + wined3d_texture_translate_drawable_coords(dst_texture, context_gl->window, &d); + dst_rect = &d; + } + + gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + context_invalidate_state(context, STATE_BLEND); + + gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST); + context_invalidate_state(context, STATE_RASTERIZER); + + gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, + dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, GL_COLOR_BUFFER_BIT, gl_filter); + checkGLcall("glBlitFramebuffer()"); + + if (dst_location == WINED3D_LOCATION_DRAWABLE && dst_texture->swapchain->front_buffer == dst_texture) + gl_info->gl_ops.gl.p_glFlush(); + + if (dst_texture != dst_save_texture) + { + if (dst_location == WINED3D_LOCATION_DRAWABLE) + FIXME("WINED3D_LOCATION_DRAWABLE not supported for the destination of a typeless resolve.\n"); + + device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_RAW_BLIT, context, + dst_texture, 0, dst_location, dst_rect, + dst_save_texture, dst_save_sub_resource_idx, dst_location, dst_rect, + NULL, WINED3D_TEXF_NONE, NULL); + } + +done: + if (dst_texture != dst_save_texture) + wined3d_texture_decref(dst_texture); + + if (src_staging_texture) + wined3d_texture_decref(src_staging_texture); + + if (restore_context) + context_restore(context, restore_texture, restore_idx); +} + +static void texture2d_depth_blt_fbo(const struct wined3d_device *device, struct wined3d_context *context, + struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, DWORD src_location, + const RECT *src_rect, struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, + DWORD dst_location, const RECT *dst_rect) +{ + struct wined3d_context_gl *context_gl = wined3d_context_gl(context); + const struct wined3d_gl_info *gl_info = context_gl->gl_info; + GLbitfield src_mask, dst_mask; + GLbitfield gl_mask; + + TRACE("device %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_rect %s, " + "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s.\n", device, + src_texture, src_sub_resource_idx, wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect), + dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect)); + + src_mask = 0; + if (src_texture->resource.format->depth_size) + src_mask |= GL_DEPTH_BUFFER_BIT; + if (src_texture->resource.format->stencil_size) + src_mask |= GL_STENCIL_BUFFER_BIT; + + dst_mask = 0; + if (dst_texture->resource.format->depth_size) + dst_mask |= GL_DEPTH_BUFFER_BIT; + if (dst_texture->resource.format->stencil_size) + dst_mask |= GL_STENCIL_BUFFER_BIT; + + if (src_mask != dst_mask) + { + ERR("Incompatible formats %s and %s.\n", + debug_d3dformat(src_texture->resource.format->id), + debug_d3dformat(dst_texture->resource.format->id)); + return; + } + + if (!src_mask) + { + ERR("Not a depth / stencil format: %s.\n", + debug_d3dformat(src_texture->resource.format->id)); + return; + } + gl_mask = src_mask; + + /* Make sure the locations are up-to-date. Loading the destination + * surface isn't required if the entire surface is overwritten. */ + wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, src_location); + if (!wined3d_texture_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, dst_rect)) + wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location); + else + wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location); + + wined3d_context_gl_apply_fbo_state_explicit(context_gl, GL_READ_FRAMEBUFFER, NULL, 0, + &src_texture->resource, src_sub_resource_idx, src_location); + wined3d_context_gl_check_fbo_status(context_gl, GL_READ_FRAMEBUFFER); + + context_gl_apply_texture_draw_state(context_gl, dst_texture, dst_sub_resource_idx, dst_location); + + if (gl_mask & GL_DEPTH_BUFFER_BIT) + { + gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE); + context_invalidate_state(context, STATE_DEPTH_STENCIL); + } + if (gl_mask & GL_STENCIL_BUFFER_BIT) + { + if (gl_info->supported[EXT_STENCIL_TWO_SIDE]) + gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT); + gl_info->gl_ops.gl.p_glStencilMask(~0U); + context_invalidate_state(context, STATE_DEPTH_STENCIL); + } + + gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST); + context_invalidate_state(context, STATE_RASTERIZER); + + gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, + dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST); + checkGLcall("glBlitFramebuffer()"); +} + +/* Context activation is done by the caller. */ +static void wined3d_texture_remove_buffer_object(struct wined3d_texture *texture, + unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl) +{ + struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx]; + struct wined3d_bo_gl *bo_gl = wined3d_bo_gl(sub_resource->bo); + + TRACE("texture %p, sub_resource_idx %u, context_gl %p.\n", texture, sub_resource_idx, context_gl); + + wined3d_context_gl_destroy_bo(context_gl, bo_gl); + wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_BUFFER); + sub_resource->bo = NULL; + free(bo_gl); +} + +/* A GL context is provided by the caller */ +static void gltexture_delete(struct wined3d_device *device, const struct wined3d_gl_info *gl_info, + struct gl_texture *tex) +{ + context_gl_resource_released(device, tex->name, FALSE); + gl_info->gl_ops.gl.p_glDeleteTextures(1, &tex->name); + tex->name = 0; +} + +/* Context activation is done by the caller. */ +/* The caller is responsible for binding the correct texture. */ +static void wined3d_texture_gl_allocate_mutable_storage(struct wined3d_texture_gl *texture_gl, + GLenum gl_internal_format, const struct wined3d_format_gl *format, + const struct wined3d_gl_info *gl_info) +{ + unsigned int level, level_count, layer, layer_count; + GLsizei width, height, depth; + GLenum target; + + level_count = texture_gl->t.level_count; + if (texture_gl->target == GL_TEXTURE_1D_ARRAY || texture_gl->target == GL_TEXTURE_2D_ARRAY) + layer_count = 1; + else + layer_count = texture_gl->t.layer_count; + + GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0)); + checkGLcall("glBindBuffer"); + + for (layer = 0; layer < layer_count; ++layer) + { + target = wined3d_texture_gl_get_sub_resource_target(texture_gl, layer * level_count); + + for (level = 0; level < level_count; ++level) + { + width = wined3d_texture_get_level_width(&texture_gl->t, level); + height = wined3d_texture_get_level_height(&texture_gl->t, level); + if (texture_gl->t.resource.format_attrs & WINED3D_FORMAT_ATTR_HEIGHT_SCALE) + { + height *= format->f.height_scale.numerator; + height /= format->f.height_scale.denominator; + } + + TRACE("texture_gl %p, layer %u, level %u, target %#x, width %u, height %u.\n", + texture_gl, layer, level, target, width, height); + + if (target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY) + { + depth = wined3d_texture_get_level_depth(&texture_gl->t, level); + GL_EXTCALL(glTexImage3D(target, level, gl_internal_format, width, height, + target == GL_TEXTURE_2D_ARRAY ? texture_gl->t.layer_count : depth, 0, + format->format, format->type, NULL)); + checkGLcall("glTexImage3D"); + } + else if (target == GL_TEXTURE_1D) + { + gl_info->gl_ops.gl.p_glTexImage1D(target, level, gl_internal_format, + width, 0, format->format, format->type, NULL); + } + else + { + gl_info->gl_ops.gl.p_glTexImage2D(target, level, gl_internal_format, width, + target == GL_TEXTURE_1D_ARRAY ? texture_gl->t.layer_count : height, 0, + format->format, format->type, NULL); + checkGLcall("glTexImage2D"); + } + } + } +} + +/* Context activation is done by the caller. */ +/* The caller is responsible for binding the correct texture. */ +static void wined3d_texture_gl_allocate_immutable_storage(struct wined3d_texture_gl *texture_gl, + GLenum gl_internal_format, const struct wined3d_gl_info *gl_info) +{ + unsigned int samples = wined3d_resource_get_sample_count(&texture_gl->t.resource); + GLboolean standard_pattern = texture_gl->t.resource.multisample_type != WINED3D_MULTISAMPLE_NON_MASKABLE + && texture_gl->t.resource.multisample_quality == WINED3D_STANDARD_MULTISAMPLE_PATTERN; + GLsizei height = wined3d_texture_get_level_height(&texture_gl->t, 0); + GLsizei width = wined3d_texture_get_level_width(&texture_gl->t, 0); + + switch (texture_gl->target) + { + case GL_TEXTURE_3D: + GL_EXTCALL(glTexStorage3D(texture_gl->target, texture_gl->t.level_count, + gl_internal_format, width, height, wined3d_texture_get_level_depth(&texture_gl->t, 0))); + break; + case GL_TEXTURE_2D_ARRAY: + GL_EXTCALL(glTexStorage3D(texture_gl->target, texture_gl->t.level_count, + gl_internal_format, width, height, texture_gl->t.layer_count)); + break; + case GL_TEXTURE_2D_MULTISAMPLE: + GL_EXTCALL(glTexStorage2DMultisample(texture_gl->target, samples, + gl_internal_format, width, height, standard_pattern)); + break; + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: + GL_EXTCALL(glTexStorage3DMultisample(texture_gl->target, samples, + gl_internal_format, width, height, texture_gl->t.layer_count, standard_pattern)); + break; + case GL_TEXTURE_1D_ARRAY: + GL_EXTCALL(glTexStorage2D(texture_gl->target, texture_gl->t.level_count, + gl_internal_format, width, texture_gl->t.layer_count)); + break; + case GL_TEXTURE_1D: + GL_EXTCALL(glTexStorage1D(texture_gl->target, texture_gl->t.level_count, gl_internal_format, width)); + break; + default: + GL_EXTCALL(glTexStorage2D(texture_gl->target, texture_gl->t.level_count, + gl_internal_format, width, height)); + break; + } + + checkGLcall("allocate immutable storage"); +} + +void wined3d_gl_texture_swizzle_from_color_fixup(GLint swizzle[4], struct color_fixup_desc fixup) +{ + static const GLenum swizzle_source[] = + { + GL_ZERO, /* CHANNEL_SOURCE_ZERO */ + GL_ONE, /* CHANNEL_SOURCE_ONE */ + GL_RED, /* CHANNEL_SOURCE_X */ + GL_GREEN, /* CHANNEL_SOURCE_Y */ + GL_BLUE, /* CHANNEL_SOURCE_Z */ + GL_ALPHA, /* CHANNEL_SOURCE_W */ + }; + + swizzle[0] = swizzle_source[fixup.x_source]; + swizzle[1] = swizzle_source[fixup.y_source]; + swizzle[2] = swizzle_source[fixup.z_source]; + swizzle[3] = swizzle_source[fixup.w_source]; +} + +/* Context activation is done by the caller. */ +void wined3d_texture_gl_bind(struct wined3d_texture_gl *texture_gl, + struct wined3d_context_gl *context_gl, BOOL srgb) +{ + const struct wined3d_format *format = texture_gl->t.resource.format; + const struct wined3d_gl_info *gl_info = context_gl->gl_info; + const struct color_fixup_desc fixup = format->color_fixup; + struct gl_texture *gl_tex; + GLenum target; + + TRACE("texture_gl %p, context_gl %p, srgb %#x.\n", texture_gl, context_gl, srgb); + + if (!needs_separate_srgb_gl_texture(&context_gl->c, &texture_gl->t)) + srgb = FALSE; + + /* sRGB mode cache for preload() calls outside drawprim. */ + if (srgb) + texture_gl->t.flags |= WINED3D_TEXTURE_IS_SRGB; + else + texture_gl->t.flags &= ~WINED3D_TEXTURE_IS_SRGB; + + gl_tex = wined3d_texture_gl_get_gl_texture(texture_gl, srgb); + target = texture_gl->target; + + if (gl_tex->name) + { + wined3d_context_gl_bind_texture(context_gl, target, gl_tex->name); + return; + } + + gl_info->gl_ops.gl.p_glGenTextures(1, &gl_tex->name); + checkGLcall("glGenTextures"); + TRACE("Generated texture %d.\n", gl_tex->name); + + if (!gl_tex->name) + { + ERR("Failed to generate a texture name.\n"); + return; + } + + /* Initialise the state of the texture object to the OpenGL defaults, not + * the wined3d defaults. */ + gl_tex->sampler_desc.address_u = WINED3D_TADDRESS_WRAP; + gl_tex->sampler_desc.address_v = WINED3D_TADDRESS_WRAP; + gl_tex->sampler_desc.address_w = WINED3D_TADDRESS_WRAP; + memset(gl_tex->sampler_desc.border_color, 0, sizeof(gl_tex->sampler_desc.border_color)); + gl_tex->sampler_desc.mag_filter = WINED3D_TEXF_LINEAR; + gl_tex->sampler_desc.min_filter = WINED3D_TEXF_POINT; /* GL_NEAREST_MIPMAP_LINEAR */ + gl_tex->sampler_desc.mip_filter = WINED3D_TEXF_LINEAR; /* GL_NEAREST_MIPMAP_LINEAR */ + gl_tex->sampler_desc.lod_bias = 0.0f; + gl_tex->sampler_desc.min_lod = -1000.0f; + gl_tex->sampler_desc.max_lod = 1000.0f; + gl_tex->sampler_desc.max_anisotropy = 1; + gl_tex->sampler_desc.compare = FALSE; + gl_tex->sampler_desc.comparison_func = WINED3D_CMP_LESSEQUAL; + if (gl_info->supported[EXT_TEXTURE_SRGB_DECODE]) + gl_tex->sampler_desc.srgb_decode = TRUE; + else + gl_tex->sampler_desc.srgb_decode = srgb; + gl_tex->sampler_desc.mip_base_level = 0; + wined3d_texture_set_dirty(&texture_gl->t); + + wined3d_context_gl_bind_texture(context_gl, target, gl_tex->name); + + /* For a new texture we have to set the texture levels after binding the + * texture. */ + TRACE("Setting GL_TEXTURE_MAX_LEVEL to %u.\n", texture_gl->t.level_count - 1); + gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture_gl->t.level_count - 1); + checkGLcall("glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture->level_count)"); + + if (target == GL_TEXTURE_CUBE_MAP_ARB) + { + /* Cubemaps are always set to clamp, regardless of the sampler state. */ + gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + } + + if (texture_gl->t.flags & WINED3D_TEXTURE_COND_NP2 && target != GL_TEXTURE_2D_MULTISAMPLE + && target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY) + { + /* Conditional non power of two textures use a different clamping + * default. If we're using the GL_WINE_normalized_texrect partial + * driver emulation, we're dealing with a GL_TEXTURE_2D texture which + * has the address mode set to repeat - something that prevents us + * from hitting the accelerated codepath. Thus manually set the GL + * state. The same applies to filtering. Even if the texture has only + * one mip level, the default LINEAR_MIPMAP_LINEAR filter causes a SW + * fallback on macos. */ + gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + checkGLcall("glTexParameteri"); + gl_tex->sampler_desc.address_u = WINED3D_TADDRESS_CLAMP; + gl_tex->sampler_desc.address_v = WINED3D_TADDRESS_CLAMP; + gl_tex->sampler_desc.mag_filter = WINED3D_TEXF_POINT; + gl_tex->sampler_desc.min_filter = WINED3D_TEXF_POINT; + gl_tex->sampler_desc.mip_filter = WINED3D_TEXF_NONE; + } + + if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT] && gl_info->supported[ARB_DEPTH_TEXTURE]) + { + gl_info->gl_ops.gl.p_glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY); + checkGLcall("glTexParameteri(GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY)"); + } + + if (!is_identity_fixup(fixup) && can_use_texture_swizzle(context_gl->c.d3d_info, format)) + { + GLint swizzle[4]; + + wined3d_gl_texture_swizzle_from_color_fixup(swizzle, fixup); + gl_info->gl_ops.gl.p_glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle); + checkGLcall("set format swizzle"); + } +} + +/* Context activation is done by the caller. */ +void wined3d_texture_gl_bind_and_dirtify(struct wined3d_texture_gl *texture_gl, + struct wined3d_context_gl *context_gl, BOOL srgb) +{ + /* FIXME: Ideally we'd only do this when touching a binding that's used by + * a shader. */ + context_invalidate_compute_state(&context_gl->c, STATE_COMPUTE_SHADER_RESOURCE_BINDING); + context_invalidate_state(&context_gl->c, STATE_GRAPHICS_SHADER_RESOURCE_BINDING); + + wined3d_texture_gl_bind(texture_gl, context_gl, srgb); +} + +/* Context activation is done by the caller (state handler). */ +/* This function relies on the correct texture being bound and loaded. */ +void wined3d_texture_gl_apply_sampler_desc(struct wined3d_texture_gl *texture_gl, + const struct wined3d_sampler_desc *sampler_desc, const struct wined3d_context_gl *context_gl) +{ + const struct wined3d_gl_info *gl_info = context_gl->gl_info; + GLenum target = texture_gl->target; + struct gl_texture *gl_tex; + DWORD state; + + TRACE("texture_gl %p, sampler_desc %p, context_gl %p.\n", texture_gl, sampler_desc, context_gl); + + gl_tex = wined3d_texture_gl_get_gl_texture(texture_gl, texture_gl->t.flags & WINED3D_TEXTURE_IS_SRGB); + + state = sampler_desc->address_u; + if (state != gl_tex->sampler_desc.address_u) + { + gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S, + gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]); + gl_tex->sampler_desc.address_u = state; + } + + state = sampler_desc->address_v; + if (state != gl_tex->sampler_desc.address_v) + { + gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T, + gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]); + gl_tex->sampler_desc.address_v = state; + } + + state = sampler_desc->address_w; + if (state != gl_tex->sampler_desc.address_w) + { + gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_R, + gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]); + gl_tex->sampler_desc.address_w = state; + } + + if (memcmp(gl_tex->sampler_desc.border_color, sampler_desc->border_color, + sizeof(gl_tex->sampler_desc.border_color))) + { + gl_info->gl_ops.gl.p_glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, &sampler_desc->border_color[0]); + memcpy(gl_tex->sampler_desc.border_color, sampler_desc->border_color, + sizeof(gl_tex->sampler_desc.border_color)); + } + + state = sampler_desc->mag_filter; + if (state != gl_tex->sampler_desc.mag_filter) + { + gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(state)); + gl_tex->sampler_desc.mag_filter = state; + } + + if (sampler_desc->min_filter != gl_tex->sampler_desc.min_filter + || sampler_desc->mip_filter != gl_tex->sampler_desc.mip_filter) + { + gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MIN_FILTER, + wined3d_gl_min_mip_filter(sampler_desc->min_filter, sampler_desc->mip_filter)); + gl_tex->sampler_desc.min_filter = sampler_desc->min_filter; + gl_tex->sampler_desc.mip_filter = sampler_desc->mip_filter; + } + + state = sampler_desc->max_anisotropy; + if (state != gl_tex->sampler_desc.max_anisotropy) + { + if (gl_info->supported[ARB_TEXTURE_FILTER_ANISOTROPIC]) + gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY, state); + else + WARN("Anisotropic filtering not supported.\n"); + gl_tex->sampler_desc.max_anisotropy = state; + } + + if (!sampler_desc->srgb_decode != !gl_tex->sampler_desc.srgb_decode + && (context_gl->c.d3d_info->wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL) + && gl_info->supported[EXT_TEXTURE_SRGB_DECODE]) + { + gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_SRGB_DECODE_EXT, + sampler_desc->srgb_decode ? GL_DECODE_EXT : GL_SKIP_DECODE_EXT); + gl_tex->sampler_desc.srgb_decode = sampler_desc->srgb_decode; + } + + if (!sampler_desc->compare != !gl_tex->sampler_desc.compare) + { + if (sampler_desc->compare) + gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); + else + gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); + gl_tex->sampler_desc.compare = sampler_desc->compare; + } + + checkGLcall("Texture parameter application"); + + if (gl_info->supported[EXT_TEXTURE_LOD_BIAS]) + { + gl_info->gl_ops.gl.p_glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, + GL_TEXTURE_LOD_BIAS_EXT, sampler_desc->lod_bias); + checkGLcall("glTexEnvf(GL_TEXTURE_LOD_BIAS_EXT, ...)"); + } +} + +/* In D3D the depth stencil dimensions have to be greater than or equal to the + * render target dimensions. With FBOs, the dimensions have to be an exact match. */ +/* TODO: We should synchronize the renderbuffer's content with the texture's content. */ +/* Context activation is done by the caller. */ +void wined3d_texture_gl_set_compatible_renderbuffer(struct wined3d_texture_gl *texture_gl, + struct wined3d_context_gl *context_gl, unsigned int level, const struct wined3d_rendertarget_info *rt) +{ + const struct wined3d_gl_info *gl_info = context_gl->gl_info; + struct wined3d_renderbuffer_entry *entry; + unsigned int src_width, src_height; + unsigned int width, height; + GLuint renderbuffer = 0; + + if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]) + return; + + if (rt && rt->resource->format->id != WINED3DFMT_NULL) + { + struct wined3d_texture *rt_texture; + unsigned int rt_level; + + if (rt->resource->type == WINED3D_RTYPE_BUFFER) + { + FIXME("Unsupported resource type %s.\n", debug_d3dresourcetype(rt->resource->type)); + return; + } + rt_texture = wined3d_texture_from_resource(rt->resource); + rt_level = rt->sub_resource_idx % rt_texture->level_count; + + width = wined3d_texture_get_level_width(rt_texture, rt_level); + height = wined3d_texture_get_level_height(rt_texture, rt_level); + } + else + { + width = wined3d_texture_get_level_width(&texture_gl->t, level); + height = wined3d_texture_get_level_height(&texture_gl->t, level); + } + + src_width = wined3d_texture_get_level_width(&texture_gl->t, level); + src_height = wined3d_texture_get_level_height(&texture_gl->t, level); + + /* A depth stencil smaller than the render target is not valid */ + if (width > src_width || height > src_height) + return; + + /* Remove any renderbuffer set if the sizes match */ + if (width == src_width && height == src_height) + { + texture_gl->current_renderbuffer = NULL; + return; + } + + /* Look if we've already got a renderbuffer of the correct dimensions */ + LIST_FOR_EACH_ENTRY(entry, &texture_gl->renderbuffers, struct wined3d_renderbuffer_entry, entry) + { + if (entry->width == width && entry->height == height) + { + renderbuffer = entry->id; + texture_gl->current_renderbuffer = entry; + break; + } + } + + if (!renderbuffer) + { + const struct wined3d_format_gl *format_gl; + + format_gl = wined3d_format_gl(texture_gl->t.resource.format); + gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer); + gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); + gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, format_gl->internal, width, height); + + entry = malloc(sizeof(*entry)); + entry->width = width; + entry->height = height; + entry->id = renderbuffer; + list_add_head(&texture_gl->renderbuffers, &entry->entry); + + texture_gl->current_renderbuffer = entry; + } + + checkGLcall("set compatible renderbuffer"); +} + +/* Context activation is done by the caller. */ +static void wined3d_texture_gl_prepare_buffer_object(struct wined3d_texture_gl *texture_gl, + unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl) +{ + struct wined3d_texture_sub_resource *sub_resource; + struct wined3d_bo_gl *bo; + + sub_resource = &texture_gl->t.sub_resources[sub_resource_idx]; + + if (sub_resource->bo) + return; + + if (!(bo = malloc(sizeof(*bo)))) + return; + + if (!wined3d_device_gl_create_bo(wined3d_device_gl(texture_gl->t.resource.device), + context_gl, sub_resource->size, GL_PIXEL_UNPACK_BUFFER, GL_STREAM_DRAW, true, + GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_CLIENT_STORAGE_BIT, bo)) + { + free(bo); + return; + } + + TRACE("Created buffer object %u for texture %p, sub-resource %u.\n", bo->id, texture_gl, sub_resource_idx); + sub_resource->bo = &bo->b; +} + +/* Context activation is done by the caller. */ +void wined3d_texture_gl_prepare_texture(struct wined3d_texture_gl *texture_gl, + struct wined3d_context_gl *context_gl, BOOL srgb) +{ + DWORD alloc_flag = srgb ? WINED3D_TEXTURE_SRGB_ALLOCATED : WINED3D_TEXTURE_RGB_ALLOCATED; + const struct wined3d_gl_info *gl_info = context_gl->gl_info; + struct wined3d_resource *resource = &texture_gl->t.resource; + const struct wined3d_device *device = resource->device; + const struct wined3d_format *format = resource->format; + const struct wined3d_color_key_conversion *conversion; + const struct wined3d_format_gl *format_gl; + GLenum internal; + + TRACE("texture_gl %p, context_gl %p, srgb %d, format %s.\n", + texture_gl, context_gl, srgb, debug_d3dformat(format->id)); + + if (texture_gl->t.flags & alloc_flag) + return; + + if (resource->format_caps & WINED3D_FORMAT_CAP_DECOMPRESS) + { + TRACE("WINED3D_FORMAT_CAP_DECOMPRESS set.\n"); + texture_gl->t.flags |= WINED3D_TEXTURE_CONVERTED; + format = wined3d_resource_get_decompress_format(resource); + } + else if (format->conv_byte_count) + { + texture_gl->t.flags |= WINED3D_TEXTURE_CONVERTED; + } + else if ((conversion = wined3d_format_get_color_key_conversion(&texture_gl->t, TRUE))) + { + texture_gl->t.flags |= WINED3D_TEXTURE_CONVERTED; + format = wined3d_get_format(device->adapter, conversion->dst_format, resource->bind_flags); + TRACE("Using format %s for color key conversion.\n", debug_d3dformat(format->id)); + } + format_gl = wined3d_format_gl(format); + + wined3d_texture_gl_bind_and_dirtify(texture_gl, context_gl, srgb); + + internal = wined3d_gl_get_internal_format(resource, format_gl, srgb); + if (!internal) + FIXME("No GL internal format for format %s.\n", debug_d3dformat(format->id)); + + TRACE("internal %#x, format %#x, type %#x.\n", internal, format_gl->format, format_gl->type); + + if (wined3d_texture_use_immutable_storage(&texture_gl->t, gl_info)) + wined3d_texture_gl_allocate_immutable_storage(texture_gl, internal, gl_info); + else + wined3d_texture_gl_allocate_mutable_storage(texture_gl, internal, format_gl, gl_info); + texture_gl->t.flags |= alloc_flag; +} + +static void wined3d_texture_gl_prepare_rb(struct wined3d_texture_gl *texture_gl, + const struct wined3d_gl_info *gl_info, BOOL multisample) +{ + const struct wined3d_format_gl *format_gl; + + format_gl = wined3d_format_gl(texture_gl->t.resource.format); + if (multisample) + { + DWORD samples; + + if (texture_gl->rb_multisample) + return; + + samples = wined3d_resource_get_sample_count(&texture_gl->t.resource); + + gl_info->fbo_ops.glGenRenderbuffers(1, &texture_gl->rb_multisample); + gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, texture_gl->rb_multisample); + gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, + format_gl->internal, texture_gl->t.resource.width, texture_gl->t.resource.height); + checkGLcall("glRenderbufferStorageMultisample()"); + TRACE("Created multisample rb %u.\n", texture_gl->rb_multisample); + } + else + { + if (texture_gl->rb_resolved) + return; + + gl_info->fbo_ops.glGenRenderbuffers(1, &texture_gl->rb_resolved); + gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, texture_gl->rb_resolved); + gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, format_gl->internal, + texture_gl->t.resource.width, texture_gl->t.resource.height); + checkGLcall("glRenderbufferStorage()"); + TRACE("Created resolved rb %u.\n", texture_gl->rb_resolved); + } +} + +static void wined3d_texture_gl_upload_bo(const struct wined3d_format *src_format, GLenum target, + unsigned int level, unsigned int src_row_pitch, unsigned int src_slice_pitch, + unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, unsigned int update_w, + unsigned int update_h, unsigned int update_d, const BYTE *addr, BOOL srgb, + struct wined3d_texture *dst_texture, const struct wined3d_gl_info *gl_info) +{ + const struct wined3d_format_gl *format_gl = wined3d_format_gl(src_format); + + if (src_format->attrs & WINED3D_FORMAT_ATTR_COMPRESSED) + { + GLenum internal = wined3d_gl_get_internal_format(&dst_texture->resource, format_gl, srgb); + unsigned int dst_row_pitch, dst_slice_pitch; + + wined3d_format_calculate_pitch(src_format, 1, update_w, update_h, &dst_row_pitch, &dst_slice_pitch); + + TRACE("Uploading compressed data, target %#x, level %u, x %u, y %u, z %u, " + "w %u, h %u, d %u, format %#x, image_size %#x, addr %p.\n", + target, level, dst_x, dst_y, dst_z, update_w, update_h, + update_d, internal, dst_slice_pitch, addr); + + if (target == GL_TEXTURE_1D) + { + GL_EXTCALL(glCompressedTexSubImage1D(target, level, dst_x, + update_w, internal, dst_row_pitch, addr)); + } + else + { + unsigned int row, y, slice, slice_count = 1, row_count = 1; + + /* glCompressedTexSubImage2D() ignores pixel store state, so we + * can't use the unpack row length like for glTexSubImage2D. */ + if (dst_row_pitch != src_row_pitch) + { + row_count = (update_h + src_format->block_height - 1) / src_format->block_height; + update_h = src_format->block_height; + wined3d_format_calculate_pitch(src_format, 1, update_w, update_h, + &dst_row_pitch, &dst_slice_pitch); + } + + if (dst_slice_pitch != src_slice_pitch) + { + slice_count = update_d; + update_d = 1; + } + + for (slice = 0; slice < slice_count; ++slice) + { + for (row = 0, y = dst_y; row < row_count; ++row) + { + const BYTE *upload_addr = &addr[slice * src_slice_pitch + row * src_row_pitch]; + + if (target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_3D) + { + GL_EXTCALL(glCompressedTexSubImage3D(target, level, dst_x, y, dst_z + slice, update_w, + update_h, update_d, internal, update_d * dst_slice_pitch, upload_addr)); + } + else + { + GL_EXTCALL(glCompressedTexSubImage2D(target, level, dst_x, y, update_w, + update_h, internal, dst_slice_pitch, upload_addr)); + } + + y += src_format->block_height; + } + } + } + checkGLcall("Upload compressed texture data"); + } + else + { + unsigned int y, y_count, z, z_count; + bool unpacking_rows = false; + + TRACE("Uploading data, target %#x, level %u, x %u, y %u, z %u, " + "w %u, h %u, d %u, format %#x, type %#x, addr %p.\n", + target, level, dst_x, dst_y, dst_z, update_w, update_h, + update_d, format_gl->format, format_gl->type, addr); + + if (src_row_pitch && !(src_row_pitch % src_format->byte_count)) + { + gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_row_pitch / src_format->byte_count); + y_count = 1; + unpacking_rows = true; + } + else + { + y_count = update_h; + update_h = 1; + } + + if (src_slice_pitch && unpacking_rows && !(src_slice_pitch % src_row_pitch)) + { + gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, src_slice_pitch / src_row_pitch); + z_count = 1; + } + else if (src_slice_pitch && !unpacking_rows && !(src_slice_pitch % (update_w * src_format->byte_count))) + { + gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, + src_slice_pitch / (update_w * src_format->byte_count)); + z_count = 1; + } + else + { + z_count = update_d; + update_d = 1; + } + + for (z = 0; z < z_count; ++z) + { + for (y = 0; y < y_count; ++y) + { + const BYTE *upload_addr = &addr[z * src_slice_pitch + y * src_row_pitch]; + if (target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_3D) + { + GL_EXTCALL(glTexSubImage3D(target, level, dst_x, dst_y + y, dst_z + z, update_w, + update_h, update_d, format_gl->format, format_gl->type, upload_addr)); + } + else if (target == GL_TEXTURE_1D) + { + gl_info->gl_ops.gl.p_glTexSubImage1D(target, level, dst_x, + update_w, format_gl->format, format_gl->type, upload_addr); + } + else + { + gl_info->gl_ops.gl.p_glTexSubImage2D(target, level, dst_x, dst_y + y, + update_w, update_h, format_gl->format, format_gl->type, upload_addr); + } + } + } + gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); + checkGLcall("Upload texture data"); + } +} + +static void wined3d_texture_gl_upload_data(struct wined3d_context *context, + const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *src_format, + const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch, + struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, unsigned int dst_location, + unsigned int dst_x, unsigned int dst_y, unsigned int dst_z) +{ + struct wined3d_context_gl *context_gl = wined3d_context_gl(context); + enum wined3d_format_id alpha_fixup_format_id = WINED3DFMT_UNKNOWN; + const struct wined3d_gl_info *gl_info = context_gl->gl_info; + unsigned int update_w = src_box->right - src_box->left; + unsigned int update_h = src_box->bottom - src_box->top; + unsigned int update_d = src_box->back - src_box->front; + struct wined3d_bo_address bo; + unsigned int level; + BOOL srgb = FALSE; + BOOL decompress; + GLenum target; + + TRACE("context %p, src_bo_addr %s, src_format %s, src_box %s, src_row_pitch %u, src_slice_pitch %u, " + "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_x %u, dst_y %u, dst_z %u.\n", + context, debug_const_bo_address(src_bo_addr), debug_d3dformat(src_format->id), debug_box(src_box), + src_row_pitch, src_slice_pitch, dst_texture, dst_sub_resource_idx, + wined3d_debug_location(dst_location), dst_x, dst_y, dst_z); + + if (dst_location == WINED3D_LOCATION_TEXTURE_SRGB) + { + srgb = TRUE; + } + else if (dst_location != WINED3D_LOCATION_TEXTURE_RGB) + { + FIXME("Unhandled location %s.\n", wined3d_debug_location(dst_location)); + return; + } + + wined3d_texture_gl_bind_and_dirtify(wined3d_texture_gl(dst_texture), wined3d_context_gl(context), srgb); + + if (dst_texture->sub_resources[dst_sub_resource_idx].map_count) + { + WARN("Uploading a texture that is currently mapped, pinning sysmem.\n"); + dst_texture->resource.pin_sysmem = 1; + } + + if (src_format->attrs & WINED3D_FORMAT_ATTR_HEIGHT_SCALE) + { + update_h *= src_format->height_scale.numerator; + update_h /= src_format->height_scale.denominator; + } + + target = wined3d_texture_gl_get_sub_resource_target(wined3d_texture_gl(dst_texture), dst_sub_resource_idx); + level = dst_sub_resource_idx % dst_texture->level_count; + + switch (target) + { + case GL_TEXTURE_1D_ARRAY: + dst_y = dst_sub_resource_idx / dst_texture->level_count; + update_h = 1; + break; + case GL_TEXTURE_2D_ARRAY: + dst_z = dst_sub_resource_idx / dst_texture->level_count; + update_d = 1; + break; + case GL_TEXTURE_2D_MULTISAMPLE: + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: + FIXME("Not supported for multisample textures.\n"); + return; + } + + bo.buffer_object = src_bo_addr->buffer_object; + bo.addr = (BYTE *)src_bo_addr->addr + src_box->front * src_slice_pitch; + if (dst_texture->resource.format_attrs & WINED3D_FORMAT_ATTR_BLOCKS) + { + bo.addr += (src_box->top / src_format->block_height) * src_row_pitch; + bo.addr += (src_box->left / src_format->block_width) * src_format->block_byte_count; + } + else + { + bo.addr += src_box->top * src_row_pitch; + bo.addr += src_box->left * src_format->byte_count; + } + + decompress = (dst_texture->resource.format_caps & WINED3D_FORMAT_CAP_DECOMPRESS) + || (src_format->decompress && src_format->id != dst_texture->resource.format->id); + + if (src_format->upload || decompress + || (alpha_fixup_format_id = wined3d_get_alpha_fixup_format(src_format->id, + dst_texture->resource.format)) != WINED3DFMT_UNKNOWN) + { + const struct wined3d_format *compressed_format = src_format; + unsigned int dst_row_pitch, dst_slice_pitch; + struct wined3d_format_gl f; + void *converted_mem; + unsigned int z; + BYTE *src_mem; + + if (decompress) + { + src_format = wined3d_resource_get_decompress_format(&dst_texture->resource); + } + else if (alpha_fixup_format_id != WINED3DFMT_UNKNOWN) + { + src_format = wined3d_get_format(context->device->adapter, alpha_fixup_format_id, 0); + assert(!!src_format); + } + else + { + if (dst_texture->resource.format_attrs & WINED3D_FORMAT_ATTR_BLOCKS) + ERR("Converting a block-based format.\n"); + + f = *wined3d_format_gl(src_format); + f.f.byte_count = src_format->conv_byte_count; + src_format = &f.f; + } + + wined3d_format_calculate_pitch(src_format, 1, update_w, update_h, &dst_row_pitch, &dst_slice_pitch); + + if (!(converted_mem = malloc(dst_slice_pitch))) + { + ERR("Failed to allocate upload buffer.\n"); + return; + } + + src_mem = wined3d_context_gl_map_bo_address(context_gl, &bo, src_slice_pitch * update_d, WINED3D_MAP_READ); + + GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0)); + checkGLcall("glBindBuffer"); + + for (z = 0; z < update_d; ++z, src_mem += src_slice_pitch) + { + if (decompress) + compressed_format->decompress(src_mem, converted_mem, src_row_pitch, src_slice_pitch, + dst_row_pitch, dst_slice_pitch, update_w, update_h, 1); + else if (alpha_fixup_format_id != WINED3DFMT_UNKNOWN) + wined3d_fixup_alpha(src_format, src_mem, src_row_pitch, converted_mem, dst_row_pitch, + update_w, update_h); + else + src_format->upload(src_mem, converted_mem, src_row_pitch, src_slice_pitch, + dst_row_pitch, dst_slice_pitch, update_w, update_h, 1); + + wined3d_texture_gl_upload_bo(src_format, target, level, dst_row_pitch, dst_slice_pitch, dst_x, + dst_y, dst_z + z, update_w, update_h, 1, converted_mem, srgb, dst_texture, gl_info); + } + + wined3d_context_gl_unmap_bo_address(context_gl, &bo, 0, NULL); + free(converted_mem); + } + else + { + const uint8_t *offset = bo.addr; + + if (bo.buffer_object) + { + GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, wined3d_bo_gl(bo.buffer_object)->id)); + checkGLcall("glBindBuffer"); + offset += bo.buffer_object->buffer_offset; + } + else + { + GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0)); + checkGLcall("glBindBuffer"); + } + + wined3d_texture_gl_upload_bo(src_format, target, level, src_row_pitch, src_slice_pitch, dst_x, + dst_y, dst_z, update_w, update_h, update_d, offset, srgb, dst_texture, gl_info); + + if (bo.buffer_object) + { + GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0)); + wined3d_context_gl_reference_bo(context_gl, wined3d_bo_gl(bo.buffer_object)); + checkGLcall("glBindBuffer"); + } + } + + if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE) + { + struct wined3d_device *device = dst_texture->resource.device; + unsigned int i; + + for (i = 0; i < device->context_count; ++i) + { + wined3d_context_gl_texture_update(wined3d_context_gl(device->contexts[i]), wined3d_texture_gl(dst_texture)); + } + } +} + +static void wined3d_texture_gl_download_data_slow_path(struct wined3d_texture_gl *texture_gl, + unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl, const struct wined3d_bo_address *data) +{ + struct wined3d_bo_gl *bo = wined3d_bo_gl(data->buffer_object); + const struct wined3d_gl_info *gl_info = context_gl->gl_info; + struct wined3d_texture_sub_resource *sub_resource; + unsigned int dst_row_pitch, dst_slice_pitch; + unsigned int src_row_pitch, src_slice_pitch; + const struct wined3d_format_gl *format_gl; + BYTE *temporary_mem = NULL; + unsigned int level; + GLenum target; + void *mem; + + format_gl = wined3d_format_gl(texture_gl->t.resource.format); + + /* Only support read back of converted P8 textures. */ + if (texture_gl->t.flags & WINED3D_TEXTURE_CONVERTED && format_gl->f.id != WINED3DFMT_P8_UINT + && !format_gl->f.download) + { + ERR("Trying to read back converted texture %p, %u with format %s.\n", + texture_gl, sub_resource_idx, debug_d3dformat(format_gl->f.id)); + return; + } + + sub_resource = &texture_gl->t.sub_resources[sub_resource_idx]; + target = wined3d_texture_gl_get_sub_resource_target(texture_gl, sub_resource_idx); + level = sub_resource_idx % texture_gl->t.level_count; + + if (target == GL_TEXTURE_1D_ARRAY || target == GL_TEXTURE_2D_ARRAY) + { + if (format_gl->f.download) + { + FIXME("Reading back converted array texture %p is not supported.\n", texture_gl); + return; + } + + WARN_(d3d_perf)("Downloading all miplevel layers to get the data for a single sub-resource.\n"); + + if (!(temporary_mem = calloc(texture_gl->t.layer_count, sub_resource->size))) + { + ERR("Out of memory.\n"); + return; + } + } + + if (format_gl->f.download) + { + struct wined3d_format f; + + if (bo) + ERR("Converted texture %p uses PBO unexpectedly.\n", texture_gl); + + WARN_(d3d_perf)("Downloading converted texture %p, %u with format %s.\n", + texture_gl, sub_resource_idx, debug_d3dformat(format_gl->f.id)); + + f = format_gl->f; + f.byte_count = format_gl->f.conv_byte_count; + wined3d_texture_get_pitch(&texture_gl->t, level, &dst_row_pitch, &dst_slice_pitch); + wined3d_format_calculate_pitch(&f, texture_gl->t.resource.device->surface_alignment, + wined3d_texture_get_level_width(&texture_gl->t, level), + wined3d_texture_get_level_height(&texture_gl->t, level), + &src_row_pitch, &src_slice_pitch); + + if (!(temporary_mem = malloc(src_slice_pitch))) + { + ERR("Failed to allocate memory.\n"); + return; + } + } + + if (temporary_mem) + { + GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)); + checkGLcall("glBindBuffer"); + mem = temporary_mem; + } + else if (bo) + { + GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, bo->id)); + checkGLcall("glBindBuffer"); + mem = (uint8_t *)data->addr + bo->b.buffer_offset; + } + else + { + GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)); + checkGLcall("glBindBuffer"); + mem = data->addr; + } + + if (texture_gl->t.resource.format_attrs & WINED3D_FORMAT_ATTR_COMPRESSED) + { + TRACE("Downloading compressed texture %p, %u, level %u, format %#x, type %#x, data %p.\n", + texture_gl, sub_resource_idx, level, format_gl->format, format_gl->type, mem); + + GL_EXTCALL(glGetCompressedTexImage(target, level, mem)); + checkGLcall("glGetCompressedTexImage"); + } + else + { + TRACE("Downloading texture %p, %u, level %u, format %#x, type %#x, data %p.\n", + texture_gl, sub_resource_idx, level, format_gl->format, format_gl->type, mem); + + gl_info->gl_ops.gl.p_glGetTexImage(target, level, format_gl->format, format_gl->type, mem); + checkGLcall("glGetTexImage"); + } + + if (format_gl->f.download) + { + format_gl->f.download(mem, data->addr, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch, + wined3d_texture_get_level_width(&texture_gl->t, level), + wined3d_texture_get_level_height(&texture_gl->t, level), 1); + } + else if (temporary_mem) + { + unsigned int layer = sub_resource_idx / texture_gl->t.level_count; + void *src_data = temporary_mem + layer * sub_resource->size; + if (bo) + { + GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, bo->id)); + checkGLcall("glBindBuffer"); + GL_EXTCALL(glBufferSubData(GL_PIXEL_PACK_BUFFER, + (GLintptr)data->addr + bo->b.buffer_offset, sub_resource->size, src_data)); + checkGLcall("glBufferSubData"); + } + else + { + memcpy(data->addr, src_data, sub_resource->size); + } + } + + if (bo) + { + GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)); + wined3d_context_gl_reference_bo(context_gl, bo); + checkGLcall("glBindBuffer"); + } + + free(temporary_mem); +} + +static void wined3d_texture_gl_download_data(struct wined3d_context *context, + struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, unsigned int src_location, + const struct wined3d_box *src_box, const struct wined3d_bo_address *dst_bo_addr, + const struct wined3d_format *dst_format, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, + unsigned int dst_row_pitch, unsigned int dst_slice_pitch) +{ + struct wined3d_texture_gl *src_texture_gl = wined3d_texture_gl(src_texture); + struct wined3d_context_gl *context_gl = wined3d_context_gl(context); + const struct wined3d_gl_info *gl_info = context_gl->gl_info; + unsigned int src_level, src_width, src_height, src_depth; + unsigned int src_row_pitch, src_slice_pitch; + const struct wined3d_format_gl *format_gl; + uint8_t *offset = dst_bo_addr->addr; + struct wined3d_bo *dst_bo; + BOOL srgb = FALSE; + GLenum target; + + TRACE("context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_box %s, dst_bo_addr %s, " + "dst_format %s, dst_x %u, dst_y %u, dst_z %u, dst_row_pitch %u, dst_slice_pitch %u.\n", + context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location), + debug_box(src_box), debug_bo_address(dst_bo_addr), debug_d3dformat(dst_format->id), + dst_x, dst_y, dst_z, dst_row_pitch, dst_slice_pitch); + + if (src_location == WINED3D_LOCATION_TEXTURE_SRGB) + { + srgb = TRUE; + } + else if (src_location != WINED3D_LOCATION_TEXTURE_RGB) + { + FIXME("Unhandled location %s.\n", wined3d_debug_location(src_location)); + return; + } + + src_level = src_sub_resource_idx % src_texture->level_count; + src_width = wined3d_texture_get_level_width(src_texture, src_level); + src_height = wined3d_texture_get_level_height(src_texture, src_level); + src_depth = wined3d_texture_get_level_depth(src_texture, src_level); + if (src_box->left || src_box->top || src_box->right != src_width || src_box->bottom != src_height + || src_box->front || src_box->back != src_depth) + { + FIXME("Unhandled source box %s.\n", debug_box(src_box)); + return; + } + + if (dst_x || dst_y || dst_z) + { + FIXME("Unhandled destination (%u, %u, %u).\n", dst_x, dst_y, dst_z); + return; + } + + if (dst_format->id != src_texture->resource.format->id) + { + FIXME("Unhandled format conversion (%s -> %s).\n", + debug_d3dformat(src_texture->resource.format->id), + debug_d3dformat(dst_format->id)); + return; + } + + wined3d_texture_get_pitch(src_texture, src_level, &src_row_pitch, &src_slice_pitch); + if (src_row_pitch != dst_row_pitch || src_slice_pitch != dst_slice_pitch) + { + FIXME("Unhandled destination pitches %u/%u (source pitches %u/%u).\n", + dst_row_pitch, dst_slice_pitch, src_row_pitch, src_slice_pitch); + return; + } + + wined3d_texture_gl_bind_and_dirtify(src_texture_gl, context_gl, srgb); + + format_gl = wined3d_format_gl(src_texture->resource.format); + target = wined3d_texture_gl_get_sub_resource_target(src_texture_gl, src_sub_resource_idx); + + if ((src_texture->resource.type == WINED3D_RTYPE_TEXTURE_2D + && (target == GL_TEXTURE_2D_ARRAY || format_gl->f.conv_byte_count + || (src_texture->flags & WINED3D_TEXTURE_CONVERTED))) + || target == GL_TEXTURE_1D_ARRAY) + { + wined3d_texture_gl_download_data_slow_path(src_texture_gl, src_sub_resource_idx, context_gl, dst_bo_addr); + return; + } + + if (format_gl->f.conv_byte_count) + { + FIXME("Attempting to download a converted texture, type %s format %s.\n", + debug_d3dresourcetype(src_texture->resource.type), + debug_d3dformat(format_gl->f.id)); + return; + } + + if ((dst_bo = dst_bo_addr->buffer_object)) + { + GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, wined3d_bo_gl(dst_bo)->id)); + checkGLcall("glBindBuffer"); + offset += dst_bo->buffer_offset; + } + else + { + GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)); + checkGLcall("glBindBuffer"); + } + + if (src_texture->resource.format_attrs & WINED3D_FORMAT_ATTR_COMPRESSED) + { + TRACE("Downloading compressed texture %p, %u, level %u, format %#x, type %#x, data %p.\n", + src_texture, src_sub_resource_idx, src_level, format_gl->format, format_gl->type, offset); + + GL_EXTCALL(glGetCompressedTexImage(target, src_level, offset)); + checkGLcall("glGetCompressedTexImage"); + } + else + { + TRACE("Downloading texture %p, %u, level %u, format %#x, type %#x, data %p.\n", + src_texture, src_sub_resource_idx, src_level, format_gl->format, format_gl->type, offset); + + gl_info->gl_ops.gl.p_glGetTexImage(target, src_level, format_gl->format, format_gl->type, offset); + checkGLcall("glGetTexImage"); + } + + if (dst_bo) + { + GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)); + wined3d_context_gl_reference_bo(context_gl, wined3d_bo_gl(dst_bo)); + checkGLcall("glBindBuffer"); + } +} + +/* Context activation is done by the caller. */ +static BOOL wined3d_texture_gl_load_sysmem(struct wined3d_texture_gl *texture_gl, + unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl, DWORD dst_location) +{ + struct wined3d_texture_sub_resource *sub_resource; + + sub_resource = &texture_gl->t.sub_resources[sub_resource_idx]; + + /* We cannot download data from multisample textures directly. */ + if (wined3d_texture_gl_is_multisample_location(texture_gl, WINED3D_LOCATION_TEXTURE_RGB) + || sub_resource->locations & WINED3D_LOCATION_RB_MULTISAMPLE) + wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, &context_gl->c, WINED3D_LOCATION_RB_RESOLVED); + + if (sub_resource->locations & WINED3D_LOCATION_RB_RESOLVED) + { + texture2d_read_from_framebuffer(&texture_gl->t, sub_resource_idx, &context_gl->c, + WINED3D_LOCATION_RB_RESOLVED, dst_location); + return TRUE; + } + + if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB)) + { + unsigned int row_pitch, slice_pitch, level; + struct wined3d_bo_address data; + struct wined3d_box src_box; + unsigned int src_location; + + level = sub_resource_idx % texture_gl->t.level_count; + wined3d_texture_get_bo_address(&texture_gl->t, sub_resource_idx, &data, dst_location); + src_location = sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB + ? WINED3D_LOCATION_TEXTURE_RGB : WINED3D_LOCATION_TEXTURE_SRGB; + wined3d_texture_get_level_box(&texture_gl->t, level, &src_box); + wined3d_texture_get_pitch(&texture_gl->t, level, &row_pitch, &slice_pitch); + wined3d_texture_gl_download_data(&context_gl->c, &texture_gl->t, sub_resource_idx, src_location, + &src_box, &data, texture_gl->t.resource.format, 0, 0, 0, row_pitch, slice_pitch); + + ++texture_gl->t.download_count; + return TRUE; + } + + if (sub_resource->locations & WINED3D_LOCATION_DRAWABLE) + { + texture2d_read_from_framebuffer(&texture_gl->t, sub_resource_idx, &context_gl->c, + texture_gl->t.resource.draw_binding, dst_location); + return TRUE; + } + + FIXME("Can't load texture %p, %u with location flags %s into sysmem.\n", + texture_gl, sub_resource_idx, wined3d_debug_location(sub_resource->locations)); + + return FALSE; +} + +static BOOL wined3d_texture_gl_load_texture(struct wined3d_texture_gl *texture_gl, + unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl, BOOL srgb) +{ + unsigned int width, height, level, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch; + struct wined3d_device *device = texture_gl->t.resource.device; + const struct wined3d_gl_info *gl_info = context_gl->gl_info; + const struct wined3d_color_key_conversion *conversion; + struct wined3d_texture_sub_resource *sub_resource; + const struct wined3d_format *format; + struct wined3d_bo_address data; + BYTE *src_mem, *dst_mem = NULL; + struct wined3d_box src_box; + DWORD dst_location; + BOOL depth; + + depth = texture_gl->t.resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL; + sub_resource = &texture_gl->t.sub_resources[sub_resource_idx]; + level = sub_resource_idx % texture_gl->t.level_count; + wined3d_texture_get_level_box(&texture_gl->t, level, &src_box); + + if (!depth && sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB) + && (texture_gl->t.resource.format_caps & WINED3D_FORMAT_CAP_FBO_ATTACHABLE_SRGB) + && fbo_blitter_supported(WINED3D_BLIT_OP_COLOR_BLIT, gl_info, + &texture_gl->t.resource, WINED3D_LOCATION_TEXTURE_RGB, + &texture_gl->t.resource, WINED3D_LOCATION_TEXTURE_SRGB)) + { + RECT src_rect; + + SetRect(&src_rect, src_box.left, src_box.top, src_box.right, src_box.bottom); + if (srgb) + texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT, + &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect, + &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect, NULL); + else + texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT, + &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect, + &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect, NULL); + + return TRUE; + } + + if (!depth && sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED) + && (!srgb || (texture_gl->t.resource.format_caps & WINED3D_FORMAT_CAP_FBO_ATTACHABLE_SRGB))) + { + DWORD src_location = sub_resource->locations & WINED3D_LOCATION_RB_RESOLVED ? + WINED3D_LOCATION_RB_RESOLVED : WINED3D_LOCATION_RB_MULTISAMPLE; + RECT src_rect; + + SetRect(&src_rect, src_box.left, src_box.top, src_box.right, src_box.bottom); + dst_location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB; + if (fbo_blitter_supported(WINED3D_BLIT_OP_COLOR_BLIT, gl_info, + &texture_gl->t.resource, src_location, &texture_gl->t.resource, dst_location)) + texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT, &texture_gl->t, sub_resource_idx, + src_location, &src_rect, &texture_gl->t, sub_resource_idx, dst_location, &src_rect, NULL); + + return TRUE; + } + + /* Upload from system memory */ + + if (srgb) + { + dst_location = WINED3D_LOCATION_TEXTURE_SRGB; + if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | texture_gl->t.resource.map_binding)) + == WINED3D_LOCATION_TEXTURE_RGB) + { + FIXME_(d3d_perf)("Downloading RGB texture %p, %u to reload it as sRGB.\n", texture_gl, sub_resource_idx); + wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, + &context_gl->c, texture_gl->t.resource.map_binding); + } + } + else + { + dst_location = WINED3D_LOCATION_TEXTURE_RGB; + if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | texture_gl->t.resource.map_binding)) + == WINED3D_LOCATION_TEXTURE_SRGB) + { + FIXME_(d3d_perf)("Downloading sRGB texture %p, %u to reload it as RGB.\n", texture_gl, sub_resource_idx); + wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, + &context_gl->c, texture_gl->t.resource.map_binding); + } + } + + if (!(sub_resource->locations & wined3d_texture_sysmem_locations)) + { + WARN("Trying to load a texture from sysmem, but no simple location is valid.\n"); + /* Lets hope we get it from somewhere... */ + wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, &context_gl->c, WINED3D_LOCATION_SYSMEM); + } + + wined3d_texture_get_pitch(&texture_gl->t, level, &src_row_pitch, &src_slice_pitch); + + format = texture_gl->t.resource.format; + if ((conversion = wined3d_format_get_color_key_conversion(&texture_gl->t, TRUE))) + format = wined3d_get_format(device->adapter, conversion->dst_format, texture_gl->t.resource.bind_flags); + + /* Don't use PBOs for converted surfaces. During PBO conversion we look at + * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is + * getting called. */ + if (conversion && sub_resource->bo) + { + TRACE("Removing the pbo attached to texture %p, %u.\n", texture_gl, sub_resource_idx); + + wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, &context_gl->c, WINED3D_LOCATION_SYSMEM); + wined3d_texture_set_map_binding(&texture_gl->t, WINED3D_LOCATION_SYSMEM); + } + + wined3d_texture_get_memory(&texture_gl->t, sub_resource_idx, &context_gl->c, &data); + if (conversion) + { + width = src_box.right - src_box.left; + height = src_box.bottom - src_box.top; + wined3d_format_calculate_pitch(format, device->surface_alignment, + width, height, &dst_row_pitch, &dst_slice_pitch); + + src_mem = wined3d_context_gl_map_bo_address(context_gl, &data, src_slice_pitch, WINED3D_MAP_READ); + if (!(dst_mem = malloc(dst_slice_pitch))) + { + ERR("Out of memory (%u).\n", dst_slice_pitch); + return FALSE; + } + conversion->convert(src_mem, src_row_pitch, dst_mem, dst_row_pitch, + width, height, &texture_gl->t.async.gl_color_key); + src_row_pitch = dst_row_pitch; + src_slice_pitch = dst_slice_pitch; + wined3d_context_gl_unmap_bo_address(context_gl, &data, 0, NULL); + + data.buffer_object = 0; + data.addr = dst_mem; + } + + wined3d_texture_gl_upload_data(&context_gl->c, wined3d_const_bo_address(&data), format, &src_box, + src_row_pitch, src_slice_pitch, &texture_gl->t, sub_resource_idx, dst_location, 0, 0, 0); + + free(dst_mem); + + return TRUE; +} + + +static BOOL wined3d_texture_gl_prepare_location(struct wined3d_texture *texture, + unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location) +{ + struct wined3d_texture_gl *texture_gl = wined3d_texture_gl(texture); + struct wined3d_context_gl *context_gl = wined3d_context_gl(context); + + switch (location) + { + case WINED3D_LOCATION_SYSMEM: + return texture->sub_resources[sub_resource_idx].user_memory ? TRUE + : wined3d_resource_prepare_sysmem(&texture->resource); + + case WINED3D_LOCATION_BUFFER: + wined3d_texture_gl_prepare_buffer_object(texture_gl, sub_resource_idx, context_gl); + return TRUE; + + case WINED3D_LOCATION_TEXTURE_RGB: + wined3d_texture_gl_prepare_texture(texture_gl, context_gl, FALSE); + return TRUE; + + case WINED3D_LOCATION_TEXTURE_SRGB: + wined3d_texture_gl_prepare_texture(texture_gl, context_gl, TRUE); + return TRUE; + + case WINED3D_LOCATION_DRAWABLE: + if (!texture->swapchain) + ERR("Texture %p does not have a drawable.\n", texture); + return TRUE; + + case WINED3D_LOCATION_RB_MULTISAMPLE: + wined3d_texture_gl_prepare_rb(texture_gl, context_gl->gl_info, TRUE); + return TRUE; + + case WINED3D_LOCATION_RB_RESOLVED: + wined3d_texture_gl_prepare_rb(texture_gl, context_gl->gl_info, FALSE); + return TRUE; + + default: + ERR("Invalid location %s.\n", wined3d_debug_location(location)); + return FALSE; + } +} + +static bool use_ffp_clear(const struct wined3d_texture *texture, unsigned int location) +{ + if (location == WINED3D_LOCATION_DRAWABLE) + return true; + + if (location == WINED3D_LOCATION_TEXTURE_RGB + && !(texture->resource.format_caps & WINED3D_FORMAT_CAP_FBO_ATTACHABLE)) + return false; + if (location == WINED3D_LOCATION_TEXTURE_SRGB + && !(texture->resource.format_caps & WINED3D_FORMAT_CAP_FBO_ATTACHABLE_SRGB)) + return false; + + return location & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED + | WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB); +} + +static bool wined3d_texture_gl_clear(struct wined3d_texture *texture, + unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl, unsigned int location) +{ + struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx]; + const struct wined3d_format *format = texture->resource.format; + const struct wined3d_gl_info *gl_info = context_gl->gl_info; + struct wined3d_bo_address addr; + + /* The code that delays clears is Vulkan-specific, so here we should only + * encounter WINED3D_LOCATION_CLEARED on newly created resources and thus + * a zero clear value. */ + if (!format->depth_size && !format->stencil_size) + { + if (sub_resource->clear_value.colour.r || sub_resource->clear_value.colour.g + || sub_resource->clear_value.colour.b || sub_resource->clear_value.colour.a) + { + ERR("Unexpected color clear value r=%08e, g=%08e, b=%08e, a=%08e.\n", + sub_resource->clear_value.colour.r, sub_resource->clear_value.colour.g, + sub_resource->clear_value.colour.b, sub_resource->clear_value.colour.a); + } + } + else + { + if (format->depth_size && sub_resource->clear_value.depth) + ERR("Unexpected depth clear value %08e.\n", sub_resource->clear_value.depth); + if (format->stencil_size && sub_resource->clear_value.stencil) + ERR("Unexpected stencil clear value %x.\n", sub_resource->clear_value.stencil); + } + + if (use_ffp_clear(texture, location)) + { + GLbitfield clear_mask = 0; + + context_gl_apply_texture_draw_state(context_gl, texture, sub_resource_idx, location); + + gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST); + context_invalidate_state(&context_gl->c, STATE_RASTERIZER); + + if (format->depth_size) + { + gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE); + context_invalidate_state(&context_gl->c, STATE_DEPTH_STENCIL); + + if (gl_info->supported[ARB_ES2_COMPATIBILITY]) + GL_EXTCALL(glClearDepthf(0.0f)); + else + gl_info->gl_ops.gl.p_glClearDepth(0.0); + clear_mask |= GL_DEPTH_BUFFER_BIT; + } + + if (format->stencil_size) + { + if (gl_info->supported[EXT_STENCIL_TWO_SIDE]) + gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT); + gl_info->gl_ops.gl.p_glStencilMask(~0u); + context_invalidate_state(&context_gl->c, STATE_DEPTH_STENCIL); + gl_info->gl_ops.gl.p_glClearStencil(0); + clear_mask |= GL_STENCIL_BUFFER_BIT; + } + + if (!format->depth_size && !format->stencil_size) + { + gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + context_invalidate_state(&context_gl->c, STATE_BLEND); + gl_info->gl_ops.gl.p_glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + clear_mask |= GL_COLOR_BUFFER_BIT; + } + + gl_info->gl_ops.gl.p_glClear(clear_mask); + checkGLcall("clear texture"); + + wined3d_texture_validate_location(texture, sub_resource_idx, location); + return true; + } + + if (!wined3d_texture_prepare_location(texture, sub_resource_idx, &context_gl->c, WINED3D_LOCATION_SYSMEM)) + return false; + wined3d_texture_get_bo_address(texture, sub_resource_idx, &addr, WINED3D_LOCATION_SYSMEM); + memset(addr.addr, 0, sub_resource->size); + wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_SYSMEM); + return true; +} + +static BOOL wined3d_texture_load_renderbuffer(struct wined3d_texture *texture, + unsigned int sub_resource_idx, struct wined3d_context *context, DWORD dst_location) +{ + unsigned int level = sub_resource_idx % texture->level_count; + const RECT rect = {0, 0, + wined3d_texture_get_level_width(texture, level), + wined3d_texture_get_level_height(texture, level)}; + struct wined3d_texture_sub_resource *sub_resource; + DWORD src_location, locations; + + sub_resource = &texture->sub_resources[sub_resource_idx]; + locations = sub_resource->locations; + if (texture->resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL) + { + FIXME("Unimplemented copy from %s for depth/stencil buffers.\n", + wined3d_debug_location(locations)); + return FALSE; + } + + if (locations & WINED3D_LOCATION_RB_MULTISAMPLE) + src_location = WINED3D_LOCATION_RB_MULTISAMPLE; + else if (locations & WINED3D_LOCATION_RB_RESOLVED) + src_location = WINED3D_LOCATION_RB_RESOLVED; + else if (locations & WINED3D_LOCATION_TEXTURE_SRGB) + src_location = WINED3D_LOCATION_TEXTURE_SRGB; + else if (locations & WINED3D_LOCATION_TEXTURE_RGB) + src_location = WINED3D_LOCATION_TEXTURE_RGB; + else if (locations & WINED3D_LOCATION_DRAWABLE) + src_location = WINED3D_LOCATION_DRAWABLE; + else /* texture2d_blt_fbo() will load the source location if necessary. */ + src_location = WINED3D_LOCATION_TEXTURE_RGB; + + texture2d_blt_fbo(texture->resource.device, context, WINED3D_TEXF_POINT, texture, + sub_resource_idx, src_location, &rect, texture, sub_resource_idx, dst_location, &rect, NULL); + + return TRUE; +} + +/* Context activation is done by the caller. */ +static BOOL wined3d_texture_gl_load_location(struct wined3d_texture *texture, + unsigned int sub_resource_idx, struct wined3d_context *context, uint32_t location) +{ + struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx]; + struct wined3d_texture_gl *texture_gl = wined3d_texture_gl(texture); + struct wined3d_context_gl *context_gl = wined3d_context_gl(context); + + TRACE("texture %p, sub_resource_idx %u, context %p, location %s.\n", + texture, sub_resource_idx, context, wined3d_debug_location(location)); + + if (!wined3d_texture_gl_prepare_location(texture, sub_resource_idx, context, location)) + return FALSE; + + if (sub_resource->locations & WINED3D_LOCATION_CLEARED) + { + if (!wined3d_texture_gl_clear(texture, sub_resource_idx, context_gl, location)) + return FALSE; + + if (sub_resource->locations & location) + return TRUE; + } + + switch (location) + { + case WINED3D_LOCATION_SYSMEM: + case WINED3D_LOCATION_BUFFER: + return wined3d_texture_gl_load_sysmem(texture_gl, sub_resource_idx, context_gl, location); + + case WINED3D_LOCATION_DRAWABLE: + return wined3d_texture_load_drawable(texture, sub_resource_idx, context); + + case WINED3D_LOCATION_RB_RESOLVED: + case WINED3D_LOCATION_RB_MULTISAMPLE: + return wined3d_texture_load_renderbuffer(texture, sub_resource_idx, context, location); + + case WINED3D_LOCATION_TEXTURE_RGB: + case WINED3D_LOCATION_TEXTURE_SRGB: + return wined3d_texture_gl_load_texture(texture_gl, sub_resource_idx, + context_gl, location == WINED3D_LOCATION_TEXTURE_SRGB); + + default: + FIXME("Unhandled %s load from %s.\n", wined3d_debug_location(location), + wined3d_debug_location(texture->sub_resources[sub_resource_idx].locations)); + return FALSE; + } +} + +static void wined3d_texture_gl_unload_location(struct wined3d_texture *texture, + struct wined3d_context *context, unsigned int location) +{ + struct wined3d_texture_gl *texture_gl = wined3d_texture_gl(texture); + struct wined3d_context_gl *context_gl = wined3d_context_gl(context); + struct wined3d_renderbuffer_entry *entry, *entry2; + unsigned int i, sub_count; + + TRACE("texture %p, context %p, location %s.\n", texture, context, wined3d_debug_location(location)); + + switch (location) + { + case WINED3D_LOCATION_BUFFER: + sub_count = texture->level_count * texture->layer_count; + for (i = 0; i < sub_count; ++i) + { + if (texture_gl->t.sub_resources[i].bo) + wined3d_texture_remove_buffer_object(&texture_gl->t, i, context_gl); + } + break; + + case WINED3D_LOCATION_TEXTURE_RGB: + if (texture_gl->texture_rgb.name) + gltexture_delete(texture_gl->t.resource.device, context_gl->gl_info, &texture_gl->texture_rgb); + break; + + case WINED3D_LOCATION_TEXTURE_SRGB: + if (texture_gl->texture_srgb.name) + gltexture_delete(texture_gl->t.resource.device, context_gl->gl_info, &texture_gl->texture_srgb); + break; + + case WINED3D_LOCATION_RB_MULTISAMPLE: + if (texture_gl->rb_multisample) + { + TRACE("Deleting multisample renderbuffer %u.\n", texture_gl->rb_multisample); + context_gl_resource_released(texture_gl->t.resource.device, texture_gl->rb_multisample, TRUE); + context_gl->gl_info->fbo_ops.glDeleteRenderbuffers(1, &texture_gl->rb_multisample); + texture_gl->rb_multisample = 0; + } + break; + + case WINED3D_LOCATION_RB_RESOLVED: + LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &texture_gl->renderbuffers, + struct wined3d_renderbuffer_entry, entry) + { + context_gl_resource_released(texture_gl->t.resource.device, entry->id, TRUE); + context_gl->gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id); + list_remove(&entry->entry); + free(entry); + } + list_init(&texture_gl->renderbuffers); + texture_gl->current_renderbuffer = NULL; + + if (texture_gl->rb_resolved) + { + TRACE("Deleting resolved renderbuffer %u.\n", texture_gl->rb_resolved); + context_gl_resource_released(texture_gl->t.resource.device, texture_gl->rb_resolved, TRUE); + context_gl->gl_info->fbo_ops.glDeleteRenderbuffers(1, &texture_gl->rb_resolved); + texture_gl->rb_resolved = 0; + } + break; + + default: + ERR("Unhandled location %s.\n", wined3d_debug_location(location)); + break; + } +} + +static const struct wined3d_texture_ops texture_gl_ops = +{ + wined3d_texture_gl_prepare_location, + wined3d_texture_gl_load_location, + wined3d_texture_gl_unload_location, + wined3d_texture_gl_upload_data, + wined3d_texture_gl_download_data, +}; + +HRESULT wined3d_texture_gl_init(struct wined3d_texture_gl *texture_gl, struct wined3d_device *device, + const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count, + uint32_t flags, void *parent, const struct wined3d_parent_ops *parent_ops) +{ + const struct wined3d_gl_info *gl_info = &wined3d_adapter_gl(device->adapter)->gl_info; + HRESULT hr; + + TRACE("texture_gl %p, device %p, desc %p, layer_count %u, " + "level_count %u, flags %#x, parent %p, parent_ops %p.\n", + texture_gl, device, desc, layer_count, + level_count, flags, parent, parent_ops); + + if (!(desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP) && layer_count > 1 + && !gl_info->supported[EXT_TEXTURE_ARRAY]) + { + WARN("OpenGL implementation does not support array textures.\n"); + return WINED3DERR_INVALIDCALL; + } + + switch (desc->resource_type) + { + case WINED3D_RTYPE_TEXTURE_1D: + if (layer_count > 1) + texture_gl->target = GL_TEXTURE_1D_ARRAY; + else + texture_gl->target = GL_TEXTURE_1D; + break; + + case WINED3D_RTYPE_TEXTURE_2D: + if (desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP) + { + texture_gl->target = GL_TEXTURE_CUBE_MAP_ARB; + } + else if (desc->multisample_type && gl_info->supported[ARB_TEXTURE_MULTISAMPLE]) + { + if (layer_count > 1) + texture_gl->target = GL_TEXTURE_2D_MULTISAMPLE_ARRAY; + else + texture_gl->target = GL_TEXTURE_2D_MULTISAMPLE; + } + else + { + if (layer_count > 1) + texture_gl->target = GL_TEXTURE_2D_ARRAY; + else + texture_gl->target = GL_TEXTURE_2D; + } + break; + + case WINED3D_RTYPE_TEXTURE_3D: + if (!gl_info->supported[EXT_TEXTURE3D]) + { + WARN("OpenGL implementation does not support 3D textures.\n"); + return WINED3DERR_INVALIDCALL; + } + texture_gl->target = GL_TEXTURE_3D; + break; + + default: + ERR("Invalid resource type %s.\n", debug_d3dresourcetype(desc->resource_type)); + return WINED3DERR_INVALIDCALL; + } + + list_init(&texture_gl->renderbuffers); + + if (FAILED(hr = wined3d_texture_init(&texture_gl->t, desc, layer_count, level_count, + flags, device, parent, parent_ops, &texture_gl[1], &texture_gl_ops))) + return hr; + + if (texture_gl->target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY || texture_gl->target == GL_TEXTURE_2D_MULTISAMPLE) + texture_gl->t.flags &= ~WINED3D_TEXTURE_DOWNLOADABLE; + + return WINED3D_OK; +} + +static void ffp_blitter_clear_rendertargets(struct wined3d_device *device, unsigned int rt_count, + const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rect, const RECT *draw_rect, + uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int stencil) +{ + struct wined3d_rendertarget_view *rtv = rt_count ? fb->render_targets[0] : NULL; + struct wined3d_rendertarget_view *dsv = fb->depth_stencil; + const struct wined3d_state *state = &device->cs->state; + struct wined3d_texture *depth_stencil = NULL; + unsigned int drawable_width, drawable_height; + const struct wined3d_gl_info *gl_info; + struct wined3d_context_gl *context_gl; + struct wined3d_texture *target = NULL; + struct wined3d_color colour_srgb; + struct wined3d_context *context; + GLbitfield clear_mask = 0; + bool render_offscreen; + unsigned int i; + + if (rtv && rtv->resource->type != WINED3D_RTYPE_BUFFER) + { + target = texture_from_resource(rtv->resource); + context = context_acquire(device, target, rtv->sub_resource_idx); + } + else + { + context = context_acquire(device, NULL, 0); + } + context_gl = wined3d_context_gl(context); + + if (dsv && dsv->resource->type != WINED3D_RTYPE_BUFFER) + depth_stencil = texture_from_resource(dsv->resource); + + if (!context_gl->valid) + { + context_release(context); + WARN("Invalid context, skipping clear.\n"); + return; + } + gl_info = context_gl->gl_info; + + /* When we're clearing parts of the drawable, make sure that the target + * surface is well up to date in the drawable. After the clear we'll mark + * the drawable up to date, so we have to make sure that this is true for + * the cleared parts, and the untouched parts. + * + * If we're clearing the whole target there is no need to copy it into the + * drawable, it will be overwritten anyway. If we're not clearing the + * colour buffer we don't have to copy either since we're not going to set + * the drawable up to date. We have to check all settings that limit the + * clear area though. Do not bother checking all this if the destination + * surface is in the drawable anyway. */ + for (i = 0; i < rt_count; ++i) + { + struct wined3d_rendertarget_view *rtv = fb->render_targets[i]; + + if (rtv && rtv->format->id != WINED3DFMT_NULL) + { + if (flags & WINED3DCLEAR_TARGET && !is_full_clear(rtv, draw_rect, rect_count ? clear_rect : NULL)) + wined3d_rendertarget_view_load_location(rtv, context, rtv->resource->draw_binding); + else + wined3d_rendertarget_view_prepare_location(rtv, context, rtv->resource->draw_binding); + } + } + + if (target) + { + render_offscreen = wined3d_resource_is_offscreen(&target->resource); + wined3d_rendertarget_view_get_drawable_size(rtv, context, &drawable_width, &drawable_height); + } + else + { + unsigned int ds_level = dsv->sub_resource_idx % depth_stencil->level_count; + + render_offscreen = true; + drawable_width = wined3d_texture_get_level_width(depth_stencil, ds_level); + drawable_height = wined3d_texture_get_level_height(depth_stencil, ds_level); + } + + if (depth_stencil) + { + DWORD ds_location = render_offscreen ? dsv->resource->draw_binding : WINED3D_LOCATION_DRAWABLE; + + if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) + && !is_full_clear(dsv, draw_rect, rect_count ? clear_rect : NULL) + wined3d_rendertarget_view_load_location(dsv, context, ds_location); + else + wined3d_rendertarget_view_prepare_location(dsv, context, ds_location); + + if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) + { + wined3d_rendertarget_view_validate_location(dsv, ds_location); + wined3d_rendertarget_view_invalidate_location(dsv, ~ds_location); + } + } + + if (!wined3d_context_gl_apply_clear_state(context_gl, state, rt_count, fb)) + { + context_release(context); + WARN("Failed to apply clear state, skipping clear.\n"); + return; + } + + /* Only set the values up once, as they are not changing. */ + if (flags & WINED3DCLEAR_STENCIL) + { + if (gl_info->supported[EXT_STENCIL_TWO_SIDE]) + gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT); + gl_info->gl_ops.gl.p_glStencilMask(~0u); + context_invalidate_state(context, STATE_DEPTH_STENCIL); + gl_info->gl_ops.gl.p_glClearStencil(stencil); + checkGLcall("glClearStencil"); + clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT; + } + + if (flags & WINED3DCLEAR_ZBUFFER) + { + gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE); + context_invalidate_state(context, STATE_DEPTH_STENCIL); + if (gl_info->supported[ARB_ES2_COMPATIBILITY]) + GL_EXTCALL(glClearDepthf(depth)); + else + gl_info->gl_ops.gl.p_glClearDepth(depth); + checkGLcall("glClearDepth"); + clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT; + } + + if (flags & WINED3DCLEAR_TARGET) + { + for (i = 0; i < rt_count; ++i) + { + struct wined3d_rendertarget_view *rtv = fb->render_targets[i]; + + if (!rtv) + continue; + + if (rtv->resource->type == WINED3D_RTYPE_BUFFER) + { + FIXME("Not supported on buffer resources.\n"); + continue; + } + + wined3d_rendertarget_view_validate_location(rtv, rtv->resource->draw_binding); + wined3d_rendertarget_view_invalidate_location(rtv, ~rtv->resource->draw_binding); + } + + if (!gl_info->supported[ARB_FRAMEBUFFER_SRGB] && needs_srgb_write(context->d3d_info, state, fb)) + { + if (rt_count > 1) + WARN("Clearing multiple sRGB render targets without GL_ARB_framebuffer_sRGB " + "support, this might cause graphical issues.\n"); + + wined3d_colour_srgb_from_linear(&colour_srgb, colour); + colour = &colour_srgb; + } + + gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + context_invalidate_state(context, STATE_BLEND); + gl_info->gl_ops.gl.p_glClearColor(colour->r, colour->g, colour->b, colour->a); + checkGLcall("glClearColor"); + clear_mask = clear_mask | GL_COLOR_BUFFER_BIT; + } + + if (!rect_count) + { + if (render_offscreen) + { + gl_info->gl_ops.gl.p_glScissor(draw_rect->left, draw_rect->top, + draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top); + } + else + { + gl_info->gl_ops.gl.p_glScissor(draw_rect->left, drawable_height - draw_rect->bottom, + draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top); + } + gl_info->gl_ops.gl.p_glClear(clear_mask); + } + else + { + RECT current_rect; + + /* Now process each rect in turn. */ + for (i = 0; i < rect_count; ++i) + { + /* Note that GL uses lower left, width/height. */ + IntersectRect(¤t_rect, draw_rect, &clear_rect[i]); + + TRACE("clear_rect[%u] %s, current_rect %s.\n", i, + wine_dbgstr_rect(&clear_rect[i]), + wine_dbgstr_rect(¤t_rect)); + + /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored + * silently. The rectangle is not cleared, no error is returned, + * but further rectangles are still cleared if they are valid. */ + if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom) + { + TRACE("Rectangle with negative dimensions, ignoring.\n"); + continue; + } + + if (render_offscreen) + { + gl_info->gl_ops.gl.p_glScissor(current_rect.left, current_rect.top, + current_rect.right - current_rect.left, current_rect.bottom - current_rect.top); + } + else + { + gl_info->gl_ops.gl.p_glScissor(current_rect.left, drawable_height - current_rect.bottom, + current_rect.right - current_rect.left, current_rect.bottom - current_rect.top); + } + gl_info->gl_ops.gl.p_glClear(clear_mask); + } + } + context->scissor_rect_count = WINED3D_MAX_VIEWPORTS; + checkGLcall("clear"); + + if (flags & WINED3DCLEAR_TARGET && target->swapchain && target->swapchain->front_buffer == target) + gl_info->gl_ops.gl.p_glFlush(); + + context_release(context); +} + +static void ffp_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context) +{ + struct wined3d_blitter *next; + + if ((next = blitter->next)) + next->ops->blitter_destroy(next, context); + + free(blitter); +} + +static void ffp_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device, + unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects, + const RECT *draw_rect, uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int stencil) +{ + struct wined3d_rendertarget_view *view, *previous = NULL; + bool have_identical_size = TRUE; + struct wined3d_fb_state tmp_fb; + unsigned int next_rt_count = 0; + struct wined3d_blitter *next; + DWORD next_flags = 0; + unsigned int i; + + if (flags & WINED3DCLEAR_TARGET) + { + for (i = 0; i < rt_count; ++i) + { + if (!(view = fb->render_targets[i])) + continue; + + if (blitter_use_cpu_clear(view) + || (!(view->resource->bind_flags & WINED3D_BIND_RENDER_TARGET) + && !(view->format_caps & WINED3D_FORMAT_CAP_FBO_ATTACHABLE))) + { + next_flags |= WINED3DCLEAR_TARGET; + flags &= ~WINED3DCLEAR_TARGET; + next_rt_count = rt_count; + rt_count = 0; + break; + } + + /* FIXME: We should reject colour fills on formats with fixups, + * but this would break P8 colour fills for example. */ + } + } + + if ((flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) && (view = fb->depth_stencil) + && (!view->format->depth_size || (flags & WINED3DCLEAR_ZBUFFER)) + && (!view->format->stencil_size || (flags & WINED3DCLEAR_STENCIL)) + && blitter_use_cpu_clear(view)) + { + next_flags |= flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL); + flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL); + } + + if (flags) + { + for (i = 0; i < rt_count; ++i) + { + if (!(view = fb->render_targets[i])) + continue; + + if (previous && (previous->width != view->width || previous->height != view->height)) + have_identical_size = false; + previous = view; + } + if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) + { + view = fb->depth_stencil; + + if (previous && (previous->width != view->width || previous->height != view->height)) + have_identical_size = false; + } + + if (have_identical_size) + { + ffp_blitter_clear_rendertargets(device, rt_count, fb, rect_count, + clear_rects, draw_rect, flags, colour, depth, stencil); + } + else + { + for (i = 0; i < rt_count; ++i) + { + if (!(view = fb->render_targets[i])) + continue; + + tmp_fb.render_targets[0] = view; + tmp_fb.depth_stencil = NULL; + ffp_blitter_clear_rendertargets(device, 1, &tmp_fb, rect_count, + clear_rects, draw_rect, WINED3DCLEAR_TARGET, colour, depth, stencil); + } + if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) + { + tmp_fb.render_targets[0] = NULL; + tmp_fb.depth_stencil = fb->depth_stencil; + ffp_blitter_clear_rendertargets(device, 0, &tmp_fb, rect_count, + clear_rects, draw_rect, flags & ~WINED3DCLEAR_TARGET, colour, depth, stencil); + } + } + } + + if (next_flags && (next = blitter->next)) + next->ops->blitter_clear(next, device, next_rt_count, fb, rect_count, + clear_rects, draw_rect, next_flags, colour, depth, stencil); +} + +static DWORD ffp_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op, + struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, + DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture, + unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect, + const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter, + const struct wined3d_format *resolve_format) +{ + struct wined3d_blitter *next; + + if (!(next = blitter->next)) + { + ERR("No blitter to handle blit op %#x.\n", op); + return dst_location; + } + + return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location, + src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter, + resolve_format); +} + +static const struct wined3d_blitter_ops ffp_blitter_ops = +{ + ffp_blitter_destroy, + ffp_blitter_clear, + ffp_blitter_blit, +}; + +void wined3d_ffp_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info) +{ + struct wined3d_blitter *blitter; + + if (!(blitter = malloc(sizeof(*blitter)))) + return; + + TRACE("Created blitter %p.\n", blitter); + + blitter->ops = &ffp_blitter_ops; + blitter->next = *next; + *next = blitter; +} + +static void fbo_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context) +{ + struct wined3d_blitter *next; + + if ((next = blitter->next)) + next->ops->blitter_destroy(next, context); + + free(blitter); +} + +static void fbo_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device, + unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects, + const RECT *draw_rect, uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int stencil) +{ + struct wined3d_blitter *next; + + if ((next = blitter->next)) + next->ops->blitter_clear(next, device, rt_count, fb, rect_count, + clear_rects, draw_rect, flags, colour, depth, stencil); +} + +static DWORD fbo_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op, + struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, + DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture, + unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect, + const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter, + const struct wined3d_format *resolve_format) +{ + struct wined3d_context_gl *context_gl = wined3d_context_gl(context); + struct wined3d_resource *src_resource, *dst_resource; + enum wined3d_blit_op blit_op = op; + struct wined3d_device *device; + struct wined3d_blitter *next; + + TRACE("blitter %p, op %#x, context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, " + "src_rect %s, dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s, " + "colour_key %p, filter %s, resolve_format %p.\n", + blitter, op, context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location), + wine_dbgstr_rect(src_rect), dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location), + wine_dbgstr_rect(dst_rect), colour_key, debug_d3dtexturefiltertype(filter), resolve_format); + + src_resource = &src_texture->resource; + dst_resource = &dst_texture->resource; + + device = dst_resource->device; + + if (blit_op == WINED3D_BLIT_OP_RAW_BLIT && dst_resource->format->id == src_resource->format->id) + { + if (dst_resource->format->depth_size || dst_resource->format->stencil_size) + blit_op = WINED3D_BLIT_OP_DEPTH_BLIT; + else + blit_op = WINED3D_BLIT_OP_COLOR_BLIT; + } + + if (!fbo_blitter_supported(blit_op, context_gl->gl_info, + src_resource, src_location, dst_resource, dst_location)) + { + if (!(next = blitter->next)) + { + ERR("No blitter to handle blit op %#x.\n", op); + return dst_location; + } + + TRACE("Forwarding to blitter %p.\n", next); + return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location, + src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter, + resolve_format); + } + + if (blit_op == WINED3D_BLIT_OP_COLOR_BLIT) + { + TRACE("Colour blit.\n"); + texture2d_blt_fbo(device, context, filter, src_texture, src_sub_resource_idx, src_location, + src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, resolve_format); + return dst_location; + } + + if (blit_op == WINED3D_BLIT_OP_DEPTH_BLIT) + { + TRACE("Depth/stencil blit.\n"); + texture2d_depth_blt_fbo(device, context, src_texture, src_sub_resource_idx, src_location, + src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect); + return dst_location; + } + + ERR("This blitter does not implement blit op %#x.\n", blit_op); + return dst_location; +} + +static const struct wined3d_blitter_ops fbo_blitter_ops = +{ + fbo_blitter_destroy, + fbo_blitter_clear, + fbo_blitter_blit, +}; + +void wined3d_fbo_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info) +{ + struct wined3d_blitter *blitter; + + if (!(blitter = malloc(sizeof(*blitter)))) + return; + + TRACE("Created blitter %p.\n", blitter); + + blitter->ops = &fbo_blitter_ops; + blitter->next = *next; + *next = blitter; +} + +static void raw_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context) +{ + struct wined3d_blitter *next; + + if ((next = blitter->next)) + next->ops->blitter_destroy(next, context); + + free(blitter); +} + +static void raw_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device, + unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects, + const RECT *draw_rect, uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int stencil) +{ + struct wined3d_blitter *next; + + if (!(next = blitter->next)) + { + ERR("No blitter to handle clear.\n"); + return; + } + + TRACE("Forwarding to blitter %p.\n", next); + next->ops->blitter_clear(next, device, rt_count, fb, rect_count, + clear_rects, draw_rect, flags, colour, depth, stencil); +} + +static bool gl_formats_compatible(struct wined3d_texture *src_texture, DWORD src_location, + struct wined3d_texture *dst_texture, DWORD dst_location) +{ + GLuint src_internal, dst_internal; + bool src_ds, dst_ds; + + src_ds = src_texture->resource.format->depth_size || src_texture->resource.format->stencil_size; + dst_ds = dst_texture->resource.format->depth_size || dst_texture->resource.format->stencil_size; + if (src_ds == dst_ds) + return true; + /* Also check the internal format because, e.g. WINED3DFMT_D24_UNORM_S8_UINT has nonzero depth and stencil + * sizes as does WINED3DFMT_R24G8_TYPELESS when bound with flag WINED3D_BIND_DEPTH_STENCIL, but these share + * the same internal format with WINED3DFMT_R24_UNORM_X8_TYPELESS. */ + src_internal = wined3d_gl_get_internal_format(&src_texture->resource, + wined3d_format_gl(src_texture->resource.format), src_location == WINED3D_LOCATION_TEXTURE_SRGB); + dst_internal = wined3d_gl_get_internal_format(&dst_texture->resource, + wined3d_format_gl(dst_texture->resource.format), dst_location == WINED3D_LOCATION_TEXTURE_SRGB); + return src_internal == dst_internal; +} + +static DWORD raw_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op, + struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, + DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture, + unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect, + const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter, + const struct wined3d_format *resolve_format) +{ + struct wined3d_texture_gl *src_texture_gl = wined3d_texture_gl(src_texture); + struct wined3d_texture_gl *dst_texture_gl = wined3d_texture_gl(dst_texture); + struct wined3d_context_gl *context_gl = wined3d_context_gl(context); + const struct wined3d_gl_info *gl_info = context_gl->gl_info; + unsigned int src_level, src_layer, dst_level, dst_layer; + struct wined3d_blitter *next; + GLuint src_name, dst_name; + DWORD location; + + /* If we would need to copy from a renderbuffer or drawable, we'd probably + * be better off using the FBO blitter directly, since we'd need to use it + * to copy the resource contents to the texture anyway. + * + * We also can't copy between depth/stencil and colour resources, since + * the formats are considered incompatible in OpenGL. */ + if (op != WINED3D_BLIT_OP_RAW_BLIT || !gl_formats_compatible(src_texture, src_location, dst_texture, dst_location) + || ((src_texture->resource.format_attrs | dst_texture->resource.format_attrs) + & WINED3D_FORMAT_ATTR_HEIGHT_SCALE) + || (src_texture->resource.format->id == dst_texture->resource.format->id + && (!(src_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB)) + || !(dst_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))))) + { + if (!(next = blitter->next)) + { + ERR("No blitter to handle blit op %#x.\n", op); + return dst_location; + } + + TRACE("Forwarding to blitter %p.\n", next); + return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location, + src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter, + resolve_format); + } + + TRACE("Blit using ARB_copy_image.\n"); + + src_level = src_sub_resource_idx % src_texture->level_count; + src_layer = src_sub_resource_idx / src_texture->level_count; + + dst_level = dst_sub_resource_idx % dst_texture->level_count; + dst_layer = dst_sub_resource_idx / dst_texture->level_count; + + location = src_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB); + if (!location) + location = src_texture->flags & WINED3D_TEXTURE_IS_SRGB + ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB; + if (!wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, location)) + ERR("Failed to load the source sub-resource into %s.\n", wined3d_debug_location(location)); + src_name = wined3d_texture_gl_get_texture_name(src_texture_gl, + context, location == WINED3D_LOCATION_TEXTURE_SRGB); + + location = dst_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB); + if (!location) + location = dst_texture->flags & WINED3D_TEXTURE_IS_SRGB + ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB; + if (wined3d_texture_is_full_rect(dst_texture, dst_level, dst_rect)) + { + if (!wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, location)) + ERR("Failed to prepare the destination sub-resource into %s.\n", wined3d_debug_location(location)); + } + else + { + if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, location)) + ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(location)); + } + dst_name = wined3d_texture_gl_get_texture_name(dst_texture_gl, + context, location == WINED3D_LOCATION_TEXTURE_SRGB); + + GL_EXTCALL(glCopyImageSubData(src_name, src_texture_gl->target, src_level, + src_rect->left, src_rect->top, src_layer, dst_name, dst_texture_gl->target, dst_level, + dst_rect->left, dst_rect->top, dst_layer, src_rect->right - src_rect->left, + src_rect->bottom - src_rect->top, 1)); + checkGLcall("copy image data"); + + wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, location); + wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~location); + if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location)) + ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(dst_location)); + + return dst_location | location; +} + +static const struct wined3d_blitter_ops raw_blitter_ops = +{ + raw_blitter_destroy, + raw_blitter_clear, + raw_blitter_blit, +}; + +void wined3d_raw_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info) +{ + struct wined3d_blitter *blitter; + + if (!gl_info->supported[ARB_COPY_IMAGE]) + return; + + if (!(blitter = malloc(sizeof(*blitter)))) + return; + + TRACE("Created blitter %p.\n", blitter); + + blitter->ops = &raw_blitter_ops; + blitter->next = *next; + *next = blitter; +} diff --git a/dlls/wined3d/texture_vk.c b/dlls/wined3d/texture_vk.c new file mode 100644 index 00000000000..830c6afa3d0 --- /dev/null +++ b/dlls/wined3d/texture_vk.c @@ -0,0 +1,1950 @@ +#include "wined3d_private.h" +#include "wined3d_vk.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d); +WINE_DECLARE_DEBUG_CHANNEL(d3d_perf); +WINE_DECLARE_DEBUG_CHANNEL(winediag); + +void wined3d_vk_swizzle_from_color_fixup(VkComponentMapping *mapping, struct color_fixup_desc fixup) +{ + static const VkComponentSwizzle swizzle_source[] = + { + VK_COMPONENT_SWIZZLE_ZERO, /* CHANNEL_SOURCE_ZERO */ + VK_COMPONENT_SWIZZLE_ONE, /* CHANNEL_SOURCE_ONE */ + VK_COMPONENT_SWIZZLE_R, /* CHANNEL_SOURCE_X */ + VK_COMPONENT_SWIZZLE_G, /* CHANNEL_SOURCE_Y */ + VK_COMPONENT_SWIZZLE_B, /* CHANNEL_SOURCE_Z */ + VK_COMPONENT_SWIZZLE_A, /* CHANNEL_SOURCE_W */ + }; + + mapping->r = swizzle_source[fixup.x_source]; + mapping->g = swizzle_source[fixup.y_source]; + mapping->b = swizzle_source[fixup.z_source]; + mapping->a = swizzle_source[fixup.w_source]; +} + +const VkDescriptorImageInfo *wined3d_texture_vk_get_default_image_info(struct wined3d_texture_vk *texture_vk, + struct wined3d_context_vk *context_vk) +{ + const struct wined3d_format_vk *format_vk; + const struct wined3d_vk_info *vk_info; + struct wined3d_device_vk *device_vk; + VkImageViewCreateInfo create_info; + struct color_fixup_desc fixup; + uint32_t flags = 0; + VkResult vr; + + if (texture_vk->default_image_info.imageView) + return &texture_vk->default_image_info; + + format_vk = wined3d_format_vk(texture_vk->t.resource.format); + device_vk = wined3d_device_vk(texture_vk->t.resource.device); + vk_info = context_vk->vk_info; + + if (texture_vk->t.layer_count > 1) + flags |= WINED3D_VIEW_TEXTURE_ARRAY; + + wined3d_texture_vk_prepare_texture(texture_vk, context_vk); + create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + create_info.pNext = NULL; + create_info.flags = 0; + create_info.image = texture_vk->image.vk_image; + create_info.viewType = vk_image_view_type_from_wined3d(texture_vk->t.resource.type, flags); + create_info.format = format_vk->vk_format; + fixup = format_vk->f.color_fixup; + if (is_identity_fixup(fixup) || !can_use_texture_swizzle(context_vk->c.d3d_info, &format_vk->f)) + { + create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + } + else + { + wined3d_vk_swizzle_from_color_fixup(&create_info.components, fixup); + } + create_info.subresourceRange.aspectMask = vk_aspect_mask_from_format(&format_vk->f); + create_info.subresourceRange.baseMipLevel = 0; + create_info.subresourceRange.levelCount = texture_vk->t.level_count; + create_info.subresourceRange.baseArrayLayer = 0; + create_info.subresourceRange.layerCount = texture_vk->t.layer_count; + if ((vr = VK_CALL(vkCreateImageView(device_vk->vk_device, &create_info, + NULL, &texture_vk->default_image_info.imageView))) < 0) + { + ERR("Failed to create Vulkan image view, vr %s.\n", wined3d_debug_vkresult(vr)); + return NULL; + } + + TRACE("Created image view 0x%s.\n", wine_dbgstr_longlong(texture_vk->default_image_info.imageView)); + + texture_vk->default_image_info.sampler = VK_NULL_HANDLE; + + /* The default image view is used for SRVs, UAVs and RTVs when the d3d view encompasses the entire + * resource. Any UAV capable resource will always use VK_IMAGE_LAYOUT_GENERAL, so we can use the + * same image info for SRVs and UAVs. For render targets wined3d_rendertarget_view_vk_get_image_view + * only cares about the VkImageView, not entire image info. So using SHADER_READ_ONLY_OPTIMAL works, + * but relies on what the callers of the function do and don't do with the descriptor we return. + * + * Note that VkWriteDescriptorSet for SRV/UAV use takes a VkDescriptorImageInfo *, so we need a + * place to store the VkDescriptorImageInfo. So returning onlky a VkImageView from this function + * would bring its own problems. */ + if (texture_vk->layout == VK_IMAGE_LAYOUT_GENERAL) + texture_vk->default_image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + else + texture_vk->default_image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + return &texture_vk->default_image_info; +} + +static void wined3d_texture_vk_upload_plane(struct wined3d_context *context, VkImageAspectFlags vk_aspect, + const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *plane_format, + const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch, + struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, + unsigned int dst_x, unsigned int dst_y, unsigned int dst_z) +{ + struct wined3d_texture_vk *dst_texture_vk = wined3d_texture_vk(dst_texture); + struct wined3d_context_vk *context_vk = wined3d_context_vk(context); + unsigned int dst_level, dst_row_pitch, dst_slice_pitch; + struct wined3d_texture_sub_resource *sub_resource; + unsigned int src_width, src_height, src_depth; + struct wined3d_bo_address staging_bo_addr; + VkPipelineStageFlags bo_stage_flags = 0; + const struct wined3d_vk_info *vk_info; + VkCommandBuffer vk_command_buffer; + VkBufferMemoryBarrier vk_barrier; + VkImageSubresourceRange vk_range; + struct wined3d_bo_vk staging_bo; + struct wined3d_bo_vk *src_bo; + struct wined3d_range range; + VkBufferImageCopy region; + size_t src_offset; + void *map_ptr; + + TRACE("context %p, vk_aspect %#x, src_bo_addr %s, plane_format %s, src_box %s, src_row_pitch %u, src_slice_pitch %u, " + "dst_texture %p, dst_sub_resource_idx %u, dst_x %u, dst_y %u, dst_z %u.\n", + context, vk_aspect, debug_const_bo_address(src_bo_addr), debug_d3dformat(plane_format->id), debug_box(src_box), + src_row_pitch, src_slice_pitch, dst_texture, dst_sub_resource_idx, dst_x, dst_y, dst_z); + + dst_level = dst_sub_resource_idx % dst_texture->level_count; + wined3d_texture_get_pitch(dst_texture, dst_level, &dst_row_pitch, &dst_slice_pitch); + if (dst_texture->resource.type == WINED3D_RTYPE_TEXTURE_1D) + src_row_pitch = dst_row_pitch = 0; + if (dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_3D) + src_slice_pitch = dst_slice_pitch = 0; + + sub_resource = &dst_texture_vk->t.sub_resources[dst_sub_resource_idx]; + vk_info = context_vk->vk_info; + + src_width = src_box->right - src_box->left; + src_height = src_box->bottom - src_box->top; + src_depth = src_box->back - src_box->front; + + src_offset = src_box->front * src_slice_pitch + + (src_box->top / plane_format->block_height) * src_row_pitch + + (src_box->left / plane_format->block_width) * plane_format->block_byte_count; + + if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk))) + { + ERR("Failed to get command buffer.\n"); + return; + } + + /* We need to be outside of a render pass for vkCmdPipelineBarrier() and vkCmdCopyBufferToImage() calls below. */ + wined3d_context_vk_end_current_render_pass(context_vk); + if (!src_bo_addr->buffer_object) + { + unsigned int staging_row_pitch, staging_slice_pitch, staging_size; + + wined3d_format_calculate_pitch(plane_format, context->device->surface_alignment, src_width, src_height, + &staging_row_pitch, &staging_slice_pitch); + staging_size = staging_slice_pitch * src_depth; + + if (!wined3d_context_vk_create_bo(context_vk, staging_size, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &staging_bo)) + { + ERR("Failed to create staging bo.\n"); + return; + } + + staging_bo_addr.buffer_object = &staging_bo.b; + staging_bo_addr.addr = NULL; + if (!(map_ptr = wined3d_context_map_bo_address(context, &staging_bo_addr, + staging_size, WINED3D_MAP_DISCARD | WINED3D_MAP_WRITE))) + { + ERR("Failed to map staging bo.\n"); + wined3d_context_vk_destroy_bo(context_vk, &staging_bo); + return; + } + + wined3d_format_copy_data(plane_format, src_bo_addr->addr + src_offset, src_row_pitch, src_slice_pitch, + map_ptr, staging_row_pitch, staging_slice_pitch, src_width, src_height, src_depth); + + range.offset = 0; + range.size = staging_size; + wined3d_context_unmap_bo_address(context, &staging_bo_addr, 1, &range); + + src_bo = &staging_bo; + + src_offset = 0; + src_row_pitch = staging_row_pitch; + src_slice_pitch = staging_slice_pitch; + } + else + { + src_bo = wined3d_bo_vk(src_bo_addr->buffer_object); + + vk_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + vk_barrier.pNext = NULL; + vk_barrier.srcAccessMask = vk_access_mask_from_buffer_usage(src_bo->usage) & ~WINED3D_READ_ONLY_ACCESS_FLAGS; + vk_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + vk_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + vk_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + vk_barrier.buffer = src_bo->vk_buffer; + vk_barrier.offset = src_bo->b.buffer_offset + (size_t)src_bo_addr->addr; + vk_barrier.size = sub_resource->size; + + src_offset += (size_t)src_bo_addr->addr; + + bo_stage_flags = vk_pipeline_stage_mask_from_buffer_usage(src_bo->usage); + if (vk_barrier.srcAccessMask) + VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, bo_stage_flags, + VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 1, &vk_barrier, 0, NULL)); + } + + vk_range.aspectMask = vk_aspect; + vk_range.baseMipLevel = dst_level; + vk_range.levelCount = 1; + vk_range.baseArrayLayer = dst_sub_resource_idx / dst_texture_vk->t.level_count; + vk_range.layerCount = 1; + + wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + vk_access_mask_from_bind_flags(dst_texture_vk->t.resource.bind_flags), + VK_ACCESS_TRANSFER_WRITE_BIT, + dst_texture_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + dst_texture_vk->image.vk_image, &vk_range); + + region.bufferOffset = src_bo->b.buffer_offset + src_offset; + region.bufferRowLength = (src_row_pitch / plane_format->block_byte_count) * plane_format->block_width; + if (src_row_pitch) + region.bufferImageHeight = (src_slice_pitch / src_row_pitch) * plane_format->block_height; + else + region.bufferImageHeight = 1; + region.imageSubresource.aspectMask = vk_range.aspectMask; + region.imageSubresource.mipLevel = vk_range.baseMipLevel; + region.imageSubresource.baseArrayLayer = vk_range.baseArrayLayer; + region.imageSubresource.layerCount = vk_range.layerCount; + region.imageOffset.x = dst_x; + region.imageOffset.y = dst_y; + region.imageOffset.z = dst_z; + region.imageExtent.width = src_width; + region.imageExtent.height = src_height; + region.imageExtent.depth = src_depth; + + VK_CALL(vkCmdCopyBufferToImage(vk_command_buffer, src_bo->vk_buffer, + dst_texture_vk->image.vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion)); + + wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, + vk_access_mask_from_bind_flags(dst_texture_vk->t.resource.bind_flags), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_texture_vk->layout, + dst_texture_vk->image.vk_image, &vk_range); + wined3d_context_vk_reference_texture(context_vk, dst_texture_vk); + wined3d_context_vk_reference_bo(context_vk, src_bo); + + if (src_bo == &staging_bo) + { + wined3d_context_vk_destroy_bo(context_vk, &staging_bo); + } + else if (vk_barrier.srcAccessMask) + { + VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, + bo_stage_flags, 0, 0, NULL, 0, NULL, 0, NULL)); + } +} + +static void wined3d_texture_vk_upload_data(struct wined3d_context *context, + const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *src_format, + const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch, + struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, unsigned int dst_location, + unsigned int dst_x, unsigned int dst_y, unsigned int dst_z) +{ + VkImageAspectFlags aspect_mask; + + TRACE("context %p, src_bo_addr %s, src_format %s, src_box %s, src_row_pitch %u, src_slice_pitch %u, " + "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_x %u, dst_y %u, dst_z %u.\n", + context, debug_const_bo_address(src_bo_addr), debug_d3dformat(src_format->id), debug_box(src_box), + src_row_pitch, src_slice_pitch, dst_texture, dst_sub_resource_idx, + wined3d_debug_location(dst_location), dst_x, dst_y, dst_z); + + if (src_format->id != dst_texture->resource.format->id) + { + FIXME("Unhandled format conversion (%s -> %s).\n", + debug_d3dformat(src_format->id), + debug_d3dformat(dst_texture->resource.format->id)); + return; + } + + if (dst_location != WINED3D_LOCATION_TEXTURE_RGB) + { + FIXME("Unhandled location %s.\n", wined3d_debug_location(dst_location)); + return; + } + + if (wined3d_resource_get_sample_count(&dst_texture->resource) > 1) + { + FIXME("Not supported for multisample textures.\n"); + return; + } + + aspect_mask = vk_aspect_mask_from_format(dst_texture->resource.format); + if (wined3d_popcount(aspect_mask) > 1) + { + FIXME("Unhandled multi-aspect format %s.\n", debug_d3dformat(dst_texture->resource.format->id)); + return; + } + + if (src_format->attrs & WINED3D_FORMAT_ATTR_PLANAR) + { + struct wined3d_const_bo_address uv_bo_addr; + const struct wined3d_format *plane_format; + struct wined3d_box uv_box; + + plane_format = wined3d_get_format(context->device->adapter, src_format->plane_formats[0], 0); + wined3d_texture_vk_upload_plane(context, VK_IMAGE_ASPECT_PLANE_0_BIT, src_bo_addr, plane_format, src_box, + src_row_pitch, src_slice_pitch, dst_texture, dst_sub_resource_idx, dst_x, dst_y, dst_z); + + uv_bo_addr = *src_bo_addr; + uv_bo_addr.addr += src_slice_pitch; + uv_box = *src_box; + uv_box.left /= src_format->uv_width; + uv_box.right /= src_format->uv_width; + uv_box.top /= src_format->uv_height; + uv_box.bottom /= src_format->uv_height; + dst_x /= src_format->uv_width; + dst_y /= src_format->uv_height; + src_row_pitch = src_row_pitch * 2 / src_format->uv_width; + src_slice_pitch = src_slice_pitch * 2 / src_format->uv_width / src_format->uv_height; + + plane_format = wined3d_get_format(context->device->adapter, src_format->plane_formats[1], 0); + wined3d_texture_vk_upload_plane(context, VK_IMAGE_ASPECT_PLANE_1_BIT, &uv_bo_addr, plane_format, &uv_box, + src_row_pitch, src_slice_pitch, dst_texture, dst_sub_resource_idx, dst_x, dst_y, dst_z); + } + else + { + wined3d_texture_vk_upload_plane(context, aspect_mask, src_bo_addr, src_format, src_box, + src_row_pitch, src_slice_pitch, dst_texture, dst_sub_resource_idx, dst_x, dst_y, dst_z); + } +} + +static void wined3d_texture_vk_download_plane(struct wined3d_context *context, VkImageAspectFlags vk_aspect, + struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, + const struct wined3d_box *src_box, const struct wined3d_bo_address *dst_bo_addr, + const struct wined3d_format *plane_format, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, + unsigned int dst_row_pitch, unsigned int dst_slice_pitch) +{ + struct wined3d_texture_vk *src_texture_vk = wined3d_texture_vk(src_texture); + struct wined3d_context_vk *context_vk = wined3d_context_vk(context); + unsigned int src_level, src_width, src_height, src_depth; + struct wined3d_texture_sub_resource *sub_resource; + unsigned int src_row_pitch, src_slice_pitch; + struct wined3d_bo_address staging_bo_addr; + VkPipelineStageFlags bo_stage_flags = 0; + const struct wined3d_vk_info *vk_info; + VkCommandBuffer vk_command_buffer; + VkImageSubresourceRange vk_range; + VkBufferMemoryBarrier vk_barrier; + struct wined3d_bo_vk staging_bo; + struct wined3d_bo_vk *dst_bo; + VkBufferImageCopy region; + size_t dst_offset = 0; + void *map_ptr; + + TRACE("context %p, vk_aspect %#x, src_texture %p, src_sub_resource_idx %u, src_box %s, dst_bo_addr %s, " + "plane_format %s, dst_x %u, dst_y %u, dst_z %u, dst_row_pitch %u, dst_slice_pitch %u.\n", + context, vk_aspect, src_texture, src_sub_resource_idx, + debug_box(src_box), debug_bo_address(dst_bo_addr), debug_d3dformat(plane_format->id), + dst_x, dst_y, dst_z, dst_row_pitch, dst_slice_pitch); + + src_level = src_sub_resource_idx % src_texture->level_count; + wined3d_texture_get_pitch(src_texture, src_level, &src_row_pitch, &src_slice_pitch); + if (src_texture->resource.type == WINED3D_RTYPE_TEXTURE_1D) + src_row_pitch = dst_row_pitch = 0; + if (src_texture->resource.type != WINED3D_RTYPE_TEXTURE_3D) + src_slice_pitch = dst_slice_pitch = 0; + + sub_resource = &src_texture_vk->t.sub_resources[src_sub_resource_idx]; + vk_info = context_vk->vk_info; + + src_width = src_box->right - src_box->left; + src_height = src_box->bottom - src_box->top; + src_depth = src_box->back - src_box->front; + + if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk))) + { + ERR("Failed to get command buffer.\n"); + return; + } + + /* We need to be outside of a render pass for vkCmdPipelineBarrier() and vkCmdCopyImageToBuffer() calls below. */ + wined3d_context_vk_end_current_render_pass(context_vk); + + if (!dst_bo_addr->buffer_object) + { + if (!wined3d_context_vk_create_bo(context_vk, sub_resource->size, + VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &staging_bo)) + { + ERR("Failed to create staging bo.\n"); + return; + } + + dst_bo = &staging_bo; + + region.bufferRowLength = (src_row_pitch / plane_format->block_byte_count) * plane_format->block_width; + if (src_row_pitch) + region.bufferImageHeight = (src_slice_pitch / src_row_pitch) * plane_format->block_height; + else + region.bufferImageHeight = 1; + + if (src_row_pitch % plane_format->byte_count) + { + FIXME("Row pitch %u is not a multiple of byte count %u.\n", src_row_pitch, plane_format->byte_count); + return; + } + if (src_row_pitch && src_slice_pitch % src_row_pitch) + { + FIXME("Slice pitch %u is not a multiple of row pitch %u.\n", src_slice_pitch, src_row_pitch); + return; + } + } + else + { + dst_bo = wined3d_bo_vk(dst_bo_addr->buffer_object); + + region.bufferRowLength = (dst_row_pitch / plane_format->block_byte_count) * plane_format->block_width; + if (dst_row_pitch) + region.bufferImageHeight = (dst_slice_pitch / dst_row_pitch) * plane_format->block_height; + else + region.bufferImageHeight = 1; + + if (dst_row_pitch % plane_format->byte_count) + { + FIXME("Row pitch %u is not a multiple of byte count %u.\n", dst_row_pitch, plane_format->byte_count); + return; + } + if (dst_row_pitch && dst_slice_pitch % dst_row_pitch) + { + FIXME("Slice pitch %u is not a multiple of row pitch %u.\n", dst_slice_pitch, dst_row_pitch); + return; + } + + vk_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + vk_barrier.pNext = NULL; + vk_barrier.srcAccessMask = vk_access_mask_from_buffer_usage(dst_bo->usage); + vk_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + vk_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + vk_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + vk_barrier.buffer = dst_bo->vk_buffer; + vk_barrier.offset = dst_bo->b.buffer_offset + (size_t)dst_bo_addr->addr; + vk_barrier.size = sub_resource->size; + + bo_stage_flags = vk_pipeline_stage_mask_from_buffer_usage(dst_bo->usage); + dst_offset = (size_t)dst_bo_addr->addr; + + VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, bo_stage_flags, + VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 1, &vk_barrier, 0, NULL)); + } + + vk_range.aspectMask = vk_aspect; + vk_range.baseMipLevel = src_level; + vk_range.levelCount = 1; + vk_range.baseArrayLayer = src_sub_resource_idx / src_texture_vk->t.level_count; + vk_range.layerCount = 1; + + wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + vk_access_mask_from_bind_flags(src_texture_vk->t.resource.bind_flags), + VK_ACCESS_TRANSFER_READ_BIT, + src_texture_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + src_texture_vk->image.vk_image, &vk_range); + + region.bufferOffset = dst_bo->b.buffer_offset + dst_offset; + region.imageSubresource.aspectMask = vk_range.aspectMask; + region.imageSubresource.mipLevel = vk_range.baseMipLevel; + region.imageSubresource.baseArrayLayer = vk_range.baseArrayLayer; + region.imageSubresource.layerCount = vk_range.layerCount; + region.imageOffset.x = 0; + region.imageOffset.y = 0; + region.imageOffset.z = 0; + region.imageExtent.width = src_width; + region.imageExtent.height = src_height; + region.imageExtent.depth = src_depth; + + VK_CALL(vkCmdCopyImageToBuffer(vk_command_buffer, src_texture_vk->image.vk_image, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_bo->vk_buffer, 1, ®ion)); + + wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_ACCESS_TRANSFER_READ_BIT, + vk_access_mask_from_bind_flags(src_texture_vk->t.resource.bind_flags), + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, src_texture_vk->layout, + src_texture_vk->image.vk_image, &vk_range); + + wined3d_context_vk_reference_texture(context_vk, src_texture_vk); + wined3d_context_vk_reference_bo(context_vk, dst_bo); + + if (dst_bo == &staging_bo) + { + wined3d_context_vk_submit_command_buffer(context_vk, 0, NULL, NULL, 0, NULL); + wined3d_context_vk_wait_command_buffer(context_vk, src_texture_vk->image.command_buffer_id); + + staging_bo_addr.buffer_object = &staging_bo.b; + staging_bo_addr.addr = NULL; + if (!(map_ptr = wined3d_context_map_bo_address(context, &staging_bo_addr, + sub_resource->size, WINED3D_MAP_READ))) + { + ERR("Failed to map staging bo.\n"); + wined3d_context_vk_destroy_bo(context_vk, &staging_bo); + return; + } + + wined3d_format_copy_data(plane_format, map_ptr, src_row_pitch, src_slice_pitch, + dst_bo_addr->addr, dst_row_pitch, dst_slice_pitch, src_box->right - src_box->left, + src_box->bottom - src_box->top, src_box->back - src_box->front); + + wined3d_context_unmap_bo_address(context, &staging_bo_addr, 0, NULL); + wined3d_context_vk_destroy_bo(context_vk, &staging_bo); + } + else + { + vk_barrier.dstAccessMask = vk_barrier.srcAccessMask; + vk_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + + if (dst_bo->host_synced) + { + vk_barrier.dstAccessMask |= VK_ACCESS_HOST_READ_BIT; + bo_stage_flags |= VK_PIPELINE_STAGE_HOST_BIT; + } + + VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, + bo_stage_flags, 0, 0, NULL, 1, &vk_barrier, 0, NULL)); + /* Start the download so we don't stall waiting for the result. */ + wined3d_context_vk_submit_command_buffer(context_vk, 0, NULL, NULL, 0, NULL); + } +} + +static void wined3d_texture_vk_download_data(struct wined3d_context *context, + struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, unsigned int src_location, + const struct wined3d_box *src_box, const struct wined3d_bo_address *dst_bo_addr, + const struct wined3d_format *dst_format, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, + unsigned int dst_row_pitch, unsigned int dst_slice_pitch) +{ + unsigned int src_level, src_width, src_height, src_depth; + VkImageAspectFlags aspect_mask; + + TRACE("context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_box %s, dst_bo_addr %s, " + "dst_format %s, dst_x %u, dst_y %u, dst_z %u, dst_row_pitch %u, dst_slice_pitch %u.\n", + context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location), + debug_box(src_box), debug_bo_address(dst_bo_addr), debug_d3dformat(dst_format->id), + dst_x, dst_y, dst_z, dst_row_pitch, dst_slice_pitch); + + if (src_location != WINED3D_LOCATION_TEXTURE_RGB) + { + FIXME("Unhandled location %s.\n", wined3d_debug_location(src_location)); + return; + } + + src_level = src_sub_resource_idx % src_texture->level_count; + src_width = wined3d_texture_get_level_width(src_texture, src_level); + src_height = wined3d_texture_get_level_height(src_texture, src_level); + src_depth = wined3d_texture_get_level_depth(src_texture, src_level); + if (src_box->left || src_box->top || src_box->right != src_width || src_box->bottom != src_height + || src_box->front || src_box->back != src_depth) + { + FIXME("Unhandled source box %s.\n", debug_box(src_box)); + return; + } + + src_level = src_sub_resource_idx % src_texture->level_count; + src_width = wined3d_texture_get_level_width(src_texture, src_level); + src_height = wined3d_texture_get_level_height(src_texture, src_level); + src_depth = wined3d_texture_get_level_depth(src_texture, src_level); + if (src_box->left || src_box->top || src_box->right != src_width || src_box->bottom != src_height + || src_box->front || src_box->back != src_depth) + { + FIXME("Unhandled source box %s.\n", debug_box(src_box)); + return; + } + + if (dst_format->id != src_texture->resource.format->id) + { + FIXME("Unhandled format conversion (%s -> %s).\n", + debug_d3dformat(src_texture->resource.format->id), + debug_d3dformat(dst_format->id)); + return; + } + + if (dst_x || dst_y || dst_z) + { + FIXME("Unhandled destination (%u, %u, %u).\n", dst_x, dst_y, dst_z); + return; + } + + if (wined3d_resource_get_sample_count(&src_texture->resource) > 1) + { + FIXME("Not supported for multisample textures.\n"); + return; + } + + aspect_mask = vk_aspect_mask_from_format(src_texture->resource.format); + if (wined3d_popcount(aspect_mask) > 1) + { + FIXME("Unhandled multi-aspect format %s.\n", debug_d3dformat(src_texture->resource.format->id)); + return; + } + + if (dst_format->attrs & WINED3D_FORMAT_ATTR_PLANAR) + { + const struct wined3d_format *plane_format; + struct wined3d_bo_address uv_bo_addr; + struct wined3d_box uv_box; + + plane_format = wined3d_get_format(context->device->adapter, dst_format->plane_formats[0], 0); + wined3d_texture_vk_download_plane(context, VK_IMAGE_ASPECT_PLANE_0_BIT, src_texture, src_sub_resource_idx, + src_box, dst_bo_addr, plane_format, dst_x, dst_y, dst_z, dst_row_pitch, dst_slice_pitch); + + uv_bo_addr = *dst_bo_addr; + uv_bo_addr.addr += dst_slice_pitch; + uv_box = *src_box; + uv_box.left /= dst_format->uv_width; + uv_box.right /= dst_format->uv_width; + uv_box.top /= dst_format->uv_height; + uv_box.bottom /= dst_format->uv_height; + dst_x /= dst_format->uv_width; + dst_y /= dst_format->uv_height; + dst_row_pitch = dst_row_pitch * 2 / dst_format->uv_width; + dst_slice_pitch = dst_slice_pitch * 2 / dst_format->uv_width / dst_format->uv_height; + + plane_format = wined3d_get_format(context->device->adapter, dst_format->plane_formats[1], 0); + wined3d_texture_vk_download_plane(context, VK_IMAGE_ASPECT_PLANE_1_BIT, src_texture, src_sub_resource_idx, + &uv_box, &uv_bo_addr, plane_format, dst_x, dst_y, dst_z, dst_row_pitch, dst_slice_pitch); + } + else + { + wined3d_texture_vk_download_plane(context, aspect_mask, src_texture, src_sub_resource_idx, + src_box, dst_bo_addr, dst_format, dst_x, dst_y, dst_z, dst_row_pitch, dst_slice_pitch); + } +} + +static bool wined3d_texture_vk_clear(struct wined3d_texture_vk *texture_vk, + unsigned int sub_resource_idx, struct wined3d_context *context) +{ + struct wined3d_texture_sub_resource *sub_resource = &texture_vk->t.sub_resources[sub_resource_idx]; + struct wined3d_context_vk *context_vk = wined3d_context_vk(context); + const struct wined3d_format *format = texture_vk->t.resource.format; + const struct wined3d_vk_info *vk_info = context_vk->vk_info; + VkClearDepthStencilValue depth_value; + VkCommandBuffer vk_command_buffer; + VkImageSubresourceRange vk_range; + VkClearColorValue colour_value; + VkImageAspectFlags aspect_mask; + VkImage vk_image; + + if (texture_vk->t.resource.format_attrs & WINED3D_FORMAT_ATTR_COMPRESSED) + { + struct wined3d_bo_address addr; + struct wined3d_color *c = &sub_resource->clear_value.colour; + + if (c->r || c->g || c-> b || c->a) + FIXME("Compressed resource %p is cleared to a non-zero color.\n", &texture_vk->t); + + if (!wined3d_texture_prepare_location(&texture_vk->t, sub_resource_idx, context, WINED3D_LOCATION_SYSMEM)) + return false; + wined3d_texture_get_bo_address(&texture_vk->t, sub_resource_idx, &addr, WINED3D_LOCATION_SYSMEM); + memset(addr.addr, 0, sub_resource->size); + wined3d_texture_validate_location(&texture_vk->t, sub_resource_idx, WINED3D_LOCATION_SYSMEM); + return true; + } + + vk_image = texture_vk->image.vk_image; + + if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk))) + { + ERR("Failed to get command buffer.\n"); + return false; + } + + aspect_mask = vk_aspect_mask_from_format(format); + + vk_range.aspectMask = aspect_mask; + vk_range.baseMipLevel = sub_resource_idx % texture_vk->t.level_count; + vk_range.levelCount = 1; + vk_range.baseArrayLayer = sub_resource_idx / texture_vk->t.level_count; + vk_range.layerCount = 1; + + wined3d_context_vk_end_current_render_pass(context_vk); + + wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + vk_access_mask_from_bind_flags(texture_vk->t.resource.bind_flags), VK_ACCESS_TRANSFER_WRITE_BIT, + texture_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, vk_image, &vk_range); + + if (format->depth_size || format->stencil_size) + { + depth_value.depth = sub_resource->clear_value.depth; + depth_value.stencil = sub_resource->clear_value.stencil; + VK_CALL(vkCmdClearDepthStencilImage(vk_command_buffer, vk_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &depth_value, 1, &vk_range)); + } + else + { + wined3d_format_colour_to_vk(format, &sub_resource->clear_value.colour, &colour_value); + VK_CALL(vkCmdClearColorImage(vk_command_buffer, vk_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &colour_value, 1, &vk_range)); + } + + wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, vk_access_mask_from_bind_flags(texture_vk->t.resource.bind_flags), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_vk->layout, vk_image, &vk_range); + wined3d_context_vk_reference_texture(context_vk, texture_vk); + + wined3d_texture_validate_location(&texture_vk->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB); + return true; +} + +static BOOL wined3d_texture_vk_load_texture(struct wined3d_texture_vk *texture_vk, + unsigned int sub_resource_idx, struct wined3d_context *context) +{ + struct wined3d_texture_sub_resource *sub_resource; + unsigned int level, row_pitch, slice_pitch; + struct wined3d_bo_address data; + struct wined3d_box src_box; + + sub_resource = &texture_vk->t.sub_resources[sub_resource_idx]; + + if (sub_resource->locations & WINED3D_LOCATION_CLEARED) + { + if (!wined3d_texture_vk_clear(texture_vk, sub_resource_idx, context)) + return FALSE; + + if (sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB) + return TRUE; + } + + if (!(sub_resource->locations & wined3d_texture_sysmem_locations)) + { + ERR("Unimplemented load from %s.\n", wined3d_debug_location(sub_resource->locations)); + return FALSE; + } + + level = sub_resource_idx % texture_vk->t.level_count; + wined3d_texture_get_memory(&texture_vk->t, sub_resource_idx, context, &data); + wined3d_texture_get_level_box(&texture_vk->t, level, &src_box); + wined3d_texture_get_pitch(&texture_vk->t, level, &row_pitch, &slice_pitch); + wined3d_texture_vk_upload_data(context, wined3d_const_bo_address(&data), texture_vk->t.resource.format, + &src_box, row_pitch, slice_pitch, &texture_vk->t, sub_resource_idx, + WINED3D_LOCATION_TEXTURE_RGB, 0, 0, 0); + + return TRUE; +} + +static BOOL wined3d_texture_vk_load_sysmem(struct wined3d_texture_vk *texture_vk, + unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location) +{ + struct wined3d_texture_sub_resource *sub_resource; + unsigned int level, row_pitch, slice_pitch; + struct wined3d_bo_address data; + struct wined3d_box src_box; + + sub_resource = &texture_vk->t.sub_resources[sub_resource_idx]; + if (!(sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB)) + { + ERR("Unimplemented load from %s.\n", wined3d_debug_location(sub_resource->locations)); + return FALSE; + } + + level = sub_resource_idx % texture_vk->t.level_count; + wined3d_texture_get_bo_address(&texture_vk->t, sub_resource_idx, &data, location); + wined3d_texture_get_level_box(&texture_vk->t, level, &src_box); + wined3d_texture_get_pitch(&texture_vk->t, level, &row_pitch, &slice_pitch); + wined3d_texture_vk_download_data(context, &texture_vk->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, + &src_box, &data, texture_vk->t.resource.format, 0, 0, 0, row_pitch, slice_pitch); + + return TRUE; +} + +BOOL wined3d_texture_vk_prepare_texture(struct wined3d_texture_vk *texture_vk, + struct wined3d_context_vk *context_vk) +{ + const struct wined3d_format_vk *format_vk; + struct wined3d_resource *resource; + VkCommandBuffer vk_command_buffer; + VkImageSubresourceRange vk_range; + VkImageUsageFlags vk_usage; + VkImageType vk_image_type; + unsigned int flags = 0; + + if (texture_vk->t.flags & WINED3D_TEXTURE_RGB_ALLOCATED) + return TRUE; + + if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk))) + { + ERR("Failed to get command buffer.\n"); + return FALSE; + } + + resource = &texture_vk->t.resource; + format_vk = wined3d_format_vk(resource->format); + + if (wined3d_format_is_typeless(&format_vk->f) || texture_vk->t.swapchain + || (texture_vk->t.resource.bind_flags & WINED3D_BIND_UNORDERED_ACCESS) + || (format_vk->f.attrs & WINED3D_FORMAT_ATTR_PLANAR)) + { + /* For UAVs, we need this in case a clear necessitates creation of a new view + * with a different format. */ + flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + } + + switch (resource->type) + { + case WINED3D_RTYPE_TEXTURE_1D: + vk_image_type = VK_IMAGE_TYPE_1D; + break; + case WINED3D_RTYPE_TEXTURE_2D: + vk_image_type = VK_IMAGE_TYPE_2D; + if (texture_vk->t.layer_count >= 6 && resource->width == resource->height) + flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + break; + case WINED3D_RTYPE_TEXTURE_3D: + vk_image_type = VK_IMAGE_TYPE_3D; + if (resource->bind_flags & (WINED3D_BIND_RENDER_TARGET | WINED3D_BIND_UNORDERED_ACCESS)) + flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; + break; + default: + ERR("Invalid resource type %s.\n", debug_d3dresourcetype(resource->type)); + vk_image_type = VK_IMAGE_TYPE_2D; + break; + } + + vk_usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + if (resource->bind_flags & WINED3D_BIND_SHADER_RESOURCE) + vk_usage |= VK_IMAGE_USAGE_SAMPLED_BIT; + if (resource->bind_flags & WINED3D_BIND_RENDER_TARGET) + vk_usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + if (resource->bind_flags & WINED3D_BIND_DEPTH_STENCIL) + vk_usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + if (resource->bind_flags & WINED3D_BIND_UNORDERED_ACCESS) + vk_usage |= VK_IMAGE_USAGE_STORAGE_BIT; + + if (resource->bind_flags & WINED3D_BIND_UNORDERED_ACCESS) + texture_vk->layout = VK_IMAGE_LAYOUT_GENERAL; + else if (resource->bind_flags & WINED3D_BIND_RENDER_TARGET) + texture_vk->layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + else if (resource->bind_flags & WINED3D_BIND_DEPTH_STENCIL) + texture_vk->layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + else if (resource->bind_flags & WINED3D_BIND_SHADER_RESOURCE) + texture_vk->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + else if (resource->bind_flags & WINED3D_BIND_DECODER_OUTPUT) + texture_vk->layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + else + { + FIXME("unexpected bind flags %s, using VK_IMAGE_LAYOUT_GENERAL\n", wined3d_debug_bind_flags(resource->bind_flags)); + texture_vk->layout = VK_IMAGE_LAYOUT_GENERAL; + } + + if (!wined3d_context_vk_create_image(context_vk, vk_image_type, vk_usage, format_vk->vk_format, + resource->width, resource->height, resource->depth, max(1, wined3d_resource_get_sample_count(resource)), + texture_vk->t.level_count, texture_vk->t.layer_count, flags, NULL, &texture_vk->image)) + { + return FALSE; + } + + /* We can't use a zero src access mask without synchronization2. Set the last-used bind mask to something + * non-zero to avoid this. */ + texture_vk->bind_mask = resource->bind_flags; + + vk_range.aspectMask = vk_aspect_mask_from_format(&format_vk->f); + vk_range.baseMipLevel = 0; + vk_range.levelCount = VK_REMAINING_MIP_LEVELS; + vk_range.baseArrayLayer = 0; + vk_range.layerCount = VK_REMAINING_ARRAY_LAYERS; + + wined3d_context_vk_reference_texture(context_vk, texture_vk); + wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + 0, 0, + VK_IMAGE_LAYOUT_UNDEFINED, texture_vk->layout, + texture_vk->image.vk_image, &vk_range); + + texture_vk->t.flags |= WINED3D_TEXTURE_RGB_ALLOCATED; + + TRACE("Created image 0x%s, memory 0x%s for texture %p.\n", + wine_dbgstr_longlong(texture_vk->image.vk_image), wine_dbgstr_longlong(texture_vk->image.vk_memory), texture_vk); + + return TRUE; +} + +static BOOL wined3d_texture_vk_prepare_buffer_object(struct wined3d_texture_vk *texture_vk, + unsigned int sub_resource_idx, struct wined3d_context_vk *context_vk) +{ + struct wined3d_texture_sub_resource *sub_resource; + struct wined3d_bo_vk *bo; + + sub_resource = &texture_vk->t.sub_resources[sub_resource_idx]; + if (sub_resource->bo) + return TRUE; + + if (!(bo = malloc(sizeof(*bo)))) + return FALSE; + + if (!wined3d_context_vk_create_bo(context_vk, sub_resource->size, + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, bo)) + { + free(bo); + return FALSE; + } + + /* Texture buffer objects receive a barrier to HOST_READ in wined3d_texture_vk_download_data(), + * so they don't need it when they are mapped for reading. */ + bo->host_synced = true; + sub_resource->bo = &bo->b; + TRACE("Created buffer object %p for texture %p, sub-resource %u.\n", bo, texture_vk, sub_resource_idx); + return TRUE; +} + +static BOOL wined3d_texture_vk_prepare_location(struct wined3d_texture *texture, + unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location) +{ + switch (location) + { + case WINED3D_LOCATION_SYSMEM: + return texture->sub_resources[sub_resource_idx].user_memory ? TRUE + : wined3d_resource_prepare_sysmem(&texture->resource); + + case WINED3D_LOCATION_TEXTURE_RGB: + return wined3d_texture_vk_prepare_texture(wined3d_texture_vk(texture), wined3d_context_vk(context)); + + case WINED3D_LOCATION_BUFFER: + return wined3d_texture_vk_prepare_buffer_object(wined3d_texture_vk(texture), sub_resource_idx, + wined3d_context_vk(context)); + + default: + FIXME("Unhandled location %s.\n", wined3d_debug_location(location)); + return FALSE; + } +} + +static BOOL wined3d_texture_vk_load_location(struct wined3d_texture *texture, + unsigned int sub_resource_idx, struct wined3d_context *context, uint32_t location) +{ + if (!wined3d_texture_vk_prepare_location(texture, sub_resource_idx, context, location)) + return FALSE; + + switch (location) + { + case WINED3D_LOCATION_TEXTURE_RGB: + return wined3d_texture_vk_load_texture(wined3d_texture_vk(texture), sub_resource_idx, context); + + case WINED3D_LOCATION_SYSMEM: + case WINED3D_LOCATION_BUFFER: + return wined3d_texture_vk_load_sysmem(wined3d_texture_vk(texture), sub_resource_idx, context, location); + + default: + FIXME("Unimplemented location %s.\n", wined3d_debug_location(location)); + return FALSE; + } +} + +static void wined3d_texture_vk_unload_location(struct wined3d_texture *texture, + struct wined3d_context *context, unsigned int location) +{ + struct wined3d_texture_vk *texture_vk = wined3d_texture_vk(texture); + struct wined3d_context_vk *context_vk = wined3d_context_vk(context); + unsigned int i, sub_count; + + TRACE("texture %p, context %p, location %s.\n", texture, context, wined3d_debug_location(location)); + + switch (location) + { + case WINED3D_LOCATION_TEXTURE_RGB: + if (texture_vk->default_image_info.imageView) + { + wined3d_context_vk_destroy_vk_image_view(context_vk, + texture_vk->default_image_info.imageView, texture_vk->image.command_buffer_id); + texture_vk->default_image_info.imageView = VK_NULL_HANDLE; + } + + if (texture_vk->image.vk_image) + wined3d_context_vk_destroy_image(context_vk, &texture_vk->image); + break; + + case WINED3D_LOCATION_BUFFER: + sub_count = texture->level_count * texture->layer_count; + for (i = 0; i < sub_count; ++i) + { + struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[i]; + + if (sub_resource->bo) + { + struct wined3d_bo_vk *bo_vk = wined3d_bo_vk(sub_resource->bo); + + wined3d_context_vk_destroy_bo(context_vk, bo_vk); + free(bo_vk); + sub_resource->bo = NULL; + } + } + break; + + case WINED3D_LOCATION_TEXTURE_SRGB: + case WINED3D_LOCATION_RB_MULTISAMPLE: + case WINED3D_LOCATION_RB_RESOLVED: + break; + + default: + ERR("Unhandled location %s.\n", wined3d_debug_location(location)); + break; + } +} + +static const struct wined3d_texture_ops wined3d_texture_vk_ops = +{ + wined3d_texture_vk_prepare_location, + wined3d_texture_vk_load_location, + wined3d_texture_vk_unload_location, + wined3d_texture_vk_upload_data, + wined3d_texture_vk_download_data, +}; + +HRESULT wined3d_texture_vk_init(struct wined3d_texture_vk *texture_vk, struct wined3d_device *device, + const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count, + uint32_t flags, void *parent, const struct wined3d_parent_ops *parent_ops) +{ + TRACE("texture_vk %p, device %p, desc %p, layer_count %u, " + "level_count %u, flags %#x, parent %p, parent_ops %p.\n", + texture_vk, device, desc, layer_count, + level_count, flags, parent, parent_ops); + + return wined3d_texture_init(&texture_vk->t, desc, layer_count, level_count, + flags, device, parent, parent_ops, &texture_vk[1], &wined3d_texture_vk_ops); +} + +enum VkImageLayout wined3d_layout_from_bind_mask(const struct wined3d_texture_vk *texture_vk, const uint32_t bind_mask) +{ + assert(wined3d_popcount(bind_mask) == 1); + + /* We want to avoid switching between LAYOUT_GENERAL and other layouts. In Radeon GPUs (and presumably + * others), this will trigger decompressing and recompressing the texture. We also hardcode the layout + * into views when they are created. */ + if (texture_vk->layout == VK_IMAGE_LAYOUT_GENERAL) + return VK_IMAGE_LAYOUT_GENERAL; + + switch (bind_mask) + { + case WINED3D_BIND_RENDER_TARGET: + return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + case WINED3D_BIND_DEPTH_STENCIL: + return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + case WINED3D_BIND_SHADER_RESOURCE: + return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + default: + ERR("Unexpected bind mask %s.\n", wined3d_debug_bind_flags(bind_mask)); + return VK_IMAGE_LAYOUT_GENERAL; + } +} + +void wined3d_texture_vk_barrier(struct wined3d_texture_vk *texture_vk, + struct wined3d_context_vk *context_vk, uint32_t bind_mask) +{ + enum VkImageLayout new_layout; + uint32_t src_bind_mask = 0; + + TRACE("texture_vk %p, context_vk %p, bind_mask %s.\n", + texture_vk, context_vk, wined3d_debug_bind_flags(bind_mask)); + + new_layout = wined3d_layout_from_bind_mask(texture_vk, bind_mask); + + /* A layout transition is potentially a read-write operation, so even if we + * prepare the texture to e.g. read only shader resource mode, we have to wait + * for past operations to finish. */ + if (bind_mask & ~WINED3D_READ_ONLY_BIND_MASK || new_layout != texture_vk->layout) + { + src_bind_mask = texture_vk->bind_mask & WINED3D_READ_ONLY_BIND_MASK; + if (!src_bind_mask) + src_bind_mask = texture_vk->bind_mask; + + texture_vk->bind_mask = bind_mask; + } + else if ((texture_vk->bind_mask & bind_mask) != bind_mask) + { + src_bind_mask = texture_vk->bind_mask & ~WINED3D_READ_ONLY_BIND_MASK; + texture_vk->bind_mask |= bind_mask; + } + + if (src_bind_mask) + { + VkImageSubresourceRange vk_range; + + TRACE(" %s(%x) -> %s(%x).\n", + wined3d_debug_bind_flags(src_bind_mask), texture_vk->layout, + wined3d_debug_bind_flags(bind_mask), new_layout); + + vk_range.aspectMask = vk_aspect_mask_from_format(texture_vk->t.resource.format); + vk_range.baseMipLevel = 0; + vk_range.levelCount = VK_REMAINING_MIP_LEVELS; + vk_range.baseArrayLayer = 0; + vk_range.layerCount = VK_REMAINING_ARRAY_LAYERS; + + wined3d_context_vk_image_barrier(context_vk, wined3d_context_vk_get_command_buffer(context_vk), + vk_pipeline_stage_mask_from_bind_flags(src_bind_mask), + vk_pipeline_stage_mask_from_bind_flags(bind_mask), + vk_access_mask_from_bind_flags(src_bind_mask), vk_access_mask_from_bind_flags(bind_mask), + texture_vk->layout, new_layout, texture_vk->image.vk_image, &vk_range); + + texture_vk->layout = new_layout; + } +} + +/* This is called when a texture is used as render target and shader resource + * or depth stencil and shader resource at the same time. This can either be + * read-only simultaneos use as depth stencil, but also for rendering to one + * subresource while reading from another. Without tracking of barriers and + * layouts per subresource VK_IMAGE_LAYOUT_GENERAL is the only thing we can do. */ +void wined3d_texture_vk_make_generic(struct wined3d_texture_vk *texture_vk, + struct wined3d_context_vk *context_vk) +{ + VkImageSubresourceRange vk_range; + + if (texture_vk->layout == VK_IMAGE_LAYOUT_GENERAL) + return; + + vk_range.aspectMask = vk_aspect_mask_from_format(texture_vk->t.resource.format); + vk_range.baseMipLevel = 0; + vk_range.levelCount = VK_REMAINING_MIP_LEVELS; + vk_range.baseArrayLayer = 0; + vk_range.layerCount = VK_REMAINING_ARRAY_LAYERS; + + wined3d_context_vk_image_barrier(context_vk, wined3d_context_vk_get_command_buffer(context_vk), + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + 0, 0, + texture_vk->layout, VK_IMAGE_LAYOUT_GENERAL, texture_vk->image.vk_image, &vk_range); + + texture_vk->layout = VK_IMAGE_LAYOUT_GENERAL; + texture_vk->default_image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; +} + +static void vk_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context) +{ + struct wined3d_blitter *next; + + TRACE("blitter %p, context %p.\n", blitter, context); + + if ((next = blitter->next)) + next->ops->blitter_destroy(next, context); + + free(blitter); +} + +static void vk_blitter_clear_rendertargets(struct wined3d_context_vk *context_vk, unsigned int rt_count, + const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects, const RECT *draw_rect, + uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int stencil) +{ + unsigned int i, attachment_count, immediate_rt_count = 0, delay_count = 0; + VkClearValue clear_values[WINED3D_MAX_RENDER_TARGETS + 1]; + VkImageView views[WINED3D_MAX_RENDER_TARGETS + 1]; + struct wined3d_rendertarget_view_vk *rtv_vk; + struct wined3d_rendertarget_view *view; + const struct wined3d_vk_info *vk_info; + struct wined3d_fb_state immediate_fb; + struct wined3d_device_vk *device_vk; + VkCommandBuffer vk_command_buffer; + VkRenderPassBeginInfo begin_desc; + VkFramebufferCreateInfo fb_desc; + VkFramebuffer vk_framebuffer; + VkRenderPass vk_render_pass; + bool depth_stencil = false; + unsigned int layer_count; + VkClearColorValue *c; + VkResult vr; + RECT r; + + TRACE("context_vk %p, rt_count %u, fb %p, rect_count %u, clear_rects %p, " + "draw_rect %s, flags %#x, colour %s, depth %.8e, stencil %#x.\n", + context_vk, rt_count, fb, rect_count, clear_rects, + wine_dbgstr_rect(draw_rect), flags, debug_color(colour), depth, stencil); + + device_vk = wined3d_device_vk(context_vk->c.device); + vk_info = context_vk->vk_info; + + if (!(flags & WINED3DCLEAR_TARGET)) + rt_count = 0; + + for (i = 0, attachment_count = 0, layer_count = 1; i < rt_count; ++i) + { + if (!(view = fb->render_targets[i])) + continue; + + /* Don't delay typeless clears because the data written into the resource depends on the + * view format. Except all-zero clears, those should result in zeros in either case. + * + * We could store the clear format along with the clear value, but then we'd have to + * create a matching RTV at draw time, which would need its own render pass, thus mooting + * the point of the delayed clear. (Unless we are lucky enough that the application + * draws with the same RTV as it clears.) */ + if (is_full_clear(view, draw_rect, clear_rects) + && (!wined3d_format_is_typeless(view->resource->format) || (!colour->r && !colour->g + && !colour->b && !colour->a))) + { + struct wined3d_texture *texture = texture_from_resource(view->resource); + wined3d_rendertarget_view_validate_location(view, WINED3D_LOCATION_CLEARED); + wined3d_rendertarget_view_invalidate_location(view, ~WINED3D_LOCATION_CLEARED); + texture->sub_resources[view->sub_resource_idx].clear_value.colour = *colour; + delay_count++; + continue; + } + else + { + wined3d_rendertarget_view_load_location(view, &context_vk->c, view->resource->draw_binding); + } + wined3d_rendertarget_view_validate_location(view, view->resource->draw_binding); + wined3d_rendertarget_view_invalidate_location(view, ~view->resource->draw_binding); + + immediate_fb.render_targets[immediate_rt_count++] = view; + rtv_vk = wined3d_rendertarget_view_vk(view); + views[attachment_count] = wined3d_rendertarget_view_vk_get_image_view(rtv_vk, context_vk); + wined3d_rendertarget_view_vk_barrier(rtv_vk, context_vk, WINED3D_BIND_RENDER_TARGET); + + c = &clear_values[attachment_count].color; + wined3d_format_colour_to_vk(view->format, colour, c); + + if (view->layer_count > layer_count) + layer_count = view->layer_count; + + ++attachment_count; + } + + if (!attachment_count) + flags &= ~WINED3DCLEAR_TARGET; + + if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && (view = fb->depth_stencil)) + { + DWORD full_flags = 0; + + /* Vulkan can clear only depth or stencil, but at the moment we can't put the depth and + * stencil parts in separate locations. It isn't easy to do either, as such a half-cleared + * texture would need to be handled not just as a DS target but also when used as a shader + * resource or accessed on sysmem. */ + if (view->format->depth_size) + full_flags = WINED3DCLEAR_ZBUFFER; + if (view->format->stencil_size) + full_flags |= WINED3DCLEAR_STENCIL; + + if (!is_full_clear(view, draw_rect, clear_rects) || (flags & full_flags) != full_flags + || (wined3d_format_is_typeless(view->resource->format) && (depth || stencil))) + { + wined3d_rendertarget_view_load_location(view, &context_vk->c, view->resource->draw_binding); + wined3d_rendertarget_view_validate_location(view, view->resource->draw_binding); + wined3d_rendertarget_view_invalidate_location(view, ~view->resource->draw_binding); + + immediate_fb.depth_stencil = view; + rtv_vk = wined3d_rendertarget_view_vk(view); + views[attachment_count] = wined3d_rendertarget_view_vk_get_image_view(rtv_vk, context_vk); + wined3d_rendertarget_view_vk_barrier(rtv_vk, context_vk, WINED3D_BIND_DEPTH_STENCIL); + + clear_values[attachment_count].depthStencil.depth = depth; + clear_values[attachment_count].depthStencil.stencil = stencil; + + if (view->layer_count > layer_count) + layer_count = view->layer_count; + + depth_stencil = true; + ++attachment_count; + } + else + { + struct wined3d_texture *texture = texture_from_resource(view->resource); + texture->sub_resources[view->sub_resource_idx].clear_value.depth = depth; + texture->sub_resources[view->sub_resource_idx].clear_value.stencil = stencil; + wined3d_rendertarget_view_validate_location(view, WINED3D_LOCATION_CLEARED); + wined3d_rendertarget_view_invalidate_location(view, ~WINED3D_LOCATION_CLEARED); + flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL); + delay_count++; + } + } + + if (!attachment_count) + { + TRACE("The clear has been delayed until draw time.\n"); + return; + } + + TRACE("Doing an immediate clear of %u attachments.\n", attachment_count); + if (delay_count) + TRACE_(d3d_perf)("Partial clear: %u immediate, %u delayed.\n", attachment_count, delay_count); + + if (!(vk_render_pass = wined3d_context_vk_get_render_pass(context_vk, &immediate_fb, + immediate_rt_count, flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL), flags))) + { + ERR("Failed to get render pass.\n"); + return; + } + + if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk))) + { + ERR("Failed to get command buffer.\n"); + return; + } + + fb_desc.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + fb_desc.pNext = NULL; + fb_desc.flags = 0; + fb_desc.renderPass = vk_render_pass; + fb_desc.attachmentCount = attachment_count; + fb_desc.pAttachments = views; + fb_desc.width = draw_rect->right - draw_rect->left; + fb_desc.height = draw_rect->bottom - draw_rect->top; + fb_desc.layers = layer_count; + if ((vr = VK_CALL(vkCreateFramebuffer(device_vk->vk_device, &fb_desc, NULL, &vk_framebuffer))) < 0) + { + ERR("Failed to create Vulkan framebuffer, vr %s.\n", wined3d_debug_vkresult(vr)); + return; + } + + begin_desc.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + begin_desc.pNext = NULL; + begin_desc.renderPass = vk_render_pass; + begin_desc.framebuffer = vk_framebuffer; + begin_desc.clearValueCount = attachment_count; + begin_desc.pClearValues = clear_values; + + wined3d_context_vk_end_current_render_pass(context_vk); + + for (i = 0; i < rect_count; ++i) + { + r.left = max(clear_rects[i].left, draw_rect->left); + r.top = max(clear_rects[i].top, draw_rect->top); + r.right = min(clear_rects[i].right, draw_rect->right); + r.bottom = min(clear_rects[i].bottom, draw_rect->bottom); + + if (r.left >= r.right || r.top >= r.bottom) + continue; + + begin_desc.renderArea.offset.x = r.left; + begin_desc.renderArea.offset.y = r.top; + begin_desc.renderArea.extent.width = r.right - r.left; + begin_desc.renderArea.extent.height = r.bottom - r.top; + VK_CALL(vkCmdBeginRenderPass(vk_command_buffer, &begin_desc, VK_SUBPASS_CONTENTS_INLINE)); + VK_CALL(vkCmdEndRenderPass(vk_command_buffer)); + } + + wined3d_context_vk_destroy_vk_framebuffer(context_vk, vk_framebuffer, context_vk->current_command_buffer.id); + + for (i = 0; i < immediate_rt_count; ++i) + wined3d_context_vk_reference_rendertarget_view(context_vk, + wined3d_rendertarget_view_vk(immediate_fb.render_targets[i])); + + if (depth_stencil) + wined3d_context_vk_reference_rendertarget_view(context_vk, + wined3d_rendertarget_view_vk(immediate_fb.depth_stencil)); +} + +static void vk_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device, + unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects, + const RECT *draw_rect, uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int stencil) +{ + struct wined3d_device_vk *device_vk = wined3d_device_vk(device); + struct wined3d_rendertarget_view *view, *previous = NULL; + struct wined3d_context_vk *context_vk; + bool have_identical_size = true; + struct wined3d_fb_state tmp_fb; + unsigned int next_rt_count = 0; + struct wined3d_blitter *next; + uint32_t next_flags = 0; + unsigned int i; + + TRACE("blitter %p, device %p, rt_count %u, fb %p, rect_count %u, clear_rects %p, " + "draw_rect %s, flags %#x, colour %s, depth %.8e, stencil %#x.\n", + blitter, device, rt_count, fb, rect_count, clear_rects, + wine_dbgstr_rect(draw_rect), flags, debug_color(colour), depth, stencil); + + if (!rect_count) + { + rect_count = 1; + clear_rects = draw_rect; + } + + if (flags & WINED3DCLEAR_TARGET) + { + for (i = 0; i < rt_count; ++i) + { + if (!(view = fb->render_targets[i])) + continue; + + if (blitter_use_cpu_clear(view)) + { + next_flags |= WINED3DCLEAR_TARGET; + flags &= ~WINED3DCLEAR_TARGET; + next_rt_count = rt_count; + rt_count = 0; + break; + } + } + } + + if ((flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) && (view = fb->depth_stencil) + && (!view->format->depth_size || (flags & WINED3DCLEAR_ZBUFFER)) + && (!view->format->stencil_size || (flags & WINED3DCLEAR_STENCIL)) + && blitter_use_cpu_clear(view)) + { + next_flags |= flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL); + flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL); + } + + if (flags) + { + context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0)); + + for (i = 0; i < rt_count; ++i) + { + if (!(view = fb->render_targets[i])) + continue; + + if (previous && (previous->width != view->width || previous->height != view->height)) + have_identical_size = false; + previous = view; + } + if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) + { + view = fb->depth_stencil; + + if (previous && (previous->width != view->width || previous->height != view->height)) + have_identical_size = false; + } + + if (have_identical_size) + { + vk_blitter_clear_rendertargets(context_vk, rt_count, fb, rect_count, + clear_rects, draw_rect, flags, colour, depth, stencil); + } + else + { + for (i = 0; i < rt_count; ++i) + { + if (!(view = fb->render_targets[i])) + continue; + + tmp_fb.render_targets[0] = view; + tmp_fb.depth_stencil = NULL; + vk_blitter_clear_rendertargets(context_vk, 1, &tmp_fb, rect_count, + clear_rects, draw_rect, WINED3DCLEAR_TARGET, colour, depth, stencil); + } + if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) + { + tmp_fb.render_targets[0] = NULL; + tmp_fb.depth_stencil = fb->depth_stencil; + vk_blitter_clear_rendertargets(context_vk, 0, &tmp_fb, rect_count, + clear_rects, draw_rect, flags & ~WINED3DCLEAR_TARGET, colour, depth, stencil); + } + } + + context_release(&context_vk->c); + } + + if (!next_flags) + return; + + if (!(next = blitter->next)) + { + ERR("No blitter to handle clear.\n"); + return; + } + + TRACE("Forwarding to blitter %p.\n", next); + next->ops->blitter_clear(next, device, next_rt_count, fb, rect_count, + clear_rects, draw_rect, next_flags, colour, depth, stencil); +} + +static bool vk_blitter_blit_supported(enum wined3d_blit_op op, const struct wined3d_context *context, + const struct wined3d_resource *src_resource, const RECT *src_rect, + const struct wined3d_resource *dst_resource, const RECT *dst_rect, const struct wined3d_format *resolve_format) +{ + const struct wined3d_format *src_format = src_resource->format; + const struct wined3d_format *dst_format = dst_resource->format; + + if (!(dst_resource->access & WINED3D_RESOURCE_ACCESS_GPU)) + { + TRACE("Destination resource does not have GPU access.\n"); + return false; + } + + if (!(src_resource->access & WINED3D_RESOURCE_ACCESS_GPU)) + { + TRACE("Source resource does not have GPU access.\n"); + return false; + } + + if (dst_format->id != src_format->id) + { + if (!is_identity_fixup(dst_format->color_fixup)) + { + TRACE("Destination fixups are not supported.\n"); + return false; + } + + if (!is_identity_fixup(src_format->color_fixup)) + { + TRACE("Source fixups are not supported.\n"); + return false; + } + + if (op != WINED3D_BLIT_OP_RAW_BLIT + && wined3d_format_vk(src_format)->vk_format != wined3d_format_vk(dst_format)->vk_format + && ((!wined3d_format_is_typeless(src_format) && !wined3d_format_is_typeless(dst_format)) + || !resolve_format)) + { + TRACE("Format conversion not supported.\n"); + return false; + } + + if ((src_format->attrs | dst_format->attrs) & WINED3D_FORMAT_ATTR_PLANAR) + { + TRACE("Planar format conversion is not supported.\n"); + return false; + } + } + + if (wined3d_resource_get_sample_count(dst_resource) > 1) + { + TRACE("Multi-sample destination resource not supported.\n"); + return false; + } + + if (op == WINED3D_BLIT_OP_RAW_BLIT) + return true; + + if (op != WINED3D_BLIT_OP_COLOR_BLIT) + { + TRACE("Unsupported blit operation %#x.\n", op); + return false; + } + + if ((src_rect->right - src_rect->left != dst_rect->right - dst_rect->left) + || (src_rect->bottom - src_rect->top != dst_rect->bottom - dst_rect->top)) + { + TRACE("Scaling not supported.\n"); + return false; + } + + return true; +} + +static DWORD vk_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op, + struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, + DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture, + unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect, + const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter, + const struct wined3d_format *resolve_format) +{ + struct wined3d_texture_vk *src_texture_vk = wined3d_texture_vk(src_texture); + struct wined3d_texture_vk *dst_texture_vk = wined3d_texture_vk(dst_texture); + struct wined3d_context_vk *context_vk = wined3d_context_vk(context); + const struct wined3d_vk_info *vk_info = context_vk->vk_info; + VkImageSubresourceRange vk_src_range, vk_dst_range; + VkImageLayout src_layout, dst_layout; + VkCommandBuffer vk_command_buffer; + struct wined3d_blitter *next; + unsigned src_sample_count; + bool resolve = false; + + TRACE("blitter %p, op %#x, context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, " + "src_rect %s, dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s, " + "colour_key %p, filter %s, resolve format %p.\n", + blitter, op, context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location), + wine_dbgstr_rect(src_rect), dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location), + wine_dbgstr_rect(dst_rect), colour_key, debug_d3dtexturefiltertype(filter), resolve_format); + + if (!vk_blitter_blit_supported(op, context, &src_texture->resource, src_rect, &dst_texture->resource, dst_rect, + resolve_format)) + goto next; + + src_sample_count = wined3d_resource_get_sample_count(&src_texture_vk->t.resource); + if (src_sample_count > 1) + resolve = true; + + vk_src_range.aspectMask = vk_aspect_mask_from_format(src_texture_vk->t.resource.format); + vk_src_range.baseMipLevel = src_sub_resource_idx % src_texture->level_count; + vk_src_range.levelCount = 1; + vk_src_range.baseArrayLayer = src_sub_resource_idx / src_texture->level_count; + vk_src_range.layerCount = 1; + + vk_dst_range.aspectMask = vk_aspect_mask_from_format(dst_texture_vk->t.resource.format); + vk_dst_range.baseMipLevel = dst_sub_resource_idx % dst_texture->level_count; + vk_dst_range.levelCount = 1; + vk_dst_range.baseArrayLayer = dst_sub_resource_idx / dst_texture->level_count; + vk_dst_range.layerCount = 1; + + if (!wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB)) + ERR("Failed to load the source sub-resource.\n"); + + if (wined3d_texture_is_full_rect(dst_texture, vk_dst_range.baseMipLevel, dst_rect)) + { + if (!wined3d_texture_prepare_location(dst_texture, + dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB)) + { + ERR("Failed to prepare the destination sub-resource.\n"); + goto next; + } + } + else + { + if (!wined3d_texture_load_location(dst_texture, + dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB)) + { + ERR("Failed to load the destination sub-resource.\n"); + goto next; + } + } + + if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk))) + { + ERR("Failed to get command buffer.\n"); + goto next; + } + + if (src_texture_vk->layout == VK_IMAGE_LAYOUT_GENERAL) + src_layout = VK_IMAGE_LAYOUT_GENERAL; + else + src_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + + if (dst_texture_vk->layout == VK_IMAGE_LAYOUT_GENERAL) + dst_layout = VK_IMAGE_LAYOUT_GENERAL; + else + dst_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + + wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + vk_access_mask_from_bind_flags(src_texture_vk->t.resource.bind_flags), + VK_ACCESS_TRANSFER_READ_BIT, src_texture_vk->layout, src_layout, + src_texture_vk->image.vk_image, &vk_src_range); + wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + vk_access_mask_from_bind_flags(dst_texture_vk->t.resource.bind_flags), + VK_ACCESS_TRANSFER_WRITE_BIT, dst_texture_vk->layout, dst_layout, + dst_texture_vk->image.vk_image, &vk_dst_range); + + if (resolve) + { + const struct wined3d_format_vk *src_format_vk = wined3d_format_vk(src_texture->resource.format); + const struct wined3d_format_vk *dst_format_vk = wined3d_format_vk(dst_texture->resource.format); + const unsigned int usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT + | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + VkImageLayout resolve_src_layout, resolve_dst_layout; + VkImage src_vk_image, dst_vk_image; + VkImageSubresourceRange vk_range; + VkImageResolve resolve_region; + VkImageType vk_image_type; + VkImageCopy copy_region; + VkFormat vk_format; + + if (resolve_format) + { + vk_format = wined3d_format_vk(resolve_format)->vk_format; + } + else if (!wined3d_format_is_typeless(src_texture->resource.format)) + { + vk_format = src_format_vk->vk_format; + } + else + { + vk_format = dst_format_vk->vk_format; + } + + switch (src_texture->resource.type) + { + case WINED3D_RTYPE_TEXTURE_1D: + vk_image_type = VK_IMAGE_TYPE_1D; + break; + case WINED3D_RTYPE_TEXTURE_2D: + vk_image_type = VK_IMAGE_TYPE_2D; + break; + case WINED3D_RTYPE_TEXTURE_3D: + vk_image_type = VK_IMAGE_TYPE_3D; + break; + default: + ERR("Unexpected resource type: %s\n", debug_d3dresourcetype(src_texture->resource.type)); + goto barrier_next; + } + + vk_range.baseMipLevel = 0; + vk_range.levelCount = 1; + vk_range.baseArrayLayer = 0; + vk_range.layerCount = 1; + + resolve_region.srcSubresource.aspectMask = vk_src_range.aspectMask; + resolve_region.dstSubresource.aspectMask = vk_dst_range.aspectMask; + resolve_region.extent.width = src_rect->right - src_rect->left; + resolve_region.extent.height = src_rect->bottom - src_rect->top; + resolve_region.extent.depth = 1; + + /* In case of typeless resolve the texture type may not match the resolve type. + * To handle that, allocate intermediate texture(s) to resolve from/to. + * A possible performance improvement would be to resolve using a shader instead. */ + if (src_format_vk->vk_format != vk_format) + { + struct wined3d_image_vk src_image; + + if (!wined3d_context_vk_create_image(context_vk, vk_image_type, usage, vk_format, + resolve_region.extent.width, resolve_region.extent.height, 1, + src_sample_count, 1, 1, 0, NULL, &src_image)) + goto barrier_next; + + wined3d_context_vk_reference_image(context_vk, &src_image); + src_vk_image = src_image.vk_image; + wined3d_context_vk_destroy_image(context_vk, &src_image); + + vk_range.aspectMask = vk_src_range.aspectMask; + + wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, src_vk_image, &vk_range); + + copy_region.srcSubresource.aspectMask = vk_src_range.aspectMask; + copy_region.srcSubresource.mipLevel = vk_src_range.baseMipLevel; + copy_region.srcSubresource.baseArrayLayer = vk_src_range.baseArrayLayer; + copy_region.srcSubresource.layerCount = 1; + copy_region.srcOffset.x = src_rect->left; + copy_region.srcOffset.y = src_rect->top; + copy_region.srcOffset.z = 0; + copy_region.dstSubresource.aspectMask = vk_src_range.aspectMask; + copy_region.dstSubresource.mipLevel = 0; + copy_region.dstSubresource.baseArrayLayer = 0; + copy_region.dstSubresource.layerCount = 1; + copy_region.dstOffset.x = 0; + copy_region.dstOffset.y = 0; + copy_region.dstOffset.z = 0; + copy_region.extent.width = resolve_region.extent.width; + copy_region.extent.height = resolve_region.extent.height; + copy_region.extent.depth = 1; + + VK_CALL(vkCmdCopyImage(vk_command_buffer, src_texture_vk->image.vk_image, + src_layout, src_vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, ©_region)); + + wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + src_vk_image, &vk_range); + resolve_src_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + + resolve_region.srcSubresource.mipLevel = 0; + resolve_region.srcSubresource.baseArrayLayer = 0; + resolve_region.srcSubresource.layerCount = 1; + resolve_region.srcOffset.x = 0; + resolve_region.srcOffset.y = 0; + resolve_region.srcOffset.z = 0; + } + else + { + src_vk_image = src_texture_vk->image.vk_image; + resolve_src_layout = src_layout; + + resolve_region.srcSubresource.mipLevel = vk_src_range.baseMipLevel; + resolve_region.srcSubresource.baseArrayLayer = vk_src_range.baseArrayLayer; + resolve_region.srcSubresource.layerCount = 1; + resolve_region.srcOffset.x = src_rect->left; + resolve_region.srcOffset.y = src_rect->top; + resolve_region.srcOffset.z = 0; + } + + if (dst_format_vk->vk_format != vk_format) + { + struct wined3d_image_vk dst_image; + + if (!wined3d_context_vk_create_image(context_vk, vk_image_type, usage, vk_format, + resolve_region.extent.width, resolve_region.extent.height, 1, + VK_SAMPLE_COUNT_1_BIT, 1, 1, 0, NULL, &dst_image)) + goto barrier_next; + + wined3d_context_vk_reference_image(context_vk, &dst_image); + dst_vk_image = dst_image.vk_image; + wined3d_context_vk_destroy_image(context_vk, &dst_image); + + vk_range.aspectMask = vk_dst_range.aspectMask; + wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_vk_image, &vk_range); + resolve_dst_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + + resolve_region.dstSubresource.mipLevel = 0; + resolve_region.dstSubresource.baseArrayLayer = 0; + resolve_region.dstSubresource.layerCount = 1; + resolve_region.dstOffset.x = 0; + resolve_region.dstOffset.y = 0; + resolve_region.dstOffset.z = 0; + } + else + { + dst_vk_image = dst_texture_vk->image.vk_image; + resolve_dst_layout = dst_layout; + + resolve_region.dstSubresource.mipLevel = vk_dst_range.baseMipLevel; + resolve_region.dstSubresource.baseArrayLayer = vk_dst_range.baseArrayLayer; + resolve_region.dstSubresource.layerCount = 1; + resolve_region.dstOffset.x = dst_rect->left; + resolve_region.dstOffset.y = dst_rect->top; + resolve_region.dstOffset.z = 0; + } + + VK_CALL(vkCmdResolveImage(vk_command_buffer, src_vk_image, resolve_src_layout, + dst_vk_image, resolve_dst_layout, 1, &resolve_region)); + + if (dst_vk_image != dst_texture_vk->image.vk_image) + { + wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, + resolve_dst_layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + dst_vk_image, &vk_range); + + copy_region.srcSubresource.aspectMask = vk_dst_range.aspectMask; + copy_region.srcSubresource.mipLevel = 0; + copy_region.srcSubresource.baseArrayLayer = 0; + copy_region.srcSubresource.layerCount = 1; + copy_region.srcOffset.x = 0; + copy_region.srcOffset.y = 0; + copy_region.srcOffset.z = 0; + copy_region.dstSubresource.aspectMask = vk_dst_range.aspectMask; + copy_region.dstSubresource.mipLevel = vk_dst_range.baseMipLevel; + copy_region.dstSubresource.baseArrayLayer = vk_dst_range.baseArrayLayer; + copy_region.dstSubresource.layerCount = 1; + copy_region.dstOffset.x = dst_rect->left; + copy_region.dstOffset.y = dst_rect->top; + copy_region.dstOffset.z = 0; + copy_region.extent.width = resolve_region.extent.width; + copy_region.extent.height = resolve_region.extent.height; + copy_region.extent.depth = 1; + + VK_CALL(vkCmdCopyImage(vk_command_buffer, dst_vk_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + dst_texture_vk->image.vk_image, dst_layout, 1, ©_region)); + } + } + else + { + const struct wined3d_format *src_format = src_texture_vk->t.resource.format; + VkImageCopy region; + + region.srcSubresource.aspectMask = vk_src_range.aspectMask; + region.srcSubresource.mipLevel = vk_src_range.baseMipLevel; + region.srcSubresource.baseArrayLayer = vk_src_range.baseArrayLayer; + region.srcSubresource.layerCount = vk_src_range.layerCount; + region.srcOffset.x = src_rect->left; + region.srcOffset.y = src_rect->top; + region.srcOffset.z = 0; + region.dstSubresource.aspectMask = vk_dst_range.aspectMask; + region.dstSubresource.mipLevel = vk_dst_range.baseMipLevel; + region.dstSubresource.baseArrayLayer = vk_dst_range.baseArrayLayer; + region.dstSubresource.layerCount = vk_dst_range.layerCount; + region.dstOffset.x = dst_rect->left; + region.dstOffset.y = dst_rect->top; + region.dstOffset.z = 0; + region.extent.width = src_rect->right - src_rect->left; + region.extent.height = src_rect->bottom - src_rect->top; + region.extent.depth = 1; + + if (src_format->attrs & WINED3D_FORMAT_ATTR_PLANAR) + { + region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT; + region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT; + VK_CALL(vkCmdCopyImage(vk_command_buffer, src_texture_vk->image.vk_image, src_layout, + dst_texture_vk->image.vk_image, dst_layout, 1, ®ion)); + region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT; + region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT; + region.srcOffset.x /= src_format->uv_width; + region.srcOffset.y /= src_format->uv_height; + region.dstOffset.x /= src_format->uv_width; + region.dstOffset.y /= src_format->uv_height; + region.extent.width /= src_format->uv_width; + region.extent.height /= src_format->uv_height; + VK_CALL(vkCmdCopyImage(vk_command_buffer, src_texture_vk->image.vk_image, src_layout, + dst_texture_vk->image.vk_image, dst_layout, 1, ®ion)); + } + else + { + VK_CALL(vkCmdCopyImage(vk_command_buffer, src_texture_vk->image.vk_image, src_layout, + dst_texture_vk->image.vk_image, dst_layout, 1, ®ion)); + } + } + + wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, + vk_access_mask_from_bind_flags(dst_texture_vk->t.resource.bind_flags), + dst_layout, dst_texture_vk->layout, dst_texture_vk->image.vk_image, &vk_dst_range); + wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_ACCESS_TRANSFER_READ_BIT, + vk_access_mask_from_bind_flags(src_texture_vk->t.resource.bind_flags), + src_layout, src_texture_vk->layout, src_texture_vk->image.vk_image, &vk_src_range); + + wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB); + wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB); + if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location)) + ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(dst_location)); + + wined3d_context_vk_reference_texture(context_vk, src_texture_vk); + wined3d_context_vk_reference_texture(context_vk, dst_texture_vk); + + return dst_location | WINED3D_LOCATION_TEXTURE_RGB; + +barrier_next: + wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, + vk_access_mask_from_bind_flags(dst_texture_vk->t.resource.bind_flags), + dst_layout, dst_texture_vk->layout, dst_texture_vk->image.vk_image, &vk_dst_range); + wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_ACCESS_TRANSFER_READ_BIT, + vk_access_mask_from_bind_flags(src_texture_vk->t.resource.bind_flags), + src_layout, src_texture_vk->layout, src_texture_vk->image.vk_image, &vk_src_range); + +next: + if (!(next = blitter->next)) + { + ERR("No blitter to handle blit op %#x.\n", op); + return dst_location; + } + + TRACE("Forwarding to blitter %p.\n", next); + return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location, + src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter, resolve_format); +} + +static const struct wined3d_blitter_ops vk_blitter_ops = +{ + .blitter_destroy = vk_blitter_destroy, + .blitter_clear = vk_blitter_clear, + .blitter_blit = vk_blitter_blit, +}; + +void wined3d_vk_blitter_create(struct wined3d_blitter **next) +{ + struct wined3d_blitter *blitter; + + if (!(blitter = malloc(sizeof(*blitter)))) + return; + + TRACE("Created blitter %p.\n", blitter); + + blitter->ops = &vk_blitter_ops; + blitter->next = *next; + *next = blitter; +} diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 817fb99193b..17950c852af 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -5089,6 +5089,50 @@ static inline bool wined3d_map_persistent(void) return sizeof(void *) >= sizeof(uint64_t); }
+bool is_full_clear(const struct wined3d_rendertarget_view *rtv, const RECT *draw_rect, const RECT *clear_rect); + +struct wined3d_rect_f +{ + float l; + float t; + float r; + float b; +}; + +static const uint32_t wined3d_texture_sysmem_locations = WINED3D_LOCATION_SYSMEM | WINED3D_LOCATION_BUFFER; + +void wined3d_texture_get_memory(struct wined3d_texture *texture, unsigned int sub_resource_idx, + struct wined3d_context *context, struct wined3d_bo_address *data); + +enum wined3d_format_id wined3d_get_alpha_fixup_format(enum wined3d_format_id format_id, + const struct wined3d_format *dst_format); + +bool blitter_use_cpu_clear(struct wined3d_rendertarget_view *view); + +HRESULT wined3d_texture_init(struct wined3d_texture *texture, const struct wined3d_resource_desc *desc, + unsigned int layer_count, unsigned int level_count, uint32_t flags, struct wined3d_device *device, + void *parent, const struct wined3d_parent_ops *parent_ops, void *sub_resources, + const struct wined3d_texture_ops *texture_ops); + +void wined3d_fixup_alpha(const struct wined3d_format *format, const uint8_t *src, + unsigned int src_row_pitch, uint8_t *dst, unsigned int dst_row_pitch, + unsigned int width, unsigned int height); + +BOOL wined3d_texture_load_drawable(struct wined3d_texture *texture, + unsigned int sub_resource_idx, struct wined3d_context *context); + +void wined3d_texture_set_map_binding(struct wined3d_texture *texture, DWORD map_binding); + +void wined3d_texture_set_dirty(struct wined3d_texture *texture); + +static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct wined3d_rect_f *f) +{ + f->l = ((r->left * 2.0f) / w) - 1.0f; + f->t = ((r->top * 2.0f) / h) - 1.0f; + f->r = ((r->right * 2.0f) / w) - 1.0f; + f->b = ((r->bottom * 2.0f) / h) - 1.0f; +} + /* The WNDCLASS-Name for the fake window which we use to retrieve the GL capabilities */ #define WINED3D_OPENGL_WINDOW_CLASS_NAME "WineD3D_OpenGL"