Signed-off-by: Andrew Wesie awesie@gmail.com --- dlls/wined3d/surface.c | 233 +------------------------- dlls/wined3d/texture.c | 359 +++++++++++++++++++++++++++++++++-------- dlls/wined3d/wined3d_private.h | 2 + 3 files changed, 295 insertions(+), 299 deletions(-)
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index 8b69720..4942177 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -342,235 +342,6 @@ static BOOL fbo_blitter_supported(enum wined3d_blit_op blit_op, const struct win return TRUE; }
-/* This call just downloads data, the caller is responsible for binding the - * correct texture. */ -/* Context activation is done by the caller. */ -static void texture2d_download_data(struct wined3d_texture *texture, unsigned int sub_resource_idx, - const struct wined3d_context *context, DWORD dst_location) -{ - const struct wined3d_gl_info *gl_info = context->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; - struct wined3d_bo_address data; - BYTE *temporary_mem = NULL; - unsigned int level; - GLenum target; - void *mem; - - format_gl = wined3d_format_gl(texture->resource.format); - - /* Only support read back of converted P8 textures. */ - if (texture->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, sub_resource_idx, debug_d3dformat(format_gl->f.id)); - return; - } - - sub_resource = &texture->sub_resources[sub_resource_idx]; - target = wined3d_texture_get_sub_resource_target(texture, sub_resource_idx); - level = sub_resource_idx % texture->level_count; - - if (target == GL_TEXTURE_2D_ARRAY) - { - if (format_gl->f.download) - { - FIXME("Reading back converted array texture %p is not supported.\n", texture); - return; - } - - /* NP2 emulation is not allowed on array textures. */ - if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED) - ERR("Array texture %p uses NP2 emulation.\n", texture); - - WARN_(d3d_perf)("Downloading all miplevel layers to get the data for a single sub-resource.\n"); - - if (!(temporary_mem = heap_calloc(texture->layer_count, sub_resource->size))) - { - ERR("Out of memory.\n"); - return; - } - } - - wined3d_texture_get_memory(texture, sub_resource_idx, &data, dst_location); - - if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED) - { - if (format_gl->f.download) - { - FIXME("Reading back converted texture %p with NP2 emulation is not supported.\n", texture); - return; - } - - wined3d_texture_get_pitch(texture, level, &dst_row_pitch, &dst_slice_pitch); - wined3d_format_calculate_pitch(&format_gl->f, texture->resource.device->surface_alignment, - wined3d_texture_get_level_pow2_width(texture, level), - wined3d_texture_get_level_pow2_height(texture, level), - &src_row_pitch, &src_slice_pitch); - if (!(temporary_mem = heap_alloc(src_slice_pitch))) - { - ERR("Out of memory.\n"); - return; - } - - if (data.buffer_object) - ERR("NP2 emulated texture uses PBO unexpectedly.\n"); - if (texture->resource.format_flags & WINED3DFMT_FLAG_COMPRESSED) - ERR("Unexpected compressed format for NP2 emulated texture.\n"); - } - - if (format_gl->f.download) - { - struct wined3d_format f; - - if (data.buffer_object) - ERR("Converted texture %p uses PBO unexpectedly.\n", texture); - - WARN_(d3d_perf)("Downloading converted texture %p, %u with format %s.\n", - texture, 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, level, &dst_row_pitch, &dst_slice_pitch); - wined3d_format_calculate_pitch(&f, texture->resource.device->surface_alignment, - wined3d_texture_get_level_width(texture, level), - wined3d_texture_get_level_height(texture, level), - &src_row_pitch, &src_slice_pitch); - - if (!(temporary_mem = heap_alloc(src_slice_pitch))) - { - ERR("Failed to allocate memory.\n"); - return; - } - } - - if (temporary_mem) - { - mem = temporary_mem; - } - else if (data.buffer_object) - { - GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object)); - checkGLcall("glBindBuffer"); - mem = data.addr; - } - else - { - mem = data.addr; - } - - if (texture->resource.format_flags & WINED3DFMT_FLAG_COMPRESSED) - { - TRACE("Downloading compressed texture %p, %u, level %u, format %#x, type %#x, data %p.\n", - texture, 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, 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, level), - wined3d_texture_get_level_height(texture, level), 1); - } - else if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED) - { - const BYTE *src_data; - unsigned int h, y; - BYTE *dst_data; - /* - * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing - * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to - * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width. - * - * We're doing this... - * - * instead of boxing the texture : - * |<-texture width ->| -->pow2width| /\ - * |111111111111111111| | | - * |222 Texture 222222| boxed empty | texture height - * |3333 Data 33333333| | | - * |444444444444444444| | / - * ----------------------------------- | - * | boxed empty | boxed empty | pow2height - * | | | / - * ----------------------------------- - * - * - * we're repacking the data to the expected texture width - * - * |<-texture width ->| -->pow2width| /\ - * |111111111111111111222222222222222| | - * |222333333333333333333444444444444| texture height - * |444444 | | - * | | / - * | | | - * | empty | pow2height - * | | / - * ----------------------------------- - * - * == is the same as - * - * |<-texture width ->| /\ - * |111111111111111111| - * |222222222222222222|texture height - * |333333333333333333| - * |444444444444444444| / - * -------------------- - * - * This also means that any references to surface memory should work with the data as if it were a - * standard texture with a non-power2 width instead of a texture boxed up to be a power2 texture. - * - * internally the texture is still stored in a boxed format so any references to textureName will - * get a boxed texture with width pow2width and not a texture of width resource.width. */ - src_data = mem; - dst_data = data.addr; - TRACE("Repacking the surface data from pitch %u to pitch %u.\n", src_row_pitch, dst_row_pitch); - h = wined3d_texture_get_level_height(texture, level); - for (y = 0; y < h; ++y) - { - memcpy(dst_data, src_data, dst_row_pitch); - src_data += src_row_pitch; - dst_data += dst_row_pitch; - } - } - else if (temporary_mem) - { - unsigned int layer = sub_resource_idx / texture->level_count; - void *src_data = temporary_mem + layer * sub_resource->size; - if (data.buffer_object) - { - GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object)); - checkGLcall("glBindBuffer"); - GL_EXTCALL(glBufferSubData(GL_PIXEL_PACK_BUFFER, 0, sub_resource->size, src_data)); - checkGLcall("glBufferSubData"); - } - else - { - memcpy(data.addr, src_data, sub_resource->size); - } - } - - if (data.buffer_object) - { - GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)); - checkGLcall("glBindBuffer"); - } - - heap_free(temporary_mem); -} - /* See also float_16_to_32() in wined3d_private.h */ static inline unsigned short float_32_to_16(const float *in) { @@ -1666,9 +1437,11 @@ BOOL texture2d_load_sysmem(struct wined3d_texture *texture, unsigned int sub_res /* Download the sub-resource to system memory. */ if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB)) { + struct wined3d_bo_address data; wined3d_texture_bind_and_dirtify(texture, context, !(sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB)); - texture2d_download_data(texture, sub_resource_idx, context, dst_location); + wined3d_texture_get_memory(texture, sub_resource_idx, &data, dst_location); + wined3d_texture_download_data(texture, sub_resource_idx, context, &data); ++texture->download_count; return TRUE; } diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index 9589e49..29bbdd7 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -2136,6 +2136,291 @@ void wined3d_texture_upload_data(struct wined3d_texture *texture, unsigned int s } }
+static void texture2d_download_data(struct wined3d_texture *texture, unsigned int sub_resource_idx, + struct wined3d_context *context, const struct wined3d_bo_address *data) +{ + const struct wined3d_gl_info *gl_info = context->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->resource.format); + + /* Only support read back of converted P8 textures. */ + if (texture->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, sub_resource_idx, debug_d3dformat(format_gl->f.id)); + return; + } + + sub_resource = &texture->sub_resources[sub_resource_idx]; + target = wined3d_texture_get_sub_resource_target(texture, sub_resource_idx); + level = sub_resource_idx % texture->level_count; + + if (target == GL_TEXTURE_2D_ARRAY) + { + if (format_gl->f.download) + { + FIXME("Reading back converted array texture %p is not supported.\n", texture); + return; + } + + /* NP2 emulation is not allowed on array textures. */ + if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED) + ERR("Array texture %p uses NP2 emulation.\n", texture); + + WARN_(d3d_perf)("Downloading all miplevel layers to get the data for a single sub-resource.\n"); + + if (!(temporary_mem = heap_calloc(texture->layer_count, sub_resource->size))) + { + ERR("Out of memory.\n"); + return; + } + } + + if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED) + { + if (format_gl->f.download) + { + FIXME("Reading back converted texture %p with NP2 emulation is not supported.\n", texture); + return; + } + + wined3d_texture_get_pitch(texture, level, &dst_row_pitch, &dst_slice_pitch); + wined3d_format_calculate_pitch(&format_gl->f, texture->resource.device->surface_alignment, + wined3d_texture_get_level_pow2_width(texture, level), + wined3d_texture_get_level_pow2_height(texture, level), + &src_row_pitch, &src_slice_pitch); + if (!(temporary_mem = heap_alloc(src_slice_pitch))) + { + ERR("Out of memory.\n"); + return; + } + + if (data->buffer_object) + ERR("NP2 emulated texture uses PBO unexpectedly.\n"); + if (texture->resource.format_flags & WINED3DFMT_FLAG_COMPRESSED) + ERR("Unexpected compressed format for NP2 emulated texture.\n"); + } + + if (format_gl->f.download) + { + struct wined3d_format f; + + if (data->buffer_object) + ERR("Converted texture %p uses PBO unexpectedly.\n", texture); + + WARN_(d3d_perf)("Downloading converted texture %p, %u with format %s.\n", + texture, 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, level, &dst_row_pitch, &dst_slice_pitch); + wined3d_format_calculate_pitch(&f, texture->resource.device->surface_alignment, + wined3d_texture_get_level_width(texture, level), + wined3d_texture_get_level_height(texture, level), + &src_row_pitch, &src_slice_pitch); + + if (!(temporary_mem = heap_alloc(src_slice_pitch))) + { + ERR("Failed to allocate memory.\n"); + return; + } + } + + if (temporary_mem) + { + mem = temporary_mem; + } + else if (data->buffer_object) + { + GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data->buffer_object)); + checkGLcall("glBindBuffer"); + mem = data->addr; + } + else + { + mem = data->addr; + } + + if (texture->resource.format_flags & WINED3DFMT_FLAG_COMPRESSED) + { + TRACE("Downloading compressed texture %p, %u, level %u, format %#x, type %#x, data %p.\n", + texture, 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, 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, level), + wined3d_texture_get_level_height(texture, level), 1); + } + else if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED) + { + const BYTE *src_data; + unsigned int h, y; + BYTE *dst_data; + /* + * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing + * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to + * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width. + * + * We're doing this... + * + * instead of boxing the texture : + * |<-texture width ->| -->pow2width| /\ + * |111111111111111111| | | + * |222 Texture 222222| boxed empty | texture height + * |3333 Data 33333333| | | + * |444444444444444444| | / + * ----------------------------------- | + * | boxed empty | boxed empty | pow2height + * | | | / + * ----------------------------------- + * + * + * we're repacking the data to the expected texture width + * + * |<-texture width ->| -->pow2width| /\ + * |111111111111111111222222222222222| | + * |222333333333333333333444444444444| texture height + * |444444 | | + * | | / + * | | | + * | empty | pow2height + * | | / + * ----------------------------------- + * + * == is the same as + * + * |<-texture width ->| /\ + * |111111111111111111| + * |222222222222222222|texture height + * |333333333333333333| + * |444444444444444444| / + * -------------------- + * + * This also means that any references to surface memory should work with the data as if it were a + * standard texture with a non-power2 width instead of a texture boxed up to be a power2 texture. + * + * internally the texture is still stored in a boxed format so any references to textureName will + * get a boxed texture with width pow2width and not a texture of width resource.width. */ + src_data = mem; + dst_data = data->addr; + TRACE("Repacking the surface data from pitch %u to pitch %u.\n", src_row_pitch, dst_row_pitch); + h = wined3d_texture_get_level_height(texture, level); + for (y = 0; y < h; ++y) + { + memcpy(dst_data, src_data, dst_row_pitch); + src_data += src_row_pitch; + dst_data += dst_row_pitch; + } + } + else if (temporary_mem) + { + unsigned int layer = sub_resource_idx / texture->level_count; + void *src_data = temporary_mem + layer * sub_resource->size; + if (data->buffer_object) + { + GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data->buffer_object)); + checkGLcall("glBindBuffer"); + GL_EXTCALL(glBufferSubData(GL_PIXEL_PACK_BUFFER, 0, sub_resource->size, src_data)); + checkGLcall("glBufferSubData"); + } + else + { + memcpy(data->addr, src_data, sub_resource->size); + } + } + + if (data->buffer_object) + { + GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)); + checkGLcall("glBindBuffer"); + } + + heap_free(temporary_mem); +} + +/* This call just downloads data, the caller is responsible for binding the + * correct texture. Partial downloads are not supported. */ +/* Context activation is done by the caller. */ +void wined3d_texture_download_data(struct wined3d_texture *texture, unsigned int sub_resource_idx, + struct wined3d_context *context, const struct wined3d_bo_address *data) +{ + const struct wined3d_gl_info *gl_info = context->gl_info; + const struct wined3d_format_gl *format_gl; + unsigned int level; + GLenum target; + + format_gl = wined3d_format_gl(texture->resource.format); + target = wined3d_texture_get_sub_resource_target(texture, sub_resource_idx); + level = sub_resource_idx % texture->level_count; + + if (texture->resource.type == WINED3D_RTYPE_TEXTURE_2D + && (target == GL_TEXTURE_2D_ARRAY || format_gl->f.conv_byte_count + || texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)) + { + /* 2D-specific special cases. */ + texture2d_download_data(texture, sub_resource_idx, context, data); + return; + } + + if (format_gl->f.conv_byte_count) + { + FIXME("Attempting to download a converted texture, type %s format %s.\n", + debug_d3dresourcetype(texture->resource.type), + debug_d3dformat(format_gl->f.id)); + return; + } + + if (data->buffer_object) + { + GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data->buffer_object)); + checkGLcall("glBindBuffer"); + } + + if (texture->resource.format_flags & WINED3DFMT_FLAG_COMPRESSED) + { + TRACE("Downloading compressed texture %p, %u, level %u, format %#x, type %#x, data %p.\n", + texture, sub_resource_idx, level, format_gl->format, format_gl->type, data->addr); + + GL_EXTCALL(glGetCompressedTexImage(target, level, data->addr)); + checkGLcall("glGetCompressedTexImage"); + } + else + { + TRACE("Downloading texture %p, %u, level %u, format %#x, type %#x, data %p.\n", + texture, sub_resource_idx, level, format_gl->format, format_gl->type, data->addr); + + gl_info->gl_ops.gl.p_glGetTexImage(target, level, format_gl->format, format_gl->type, data->addr); + checkGLcall("glGetTexImage"); + } + + if (data->buffer_object) + { + GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)); + checkGLcall("glBindBuffer"); + } +} + /* Context activation is done by the caller. Context may be NULL in ddraw-only mode. */ static BOOL texture2d_load_location(struct wined3d_texture *texture, unsigned int sub_resource_idx, struct wined3d_context *context, DWORD location) @@ -2441,38 +2726,6 @@ static const struct wined3d_resource_ops texture_resource_ops = };
/* Context activation is done by the caller. */ -static void texture1d_download_data(struct wined3d_texture *texture, unsigned int sub_resource_idx, - const struct wined3d_context *context, const struct wined3d_bo_address *data) -{ - const struct wined3d_gl_info *gl_info = context->gl_info; - const struct wined3d_format_gl *format_gl; - - format_gl = wined3d_format_gl(texture->resource.format); - if (format_gl->f.conv_byte_count) - { - FIXME("Attempting to download a converted texture, format %s.\n", - debug_d3dformat(format_gl->f.id)); - return; - } - - if (data->buffer_object) - { - GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data->buffer_object)); - checkGLcall("glBindBuffer"); - } - - gl_info->gl_ops.gl.p_glGetTexImage(texture->target, sub_resource_idx, - format_gl->format, format_gl->type, data->addr); - checkGLcall("glGetTexImage"); - - if (data->buffer_object) - { - GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)); - checkGLcall("glBindBuffer"); - } -} - -/* Context activation is done by the caller. */ static BOOL texture1d_load_location(struct wined3d_texture *texture, unsigned int sub_resource_idx, struct wined3d_context *context, DWORD location) { @@ -2532,7 +2785,7 @@ static BOOL texture1d_load_location(struct wined3d_texture *texture, unsigned in else wined3d_texture_bind_and_dirtify(texture, context, TRUE);
- texture1d_download_data(texture, sub_resource_idx, context, &data); + wined3d_texture_download_data(texture, sub_resource_idx, context, &data); ++texture->download_count; } else @@ -2553,7 +2806,7 @@ static BOOL texture1d_load_location(struct wined3d_texture *texture, unsigned in else wined3d_texture_bind_and_dirtify(texture, context, TRUE);
- texture1d_download_data(texture, sub_resource_idx, context, &data); + wined3d_texture_download_data(texture, sub_resource_idx, context, &data); } else { @@ -2914,38 +3167,6 @@ static HRESULT wined3d_texture_init(struct wined3d_texture *texture, const struc }
/* Context activation is done by the caller. */ -static void texture3d_download_data(struct wined3d_texture *texture, unsigned int sub_resource_idx, - const struct wined3d_context *context, const struct wined3d_bo_address *data) -{ - const struct wined3d_gl_info *gl_info = context->gl_info; - const struct wined3d_format_gl *format_gl; - - format_gl = wined3d_format_gl(texture->resource.format); - if (format_gl->f.conv_byte_count) - { - FIXME("Attempting to download a converted volume, format %s.\n", - debug_d3dformat(format_gl->f.id)); - return; - } - - if (data->buffer_object) - { - GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data->buffer_object)); - checkGLcall("glBindBuffer"); - } - - gl_info->gl_ops.gl.p_glGetTexImage(GL_TEXTURE_3D, sub_resource_idx, - format_gl->format, format_gl->type, data->addr); - checkGLcall("glGetTexImage"); - - if (data->buffer_object) - { - GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)); - checkGLcall("glBindBuffer"); - } -} - -/* Context activation is done by the caller. */ static void texture3d_srgb_transfer(struct wined3d_texture *texture, unsigned int sub_resource_idx, struct wined3d_context *context, BOOL dest_is_srgb) { @@ -2968,7 +3189,7 @@ static void texture3d_srgb_transfer(struct wined3d_texture *texture, unsigned in wined3d_texture_get_pitch(texture, sub_resource_idx, &row_pitch, &slice_pitch); wined3d_texture_get_level_box(texture, sub_resource_idx % texture->level_count, &src_box); wined3d_texture_bind_and_dirtify(texture, context, !dest_is_srgb); - texture3d_download_data(texture, sub_resource_idx, context, &data); + wined3d_texture_download_data(texture, sub_resource_idx, context, &data); wined3d_texture_bind_and_dirtify(texture, context, dest_is_srgb); wined3d_texture_upload_data(texture, sub_resource_idx, context, texture->resource.format, &src_box, wined3d_const_bo_address(&data), row_pitch, slice_pitch, 0, 0, 0, FALSE); @@ -3041,7 +3262,7 @@ static BOOL texture3d_load_location(struct wined3d_texture *texture, unsigned in else wined3d_texture_bind_and_dirtify(texture, context, TRUE);
- texture3d_download_data(texture, sub_resource_idx, context, &data); + wined3d_texture_download_data(texture, sub_resource_idx, context, &data); ++texture->download_count; } else @@ -3062,7 +3283,7 @@ static BOOL texture3d_load_location(struct wined3d_texture *texture, unsigned in else wined3d_texture_bind_and_dirtify(texture, context, TRUE);
- texture3d_download_data(texture, sub_resource_idx, context, &data); + wined3d_texture_download_data(texture, sub_resource_idx, context, &data); } else { diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 8cfa4c3..7d35e55 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -3348,6 +3348,8 @@ void wined3d_texture_bind_and_dirtify(struct wined3d_texture *texture, struct wined3d_context *context, BOOL srgb) DECLSPEC_HIDDEN; HRESULT wined3d_texture_check_box_dimensions(const struct wined3d_texture *texture, unsigned int level, const struct wined3d_box *box) DECLSPEC_HIDDEN; +void wined3d_texture_download_data(struct wined3d_texture *texture, unsigned int sub_resource_idx, + struct wined3d_context *context, const struct wined3d_bo_address *data) DECLSPEC_HIDDEN; GLenum wined3d_texture_get_gl_buffer(const struct wined3d_texture *texture) DECLSPEC_HIDDEN; void wined3d_texture_get_memory(struct wined3d_texture *texture, unsigned int sub_resource_idx, struct wined3d_bo_address *data, DWORD locations) DECLSPEC_HIDDEN;
Signed-off-by: Andrew Wesie awesie@gmail.com --- dlls/wined3d/surface.c | 56 ++++++++++++++++++++++++++++++------------ dlls/wined3d/texture.c | 22 +++++++++++++++++ dlls/wined3d/wined3d_private.h | 2 ++ 3 files changed, 64 insertions(+), 16 deletions(-)
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index 4942177..fe64a6d 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -3218,22 +3218,7 @@ HRESULT texture2d_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_ goto cpu; }
- blit_op = WINED3D_BLIT_OP_COLOR_BLIT; - if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE) - { - colour_key = &fx->src_color_key; - blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY; - } - else if (flags & WINED3D_BLT_SRC_CKEY) - { - colour_key = &src_texture->async.src_blt_color_key; - blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY; - } - else if (flags & WINED3D_BLT_ALPHA_TEST) - { - blit_op = WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST; - } - else if ((src_sub_resource->locations & surface_simple_locations) + if ((src_sub_resource->locations & surface_simple_locations) && !(dst_sub_resource->locations & surface_simple_locations)) { /* Upload */ @@ -3257,6 +3242,45 @@ HRESULT texture2d_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_ return WINED3D_OK; } } + else if (!(src_sub_resource->locations & surface_simple_locations) + && (dst_sub_resource->locations & dst_texture->resource.map_binding)) + { + /* Download */ + if (scale) + TRACE("Not doing download because of scaling.\n"); + else if (convert) + TRACE("Not doing download because of format conversion.\n"); + else if (dst_texture->resource.format->conv_byte_count) + TRACE("Not doing download because the destination format needs conversion.\n"); + else if (!texture2d_is_full_rect(src_texture, src_sub_resource_idx % src_texture->level_count, &src_rect)) + TRACE("Not doing download because of partial download (src).\n"); + else if (!texture2d_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, &dst_rect)) + TRACE("Not doing download because of partial download (dst).\n"); + else if (is_multisample_location(src_texture, WINED3D_LOCATION_TEXTURE_RGB)) + TRACE("Not doing download because of multisample source.\n"); + else + { + wined3d_texture_download_from_texture(dst_texture, dst_sub_resource_idx, src_texture, + src_sub_resource_idx); + return WINED3D_OK; + } + } + + blit_op = WINED3D_BLIT_OP_COLOR_BLIT; + if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE) + { + colour_key = &fx->src_color_key; + blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY; + } + else if (flags & WINED3D_BLT_SRC_CKEY) + { + colour_key = &src_texture->async.src_blt_color_key; + blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY; + } + else if (flags & WINED3D_BLT_ALPHA_TEST) + { + blit_op = WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST; + } else if (dst_swapchain && dst_swapchain->back_buffers && dst_texture == dst_swapchain->front_buffer && src_texture == dst_swapchain->back_buffers[0]) diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index 29bbdd7..60d1e5b 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -3798,3 +3798,25 @@ void wined3d_texture_upload_from_texture(struct wined3d_texture *dst_texture, un 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) +{ + struct wined3d_context *context; + struct wined3d_bo_address data; + DWORD dst_location = dst_texture->resource.map_binding; + + 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_memory(dst_texture, dst_sub_resource_idx, &data, dst_location); + wined3d_texture_bind_and_dirtify(src_texture, context, + !(src_texture->sub_resources[src_sub_resource_idx].locations & WINED3D_LOCATION_TEXTURE_RGB)); + wined3d_texture_download_data(src_texture, src_sub_resource_idx, context, &data); + + 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); +} diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 7d35e55..34d5917 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -3350,6 +3350,8 @@ HRESULT wined3d_texture_check_box_dimensions(const struct wined3d_texture *textu unsigned int level, const struct wined3d_box *box) DECLSPEC_HIDDEN; void wined3d_texture_download_data(struct wined3d_texture *texture, unsigned int sub_resource_idx, struct wined3d_context *context, const struct wined3d_bo_address *data) DECLSPEC_HIDDEN; +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) DECLSPEC_HIDDEN; GLenum wined3d_texture_get_gl_buffer(const struct wined3d_texture *texture) DECLSPEC_HIDDEN; void wined3d_texture_get_memory(struct wined3d_texture *texture, unsigned int sub_resource_idx, struct wined3d_bo_address *data, DWORD locations) DECLSPEC_HIDDEN;
On Sun, 30 Sep 2018 at 20:32, Andrew Wesie awesie@gmail.com wrote:
@@ -3218,22 +3218,7 @@ HRESULT texture2d_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_ goto cpu; }
- blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
- if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
- {
colour_key = &fx->src_color_key;
blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
- }
- else if (flags & WINED3D_BLT_SRC_CKEY)
- {
colour_key = &src_texture->async.src_blt_color_key;
blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
- }
- else if (flags & WINED3D_BLT_ALPHA_TEST)
- {
blit_op = WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST;
- }
...
- blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
- if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
- {
colour_key = &fx->src_color_key;
blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
- }
- else if (flags & WINED3D_BLT_SRC_CKEY)
- {
colour_key = &src_texture->async.src_blt_color_key;
blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
- }
- else if (flags & WINED3D_BLT_ALPHA_TEST)
- {
blit_op = WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST;
- }
Moving these down means uploads/downloads will potentially be used for colour-key and alpha-test blits, which seems wrong. Was that change intentional?
On Wed, Oct 3, 2018 at 10:16 AM Henri Verbeet hverbeet@gmail.com wrote:
Moving these down means uploads/downloads will potentially be used for colour-key and alpha-test blits, which seems wrong. Was that change intentional?
The problem I was trying to solve is that blit_op = WINED3D_BLIT_OP_RAW_BLIT still needs to happen if we cannot do the download for some reason (e.g. texture sizes don't match). I agree that the change is not obviously correct.
How about moving the upload / download to after the conditionals and verifying blit_op == WINED3D_BLIT_OP_RAW_BLIT?
On Wed, 3 Oct 2018 at 19:33, Andrew Wesie awesie@gmail.com wrote:
On Wed, Oct 3, 2018 at 10:16 AM Henri Verbeet hverbeet@gmail.com wrote:
Moving these down means uploads/downloads will potentially be used for colour-key and alpha-test blits, which seems wrong. Was that change intentional?
The problem I was trying to solve is that blit_op = WINED3D_BLIT_OP_RAW_BLIT still needs to happen if we cannot do the download for some reason (e.g. texture sizes don't match). I agree that the change is not obviously correct.
How about moving the upload / download to after the conditionals and verifying blit_op == WINED3D_BLIT_OP_RAW_BLIT?
Yeah, I think that makes sense, and I think it would actually slightly simplify the upload/download branches.
On Wed, Oct 3, 2018 at 11:11 AM Henri Verbeet hverbeet@gmail.com wrote:
On Wed, 3 Oct 2018 at 19:33, Andrew Wesie awesie@gmail.com wrote:
The problem I was trying to solve is that blit_op =
WINED3D_BLIT_OP_RAW_BLIT still needs to happen if we cannot do the download for some reason (e.g. texture sizes don't match). I agree that the change is not obviously correct.
How about moving the upload / download to after the conditionals and
verifying blit_op == WINED3D_BLIT_OP_RAW_BLIT?
Yeah, I think that makes sense, and I think it would actually slightly simplify the upload/download branches.
After testing, one issue is that we need to use wined3d_texture_upload_from_texture in some cases where resolve == 1 otherwise d3d9:test_multisample_init fails on my machine. Currently, we only set blit_op = WINED3D_BLIT_OP_RAW_BLIT when resolve == 0.
In the interest of solving one problem at a time, I'll avoid this for now and do it a different way in v2, though I agree that these branches could use some clean-up.
Signed-off-by: Andrew Wesie awesie@gmail.com --- dlls/wined3d/texture.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index 60d1e5b..78e9364 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -46,11 +46,15 @@ struct wined3d_rect_f
static BOOL wined3d_texture_use_pbo(const struct wined3d_texture *texture, const struct wined3d_gl_info *gl_info) { - return !(texture->resource.access & WINED3D_RESOURCE_ACCESS_CPU) - && texture->resource.usage & WINED3DUSAGE_DYNAMIC - && gl_info->supported[ARB_PIXEL_BUFFER_OBJECT] - && !texture->resource.format->conv_byte_count - && !(texture->flags & (WINED3D_TEXTURE_PIN_SYSMEM | WINED3D_TEXTURE_COND_NP2_EMULATED)); + if (!gl_info->supported[ARB_PIXEL_BUFFER_OBJECT] + || texture->resource.format->conv_byte_count + || (texture->flags & (WINED3D_TEXTURE_PIN_SYSMEM | WINED3D_TEXTURE_COND_NP2_EMULATED))) + return FALSE; + + /* Use a PBO for dynamic textures and read-only staging textures. */ + return (!(texture->resource.access & WINED3D_RESOURCE_ACCESS_CPU) + && texture->resource.usage & WINED3DUSAGE_DYNAMIC) + || texture->resource.access == (WINED3D_RESOURCE_ACCESS_CPU | WINED3D_RESOURCE_ACCESS_MAP_R); }
static BOOL wined3d_texture_use_immutable_storage(const struct wined3d_texture *texture,
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Andrew Wesie awesie@gmail.com --- dlls/wined3d/texture.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index 78e9364..3efd675 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -2371,11 +2371,13 @@ void wined3d_texture_download_data(struct wined3d_texture *texture, unsigned int { const struct wined3d_gl_info *gl_info = context->gl_info; const struct wined3d_format_gl *format_gl; + struct wined3d_texture_sub_resource *sub_resource; unsigned int level; GLenum target;
format_gl = wined3d_format_gl(texture->resource.format); target = wined3d_texture_get_sub_resource_target(texture, sub_resource_idx); + sub_resource = &texture->sub_resources[sub_resource_idx]; level = sub_resource_idx % texture->level_count;
if (texture->resource.type == WINED3D_RTYPE_TEXTURE_2D @@ -2409,6 +2411,23 @@ void wined3d_texture_download_data(struct wined3d_texture *texture, unsigned int GL_EXTCALL(glGetCompressedTexImage(target, level, data->addr)); checkGLcall("glGetCompressedTexImage"); } + else if (data->buffer_object && texture->resource.usage & WINED3DUSAGE_RENDERTARGET) + { + /* PBO texture download is not accelerated on Mesa. Use glReadPixels if possible. */ + TRACE("Downloading (glReadPixels) texture %p, %u, level %u, format %#x, type %#x, data %p.\n", + texture, sub_resource_idx, level, format_gl->format, format_gl->type, data->addr); + + context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, &texture->resource, sub_resource_idx, NULL, + 0, sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB)); + context_check_fbo_status(context, GL_READ_FRAMEBUFFER); + context_invalidate_state(context, STATE_FRAMEBUFFER); + gl_info->gl_ops.gl.p_glReadBuffer(GL_COLOR_ATTACHMENT0); + checkGLcall("glReadBuffer()"); + + gl_info->gl_ops.gl.p_glReadPixels(0, 0, wined3d_texture_get_level_width(texture, level), + wined3d_texture_get_level_height(texture, level), format_gl->format, format_gl->type, data->addr); + checkGLcall("glReadPixels"); + } else { TRACE("Downloading texture %p, %u, level %u, format %#x, type %#x, data %p.\n",