wined3d: Move device_clear_render_targets() to texture.c.

Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Henri Verbeet 2020-04-27 20:18:44 +04:30 committed by Alexandre Julliard
parent cd94aa8fa8
commit ee8e4d2010
3 changed files with 251 additions and 251 deletions

View File

@ -257,251 +257,6 @@ void device_context_remove(struct wined3d_device *device, struct wined3d_context
device->contexts = new_array; device->contexts = new_array;
} }
static BOOL is_full_clear(const struct wined3d_texture *texture, unsigned int sub_resource_idx,
const RECT *draw_rect, const RECT *clear_rect)
{
unsigned int width, height, level;
level = sub_resource_idx % texture->level_count;
width = wined3d_texture_get_level_width(texture, level);
height = wined3d_texture_get_level_height(texture, level);
/* 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 device_clear_render_targets(struct wined3d_device *device, UINT rt_count, const struct wined3d_fb_state *fb,
UINT rect_count, const RECT *clear_rect, const RECT *draw_rect, DWORD flags, const struct wined3d_color *color,
float depth, DWORD 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;
const struct wined3d_gl_info *gl_info;
struct wined3d_context_gl *context_gl;
struct wined3d_texture *target = NULL;
UINT drawable_width, drawable_height;
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 color 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 dest 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)
{
struct wined3d_texture *rt = wined3d_texture_from_resource(rtv->resource);
if (flags & WINED3DCLEAR_TARGET && !is_full_clear(rt, rtv->sub_resource_idx,
draw_rect, rect_count ? clear_rect : NULL))
wined3d_texture_load_location(rt, rtv->sub_resource_idx, context, rtv->resource->draw_binding);
else
wined3d_texture_prepare_location(rt, rtv->sub_resource_idx, context, rtv->resource->draw_binding);
}
}
if (target)
{
render_offscreen = context->render_offscreen;
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_pow2_width(depth_stencil, ds_level);
drawable_height = wined3d_texture_get_level_pow2_height(depth_stencil, ds_level);
}
if (depth_stencil)
{
DWORD ds_location = render_offscreen ? dsv->resource->draw_binding : WINED3D_LOCATION_DRAWABLE;
struct wined3d_texture *ds = wined3d_texture_from_resource(dsv->resource);
if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)
&& !is_full_clear(ds, dsv->sub_resource_idx, draw_rect, rect_count ? clear_rect : NULL))
wined3d_texture_load_location(ds, dsv->sub_resource_idx, context, ds_location);
else
wined3d_texture_prepare_location(ds, dsv->sub_resource_idx, context, ds_location);
if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
{
wined3d_texture_validate_location(ds, dsv->sub_resource_idx, ds_location);
wined3d_texture_invalidate_location(ds, dsv->sub_resource_idx, ~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);
context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
}
gl_info->gl_ops.gl.p_glStencilMask(~0U);
context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
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_RENDER(WINED3D_RS_ZWRITEENABLE));
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];
struct wined3d_texture *texture;
if (!rtv)
continue;
if (rtv->resource->type == WINED3D_RTYPE_BUFFER)
{
FIXME("Not supported on buffer resources.\n");
continue;
}
texture = texture_from_resource(rtv->resource);
wined3d_texture_validate_location(texture, rtv->sub_resource_idx, rtv->resource->draw_binding);
wined3d_texture_invalidate_location(texture, rtv->sub_resource_idx, ~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, color);
color = &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(color->r, color->g, color->b, color->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(&current_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(&current_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);
}
ULONG CDECL wined3d_device_incref(struct wined3d_device *device) ULONG CDECL wined3d_device_incref(struct wined3d_device *device)
{ {
ULONG refcount = InterlockedIncrement(&device->ref); ULONG refcount = InterlockedIncrement(&device->ref);

View File

@ -5176,6 +5176,254 @@ static bool ffp_blit_supported(enum wined3d_blit_op blit_op, const struct wined3
} }
} }
static bool is_full_clear(const struct wined3d_texture *texture, unsigned int sub_resource_idx,
const RECT *draw_rect, const RECT *clear_rect)
{
unsigned int width, height, level;
level = sub_resource_idx % texture->level_count;
width = wined3d_texture_get_level_width(texture, level);
height = wined3d_texture_get_level_height(texture, level);
/* 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)
{
struct wined3d_texture *rt = wined3d_texture_from_resource(rtv->resource);
if (flags & WINED3DCLEAR_TARGET && !is_full_clear(rt, rtv->sub_resource_idx,
draw_rect, rect_count ? clear_rect : NULL))
wined3d_texture_load_location(rt, rtv->sub_resource_idx, context, rtv->resource->draw_binding);
else
wined3d_texture_prepare_location(rt, rtv->sub_resource_idx, context, rtv->resource->draw_binding);
}
}
if (target)
{
render_offscreen = context->render_offscreen;
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_pow2_width(depth_stencil, ds_level);
drawable_height = wined3d_texture_get_level_pow2_height(depth_stencil, ds_level);
}
if (depth_stencil)
{
DWORD ds_location = render_offscreen ? dsv->resource->draw_binding : WINED3D_LOCATION_DRAWABLE;
struct wined3d_texture *ds = wined3d_texture_from_resource(dsv->resource);
if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)
&& !is_full_clear(ds, dsv->sub_resource_idx, draw_rect, rect_count ? clear_rect : NULL))
wined3d_texture_load_location(ds, dsv->sub_resource_idx, context, ds_location);
else
wined3d_texture_prepare_location(ds, dsv->sub_resource_idx, context, ds_location);
if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
{
wined3d_texture_validate_location(ds, dsv->sub_resource_idx, ds_location);
wined3d_texture_invalidate_location(ds, dsv->sub_resource_idx, ~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);
context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
}
gl_info->gl_ops.gl.p_glStencilMask(~0u);
context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
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_RENDER(WINED3D_RS_ZWRITEENABLE));
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];
struct wined3d_texture *texture;
if (!rtv)
continue;
if (rtv->resource->type == WINED3D_RTYPE_BUFFER)
{
FIXME("Not supported on buffer resources.\n");
continue;
}
texture = texture_from_resource(rtv->resource);
wined3d_texture_validate_location(texture, rtv->sub_resource_idx, rtv->resource->draw_binding);
wined3d_texture_invalidate_location(texture, rtv->sub_resource_idx, ~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(&current_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(&current_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 ffp_blitter_use_cpu_clear(struct wined3d_rendertarget_view *view) static bool ffp_blitter_use_cpu_clear(struct wined3d_rendertarget_view *view)
{ {
struct wined3d_resource *resource; struct wined3d_resource *resource;
@ -5262,7 +5510,7 @@ static void ffp_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_de
if (have_identical_size) if (have_identical_size)
{ {
device_clear_render_targets(device, rt_count, fb, rect_count, ffp_blitter_clear_rendertargets(device, rt_count, fb, rect_count,
clear_rects, draw_rect, flags, colour, depth, stencil); clear_rects, draw_rect, flags, colour, depth, stencil);
} }
else else
@ -5274,14 +5522,14 @@ static void ffp_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_de
tmp_fb.render_targets[0] = view; tmp_fb.render_targets[0] = view;
tmp_fb.depth_stencil = NULL; tmp_fb.depth_stencil = NULL;
device_clear_render_targets(device, 1, &tmp_fb, rect_count, ffp_blitter_clear_rendertargets(device, 1, &tmp_fb, rect_count,
clear_rects, draw_rect, WINED3DCLEAR_TARGET, colour, depth, stencil); clear_rects, draw_rect, WINED3DCLEAR_TARGET, colour, depth, stencil);
} }
if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
{ {
tmp_fb.render_targets[0] = NULL; tmp_fb.render_targets[0] = NULL;
tmp_fb.depth_stencil = fb->depth_stencil; tmp_fb.depth_stencil = fb->depth_stencil;
device_clear_render_targets(device, 0, &tmp_fb, rect_count, ffp_blitter_clear_rendertargets(device, 0, &tmp_fb, rect_count,
clear_rects, draw_rect, flags & ~WINED3DCLEAR_TARGET, colour, depth, stencil); clear_rects, draw_rect, flags & ~WINED3DCLEAR_TARGET, colour, depth, stencil);
} }
} }

View File

@ -3431,9 +3431,6 @@ struct wined3d_device
}; };
void wined3d_device_cleanup(struct wined3d_device *device) DECLSPEC_HIDDEN; void wined3d_device_cleanup(struct wined3d_device *device) DECLSPEC_HIDDEN;
void device_clear_render_targets(struct wined3d_device *device, UINT rt_count, const struct wined3d_fb_state *fb,
UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags,
const struct wined3d_color *color, float depth, DWORD stencil) DECLSPEC_HIDDEN;
BOOL device_context_add(struct wined3d_device *device, struct wined3d_context *context) DECLSPEC_HIDDEN; BOOL device_context_add(struct wined3d_device *device, struct wined3d_context *context) DECLSPEC_HIDDEN;
void device_context_remove(struct wined3d_device *device, struct wined3d_context *context) DECLSPEC_HIDDEN; void device_context_remove(struct wined3d_device *device, struct wined3d_context *context) DECLSPEC_HIDDEN;
void wined3d_device_create_default_samplers(struct wined3d_device *device, void wined3d_device_create_default_samplers(struct wined3d_device *device,