wined3d: Use staging resources to blit from CPU resources in the GLSL blitter.

Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Matteo Bruni 2018-04-16 17:59:28 +04:30 committed by Alexandre Julliard
parent aa59d40a18
commit 29d506939e
4 changed files with 100 additions and 62 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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;