wined3d: Store the context's current rendertarget as a texture and sub-resource index.

Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Henri Verbeet 2016-03-29 16:45:32 +02:00 committed by Alexandre Julliard
parent 5f05acfcff
commit d6e2f650d5
4 changed files with 119 additions and 73 deletions

View File

@ -852,22 +852,26 @@ static void context_queue_fbo_entry_destruction(struct wined3d_context *context,
void context_resource_released(const struct wined3d_device *device,
struct wined3d_resource *resource, enum wined3d_resource_type type)
{
struct wined3d_texture *texture;
UINT i;
struct wined3d_surface *surface;
if (!device->d3d_initialized)
return;
switch (type)
{
case WINED3D_RTYPE_SURFACE:
surface = surface_from_resource(resource);
case WINED3D_RTYPE_TEXTURE_2D:
case WINED3D_RTYPE_TEXTURE_3D:
texture = wined3d_texture_from_resource(resource);
for (i = 0; i < device->context_count; ++i)
{
struct wined3d_context *context = device->contexts[i];
if (context->current_rt == surface)
context->current_rt = NULL;
if (context->current_rt.texture == texture)
{
context->current_rt.texture = NULL;
context->current_rt.sub_resource_idx = 0;
}
}
break;
@ -1318,7 +1322,8 @@ void context_release(struct wined3d_context *context)
* A to avoid breaking caller code. */
void context_restore(struct wined3d_context *context, struct wined3d_surface *restore)
{
if (context->current_rt != restore)
if (context->current_rt.texture != restore->container
|| context->current_rt.sub_resource_idx != surface_get_sub_resource_idx(restore))
{
context_release(context);
context = context_acquire(restore->container->resource.device, restore);
@ -1777,7 +1782,8 @@ struct wined3d_context *context_create(struct wined3d_swapchain *swapchain,
}
ret->swapchain = swapchain;
ret->current_rt = target->sub_resources[0].u.surface;
ret->current_rt.texture = target;
ret->current_rt.sub_resource_idx = 0;
ret->tid = GetCurrentThreadId();
ret->render_offscreen = wined3d_resource_is_offscreen(&target->resource);
@ -2032,9 +2038,10 @@ static void set_blit_dimension(const struct wined3d_gl_info *gl_info, UINT width
static void context_get_rt_size(const struct wined3d_context *context, SIZE *size)
{
const struct wined3d_surface *rt = context->current_rt;
const struct wined3d_texture *rt = context->current_rt.texture;
unsigned int level;
if (rt->container->swapchain && rt->container->swapchain->front_buffer == rt->container)
if (rt->swapchain && rt->swapchain->front_buffer == rt)
{
RECT window_size;
@ -2045,8 +2052,9 @@ static void context_get_rt_size(const struct wined3d_context *context, SIZE *siz
return;
}
size->cx = rt->resource.width;
size->cy = rt->resource.height;
level = context->current_rt.sub_resource_idx % rt->level_count;
size->cx = wined3d_texture_get_level_width(rt, level);
size->cy = wined3d_texture_get_level_height(rt, level);
}
/*****************************************************************************
@ -2413,7 +2421,8 @@ static void context_validate_onscreen_formats(struct wined3d_context *context,
const struct wined3d_rendertarget_view *depth_stencil)
{
/* Onscreen surfaces are always in a swapchain */
struct wined3d_swapchain *swapchain = context->current_rt->container->swapchain;
struct wined3d_swapchain *swapchain = context->current_rt.texture->swapchain;
struct wined3d_surface *surface;
if (context->render_offscreen || !depth_stencil) return;
if (match_depth_stencil_format(swapchain->ds_format, depth_stencil->format)) return;
@ -2424,7 +2433,8 @@ static void context_validate_onscreen_formats(struct wined3d_context *context,
WARN("Depth stencil format is not supported by WGL, rendering the backbuffer in an FBO\n");
/* The currently active context is the necessary context to access the swapchain's onscreen buffers */
surface_load_location(context->current_rt, context, WINED3D_LOCATION_TEXTURE_RGB);
surface = context->current_rt.texture->sub_resources[context->current_rt.sub_resource_idx].u.surface;
surface_load_location(surface, context, WINED3D_LOCATION_TEXTURE_RGB);
swapchain->render_to_fbo = TRUE;
swapchain_update_draw_bindings(swapchain);
context_set_render_offscreen(context, TRUE);
@ -2459,7 +2469,8 @@ static DWORD context_generate_rt_mask_no_fbo(const struct wined3d_context *conte
/* Context activation is done by the caller. */
void context_apply_blit_state(struct wined3d_context *context, const struct wined3d_device *device)
{
struct wined3d_surface *rt = context->current_rt;
struct wined3d_texture *rt = context->current_rt.texture;
struct wined3d_surface *surface;
DWORD rt_mask, *cur_mask;
if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
@ -2468,10 +2479,11 @@ void context_apply_blit_state(struct wined3d_context *context, const struct wine
if (context->render_offscreen)
{
wined3d_texture_load(rt->container, context, FALSE);
wined3d_texture_load(rt, context, FALSE);
context_apply_fbo_state_blit(context, GL_FRAMEBUFFER, rt, NULL, rt->container->resource.draw_binding);
if (rt->container->resource.format->id != WINED3DFMT_NULL)
surface = rt->sub_resources[context->current_rt.sub_resource_idx].u.surface;
context_apply_fbo_state_blit(context, GL_FRAMEBUFFER, surface, NULL, rt->resource.draw_binding);
if (rt->resource.format->id != WINED3DFMT_NULL)
rt_mask = 1;
else
rt_mask = 0;
@ -2480,12 +2492,12 @@ void context_apply_blit_state(struct wined3d_context *context, const struct wine
{
context->current_fbo = NULL;
context_bind_fbo(context, GL_FRAMEBUFFER, 0);
rt_mask = context_generate_rt_mask_from_resource(&rt->container->resource);
rt_mask = context_generate_rt_mask_from_resource(&rt->resource);
}
}
else
{
rt_mask = context_generate_rt_mask_no_fbo(context, rt->container);
rt_mask = context_generate_rt_mask_no_fbo(context, rt);
}
cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
@ -3419,34 +3431,38 @@ BOOL context_apply_draw_state(struct wined3d_context *context, struct wined3d_de
return TRUE;
}
static void context_setup_target(struct wined3d_context *context, struct wined3d_surface *target)
static void context_setup_target(struct wined3d_context *context,
struct wined3d_texture *texture, unsigned int sub_resource_idx)
{
BOOL old_render_offscreen = context->render_offscreen, render_offscreen;
render_offscreen = wined3d_resource_is_offscreen(&target->container->resource);
if (context->current_rt == target && render_offscreen == old_render_offscreen) return;
render_offscreen = wined3d_resource_is_offscreen(&texture->resource);
if (context->current_rt.texture == texture
&& context->current_rt.sub_resource_idx == sub_resource_idx
&& render_offscreen == old_render_offscreen)
return;
/* To compensate the lack of format switching with some offscreen rendering methods and on onscreen buffers
* the alpha blend state changes with different render target formats. */
if (!context->current_rt)
if (!context->current_rt.texture)
{
context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE));
}
else
{
const struct wined3d_format *old = context->current_rt->container->resource.format;
const struct wined3d_format *new = target->container->resource.format;
const struct wined3d_format *old = context->current_rt.texture->resource.format;
const struct wined3d_format *new = texture->resource.format;
if (old->id != new->id)
{
/* Disable blending when the alpha mask has changed and when a format doesn't support blending. */
if ((old->alpha_size && !new->alpha_size) || (!old->alpha_size && new->alpha_size)
|| !(target->container->resource.format_flags & WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING))
|| !(texture->resource.format_flags & WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING))
context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE));
/* Update sRGB writing when switching between formats that do/do not support sRGB writing */
if ((context->current_rt->container->resource.format_flags & WINED3DFMT_FLAG_SRGB_WRITE)
!= (target->container->resource.format_flags & WINED3DFMT_FLAG_SRGB_WRITE))
if ((context->current_rt.texture->resource.format_flags & WINED3DFMT_FLAG_SRGB_WRITE)
!= (texture->resource.format_flags & WINED3DFMT_FLAG_SRGB_WRITE))
context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SRGBWRITEENABLE));
}
@ -3458,25 +3474,32 @@ static void context_setup_target(struct wined3d_context *context, struct wined3d
* has to be called with the old rendertarget active, otherwise a
* wrong drawable is read. */
if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
&& old_render_offscreen && context->current_rt != target)
&& old_render_offscreen && (context->current_rt.texture != texture
|| context->current_rt.sub_resource_idx != sub_resource_idx))
{
struct wined3d_texture *texture = context->current_rt->container;
unsigned int prev_sub_resource_idx = context->current_rt.sub_resource_idx;
struct wined3d_texture *prev_texture = context->current_rt.texture;
struct wined3d_surface *prev_surface;
/* Read the back buffer of the old drawable into the destination texture. */
if (texture->texture_srgb.name)
wined3d_texture_load(texture, context, TRUE);
wined3d_texture_load(texture, context, FALSE);
surface_invalidate_location(context->current_rt, WINED3D_LOCATION_DRAWABLE);
if (prev_texture->texture_srgb.name)
wined3d_texture_load(prev_texture, context, TRUE);
wined3d_texture_load(prev_texture, context, FALSE);
prev_surface = prev_texture->sub_resources[prev_sub_resource_idx].u.surface;
surface_invalidate_location(prev_surface, WINED3D_LOCATION_DRAWABLE);
}
}
context->current_rt = target;
context->current_rt.texture = texture;
context->current_rt.sub_resource_idx = sub_resource_idx;
context_set_render_offscreen(context, render_offscreen);
}
struct wined3d_context *context_acquire(const struct wined3d_device *device, struct wined3d_surface *target)
{
struct wined3d_context *current_context = context_get_current();
struct wined3d_texture *target_texture;
unsigned int target_sub_resource_idx;
struct wined3d_context *context;
TRACE("device %p, target %p.\n", device, target);
@ -3484,33 +3507,41 @@ struct wined3d_context *context_acquire(const struct wined3d_device *device, str
if (current_context && current_context->destroyed)
current_context = NULL;
if (!target)
if (target)
{
target_texture = target->container;
target_sub_resource_idx = surface_get_sub_resource_idx(target);
}
else
{
if (current_context
&& current_context->current_rt
&& current_context->current_rt.texture
&& current_context->swapchain->device == device)
{
target = current_context->current_rt;
target_texture = current_context->current_rt.texture;
target_sub_resource_idx = current_context->current_rt.sub_resource_idx;
}
else
{
struct wined3d_swapchain *swapchain = device->swapchains[0];
if (swapchain->back_buffers)
target = surface_from_resource(wined3d_texture_get_sub_resource(swapchain->back_buffers[0], 0));
target_texture = swapchain->back_buffers[0];
else
target = surface_from_resource(wined3d_texture_get_sub_resource(swapchain->front_buffer, 0));
target_texture = swapchain->front_buffer;
target_sub_resource_idx = 0;
}
}
if (current_context && current_context->current_rt == target)
if (current_context && current_context->current_rt.texture == target_texture)
{
context = current_context;
}
else if (target->container->swapchain)
else if (target_texture->swapchain)
{
TRACE("Rendering onscreen.\n");
context = swapchain_get_context(target->container->swapchain);
context = swapchain_get_context(target_texture->swapchain);
}
else
{
@ -3526,7 +3557,7 @@ struct wined3d_context *context_acquire(const struct wined3d_device *device, str
context_enter(context);
context_update_window(context);
context_setup_target(context, target);
context_setup_target(context, target_texture, target_sub_resource_idx);
if (!context->valid) return context;
if (context != current_context)

View File

@ -58,7 +58,7 @@ static enum wined3d_event_query_result wined3d_event_query_test(const struct win
return WINED3D_EVENT_QUERY_WRONG_THREAD;
}
context = context_acquire(device, query->context->current_rt);
context = context_acquire(device, context_get_rt_surface(query->context));
gl_info = context->gl_info;
if (gl_info->supported[ARB_SYNC])
@ -132,7 +132,7 @@ enum wined3d_event_query_result wined3d_event_query_finish(const struct wined3d_
return WINED3D_EVENT_QUERY_WRONG_THREAD;
}
context = context_acquire(device, query->context->current_rt);
context = context_acquire(device, context_get_rt_surface(query->context));
if (gl_info->supported[ARB_SYNC])
{
@ -192,7 +192,7 @@ void wined3d_event_query_issue(struct wined3d_event_query *query, const struct w
}
else
{
context = context_acquire(device, query->context->current_rt);
context = context_acquire(device, context_get_rt_surface(query->context));
}
}
else
@ -348,7 +348,7 @@ static HRESULT wined3d_occlusion_query_ops_get_data(struct wined3d_query *query,
return S_OK;
}
context = context_acquire(query->device, oq->context->current_rt);
context = context_acquire(device, context_get_rt_surface(oq->context));
GL_EXTCALL(glGetQueryObjectuiv(oq->id, GL_QUERY_RESULT_AVAILABLE, &available));
checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)");
@ -490,7 +490,7 @@ static HRESULT wined3d_occlusion_query_ops_issue(struct wined3d_query *query, DW
}
else
{
context = context_acquire(query->device, oq->context->current_rt);
context = context_acquire(device, context_get_rt_surface(oq->context));
GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
checkGLcall("glEndQuery()");
@ -522,7 +522,7 @@ static HRESULT wined3d_occlusion_query_ops_issue(struct wined3d_query *query, DW
}
else
{
context = context_acquire(query->device, oq->context->current_rt);
context = context_acquire(device, context_get_rt_surface(oq->context));
GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
checkGLcall("glEndQuery()");
@ -578,7 +578,7 @@ static HRESULT wined3d_timestamp_query_ops_get_data(struct wined3d_query *query,
return S_OK;
}
context = context_acquire(query->device, tq->context->current_rt);
context = context_acquire(device, context_get_rt_surface(tq->context));
GL_EXTCALL(glGetQueryObjectuiv(tq->id, GL_QUERY_RESULT_AVAILABLE, &available));
checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)");

View File

@ -108,8 +108,8 @@ void surface_get_drawable_size(const struct wined3d_surface *surface, const stru
/* The drawable size of an onscreen drawable is the surface size.
* (Actually: The window size, but the surface is created in window
* size.) */
*width = context->current_rt->resource.width;
*height = context->current_rt->resource.height;
*width = context->current_rt.texture->resource.width;
*height = context->current_rt.texture->resource.height;
}
else if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER)
{
@ -123,10 +123,13 @@ void surface_get_drawable_size(const struct wined3d_surface *surface, const stru
}
else
{
struct wined3d_surface *rt;
/* The drawable size of an FBO target is the OpenGL texture size,
* which is the power of two size. */
*width = context->current_rt->pow2Width;
*height = context->current_rt->pow2Height;
rt = context->current_rt.texture->sub_resources[context->current_rt.sub_resource_idx].u.surface;
*width = rt->pow2Width;
*height = rt->pow2Height;
}
}
@ -675,11 +678,11 @@ static void surface_blt_fbo(const struct wined3d_device *device,
else if (dst_location == WINED3D_LOCATION_DRAWABLE) required_rt = dst_surface;
else required_rt = NULL;
if (required_rt && required_rt != old_ctx->current_rt)
{
restore_rt = old_ctx->current_rt;
restore_rt = context_get_rt_surface(old_ctx);
if (restore_rt != required_rt)
context = context_acquire(device, required_rt);
}
else
restore_rt = NULL;
if (!context->valid)
{
@ -1852,11 +1855,11 @@ static void read_from_framebuffer(struct wined3d_surface *surface,
surface_get_memory(surface, &data, dst_location);
if (surface != old_ctx->current_rt)
{
restore_rt = old_ctx->current_rt;
restore_rt = context_get_rt_surface(old_ctx);
if (restore_rt != surface)
context = context_acquire(device, surface);
}
else
restore_rt = NULL;
context_apply_blit_state(context, device);
gl_info = context->gl_info;
@ -1962,11 +1965,11 @@ void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb, struct
struct wined3d_context *context = old_ctx;
struct wined3d_surface *restore_rt = NULL;
if (old_ctx->current_rt != surface)
{
restore_rt = old_ctx->current_rt;
restore_rt = context_get_rt_surface(old_ctx);
if (restore_rt != surface)
context = context_acquire(device, surface);
}
else
restore_rt = NULL;
gl_info = context->gl_info;
device_invalidate_state(device, STATE_FRAMEBUFFER);
@ -2485,12 +2488,11 @@ static void surface_blt_to_drawable(const struct wined3d_device *device,
src_rect = *src_rect_in;
dst_rect = *dst_rect_in;
if (old_ctx->current_rt != dst_surface)
{
restore_rt = old_ctx->current_rt;
restore_rt = context_get_rt_surface(old_ctx);
if (restore_rt != dst_surface)
context = context_acquire(device, dst_surface);
}
else
restore_rt = NULL;
gl_info = context->gl_info;

View File

@ -1282,7 +1282,11 @@ struct wined3d_context
DWORD isStateDirty[STATE_HIGHEST / (sizeof(DWORD) * CHAR_BIT) + 1]; /* Bitmap to find out quickly if a state is dirty */
struct wined3d_swapchain *swapchain;
struct wined3d_surface *current_rt;
struct
{
struct wined3d_texture *texture;
unsigned int sub_resource_idx;
} current_rt;
DWORD tid; /* Thread ID which owns this context at the moment */
/* Stores some information about the context state for optimization */
@ -3473,6 +3477,15 @@ static inline BOOL can_use_texture_swizzle(const struct wined3d_gl_info *gl_info
&& !is_scaling_fixup(format->color_fixup);
}
static inline struct wined3d_surface *context_get_rt_surface(const struct wined3d_context *context)
{
struct wined3d_texture *texture = context->current_rt.texture;
if (!texture)
return NULL;
return texture->sub_resources[context->current_rt.sub_resource_idx].u.surface;
}
/* The WNDCLASS-Name for the fake window which we use to retrieve the GL capabilities */
#define WINED3D_OPENGL_WINDOW_CLASS_NAME "WineD3D_OpenGL"