From: Matteo Bruni mbruni@codeweavers.com
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com --- dlls/wined3d/glsl_shader.c | 49 ++++++++++++++++++++++++++++---- dlls/wined3d/surface.c | 64 ++++++------------------------------------ dlls/wined3d/texture.c | 46 ++++++++++++++++++++++++++++++ dlls/wined3d/wined3d_private.h | 3 ++ 4 files changed, 100 insertions(+), 62 deletions(-)
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index e839369f11c..7f1e66bc877 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -12428,11 +12428,9 @@ static BOOL glsl_blitter_supported(enum wined3d_blit_op blit_op, const struct wi return FALSE; }
- /* FIXME: We never want to blit from resources without + /* We don't necessarily want to blit from resources without * WINED3D_RESOURCE_ACCESS_GPU, but that may be the only way to decompress - * compressed textures. We should probably create an explicit staging - * texture for this purpose instead of loading the resource into an - * invalid location. */ + * compressed textures. */ decompress = src_format && (src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED) && !(dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED); if (!decompress && !(src_resource->access & dst_resource->access & WINED3D_RESOURCE_ACCESS_GPU)) @@ -12465,8 +12463,10 @@ static DWORD glsl_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_bli { struct wined3d_device *device = dst_texture->resource.device; const struct wined3d_gl_info *gl_info = context->gl_info; + struct wined3d_texture *staging_texture = NULL; struct wined3d_glsl_blitter *glsl_blitter; struct wined3d_blitter *next; + unsigned int src_level; GLuint program_id; RECT s, d;
@@ -12491,12 +12491,45 @@ static DWORD glsl_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_bli
glsl_blitter = CONTAINING_RECORD(blitter, struct wined3d_glsl_blitter, blitter);
- if (wined3d_settings.offscreen_rendering_mode != ORM_FBO + if (!(src_texture->resource.access & WINED3D_RESOURCE_ACCESS_GPU)) + { + struct wined3d_resource_desc desc; + struct wined3d_box upload_box; + HRESULT hr; + + TRACE("Source texture is not GPU accessible, creating a staging texture.\n"); + + src_level = src_sub_resource_idx % src_texture->level_count; + desc.resource_type = WINED3D_RTYPE_TEXTURE_2D; + desc.format = src_texture->resource.format->id; + desc.multisample_type = src_texture->resource.multisample_type; + desc.multisample_quality = src_texture->resource.multisample_quality; + desc.usage = WINED3DUSAGE_PRIVATE; + 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; + + if (FAILED(hr = wined3d_texture_create(device, &desc, 1, 1, 0, + NULL, NULL, &wined3d_null_parent_ops, &staging_texture))) + { + ERR("Failed to create staging texture, hr %#x.\n", hr); + return dst_location; + } + + wined3d_box_set(&upload_box, 0, 0, desc.width, desc.height, 0, desc.depth); + wined3d_texture_upload_from_texture(staging_texture, 0, 0, 0, 0, + src_texture, src_sub_resource_idx, &upload_box); + + src_texture = staging_texture; + src_sub_resource_idx = 0; + } + else if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && (src_texture->sub_resources[src_sub_resource_idx].locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_DRAWABLE)) == WINED3D_LOCATION_DRAWABLE && !wined3d_resource_is_offscreen(&src_texture->resource)) { - unsigned int src_level = src_sub_resource_idx % src_texture->level_count;
/* Without FBO blits transferring from the drawable to the texture is * expensive, because we have to flip the data in sysmem. Since we can @@ -12506,6 +12539,7 @@ static DWORD glsl_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_bli texture2d_load_fb_texture(src_texture, src_sub_resource_idx, FALSE, context);
s = *src_rect; + src_level = src_sub_resource_idx % src_texture->level_count; s.top = wined3d_texture_get_level_height(src_texture, src_level) - s.top; s.bottom = wined3d_texture_get_level_height(src_texture, src_level) - s.bottom; src_rect = &s; @@ -12557,6 +12591,9 @@ static DWORD glsl_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_bli if (dst_texture->swapchain && (dst_texture->swapchain->front_buffer == dst_texture)) gl_info->gl_ops.gl.p_glFlush();
+ if (staging_texture) + wined3d_texture_decref(staging_texture); + return dst_location; }
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index ad4ed1c33a8..7a13b5883be 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -566,52 +566,6 @@ static void texture2d_download_data(struct wined3d_texture *texture, unsigned in heap_free(temporary_mem); }
-static HRESULT texture2d_upload_from_surface(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, - unsigned int dst_x, unsigned int dst_y, 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 src_level, dst_level; - struct wined3d_context *context; - struct wined3d_bo_address data; - UINT update_w, update_h; - - TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_x %u, dst_y %u, " - "src_texture %p, src_sub_resource_idx %u, src_box %s.\n", - dst_texture, dst_sub_resource_idx, dst_x, dst_y, - 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; - 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)) - wined3d_texture_prepare_texture(dst_texture, context, FALSE); - else - wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB); - wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE); - - src_level = src_sub_resource_idx % src_texture->level_count; - wined3d_texture_get_memory(src_texture, src_sub_resource_idx, &data, - src_texture->sub_resources[src_sub_resource_idx].locations); - wined3d_texture_get_pitch(src_texture, src_level, &src_row_pitch, &src_slice_pitch); - - wined3d_texture_upload_data(dst_texture, dst_sub_resource_idx, context, src_texture->resource.format, - src_box, wined3d_const_bo_address(&data), src_row_pitch, src_slice_pitch, dst_x, dst_y, 0, FALSE); - - 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); - - return WINED3D_OK; -} - /* See also float_16_to_32() in wined3d_private.h */ static inline unsigned short float_32_to_16(const float *in) { @@ -3459,18 +3413,16 @@ HRESULT texture2d_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_ TRACE("Not doing upload because the destination format needs conversion.\n"); else { - if (SUCCEEDED(texture2d_upload_from_surface(dst_texture, dst_sub_resource_idx, - dst_box->left, dst_box->top, src_texture, src_sub_resource_idx, src_box))) + wined3d_texture_upload_from_texture(dst_texture, dst_sub_resource_idx, dst_box->left, + dst_box->top, dst_box->front, src_texture, src_sub_resource_idx, src_box); + if (!wined3d_resource_is_offscreen(&dst_texture->resource)) { - if (!wined3d_resource_is_offscreen(&dst_texture->resource)) - { - context = context_acquire(device, dst_texture, dst_sub_resource_idx); - wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, - context, dst_texture->resource.draw_binding); - context_release(context); - } - return WINED3D_OK; + context = context_acquire(device, dst_texture, dst_sub_resource_idx); + wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, + context, dst_texture->resource.draw_binding); + context_release(context); } + return WINED3D_OK; } } else if (dst_swapchain && dst_swapchain->back_buffers diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index 427ed4f3570..dadcd0323a0 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -3488,3 +3488,49 @@ HRESULT CDECL wined3d_texture_release_dc(struct wined3d_texture *texture, unsign
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_texture(dst_texture, context, FALSE); + else + wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB); + wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE); + + src_level = src_sub_resource_idx % src_texture->level_count; + wined3d_texture_get_memory(src_texture, src_sub_resource_idx, &data, + src_texture->sub_resources[src_sub_resource_idx].locations); + wined3d_texture_get_pitch(src_texture, src_level, &src_row_pitch, &src_slice_pitch); + + wined3d_texture_upload_data(dst_texture, dst_sub_resource_idx, context, src_texture->resource.format, + src_box, wined3d_const_bo_address(&data), src_row_pitch, src_slice_pitch, dst_x, dst_y, dst_z, FALSE); + + 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); +} diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index e5a61e7af0e..24d923265e3 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -3305,6 +3305,9 @@ void wined3d_texture_upload_data(struct wined3d_texture *texture, unsigned int s struct wined3d_context *context, const struct wined3d_format *format, const struct wined3d_box *src_box, const struct wined3d_const_bo_address *data, unsigned int row_pitch, unsigned int slice_pitch, unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, BOOL srgb) DECLSPEC_HIDDEN; +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) DECLSPEC_HIDDEN; void wined3d_texture_validate_location(struct wined3d_texture *texture, unsigned int sub_resource_idx, DWORD location) DECLSPEC_HIDDEN;