Signed-off-by: Henri Verbeet hverbeet@codeweavers.com --- dlls/wined3d/device.c | 245 ------------------------------- dlls/wined3d/texture.c | 254 ++++++++++++++++++++++++++++++++- dlls/wined3d/wined3d_private.h | 3 - 3 files changed, 251 insertions(+), 251 deletions(-)
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index b81cc2f53fe..e16bd84164a 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -257,251 +257,6 @@ void device_context_remove(struct wined3d_device *device, struct wined3d_context 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(¤t_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(¤t_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 refcount = InterlockedIncrement(&device->ref); diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index 7ede5dea9da..5b0b070998b 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -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(¤t_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(¤t_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) { struct wined3d_resource *resource; @@ -5262,7 +5510,7 @@ static void ffp_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_de
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); } 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.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); } if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) { tmp_fb.render_targets[0] = NULL; 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); } } diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 9ced75711f3..2faeca4b35d 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -3431,9 +3431,6 @@ struct wined3d_device };
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; void device_context_remove(struct wined3d_device *device, struct wined3d_context *context) DECLSPEC_HIDDEN; void wined3d_device_create_default_samplers(struct wined3d_device *device,