Bug 655836: Flush surface A when B changes and A has a pending drawing command depending on B. r=jrmuizel

This commit is contained in:
Bas Schouten 2011-06-09 17:28:12 -04:00
Родитель cf3be6c34b
Коммит 496e39c64c
2 изменённых файлов: 61 добавлений и 1 удалений

Просмотреть файл

@ -49,6 +49,7 @@
#include "cairo-win32-refptr.h"
#include "cairo-d2d-private-fx.h"
#include "cairo-win32.h"
#include "cairo-list-private.h"
/* describes the type of the currently applied clip so that we can pop it */
struct d2d_clip;
@ -81,7 +82,11 @@ struct _cairo_d2d_surface {
textRenderingState(TEXT_RENDERING_UNINITIALIZED)
{
_cairo_clip_init (&this->clip);
cairo_list_init(&this->dependent_surfaces);
}
~_cairo_d2d_surface();
cairo_surface_t base;
/* Device used by this surface
@ -139,11 +144,23 @@ struct _cairo_d2d_surface {
RefPtr<ID3D10RenderTargetView> buffer_rt_view;
RefPtr<ID3D10ShaderResourceView> buffer_sr_view;
// Other d2d surfaces which depend on this one and need to be flushed if
// it is drawn to. This is required for situations where this surface is
// drawn to another surface, but may be modified before the other surface
// has flushed. When the flush of the other surface then happens and the
// drawing command is actually executed, the contents of this surface will
// no longer be what it was when the drawing command was issued.
cairo_list_t dependent_surfaces;
//cairo_surface_clipper_t clipper;
};
typedef struct _cairo_d2d_surface cairo_d2d_surface_t;
struct _cairo_d2d_surface_entry
{
cairo_list_t link;
cairo_d2d_surface_t *surface;
};
typedef HRESULT (WINAPI*D2D1CreateFactoryFunc)(
__in D2D1_FACTORY_TYPE factoryType,
__in REFIID iid,

Просмотреть файл

@ -1053,6 +1053,25 @@ _cairo_d2d_set_clip (cairo_d2d_surface_t *d2dsurf, cairo_clip_t *clip)
return CAIRO_STATUS_SUCCESS;
}
static void _cairo_d2d_add_dependent_surface(cairo_d2d_surface_t *surf, cairo_d2d_surface_t *user)
{
_cairo_d2d_surface_entry *entry = new _cairo_d2d_surface_entry;
entry->surface = user;
cairo_surface_reference(&user->base);
cairo_list_add(&entry->link, &surf->dependent_surfaces);
};
static void _cairo_d2d_flush_dependent_surfaces(cairo_d2d_surface_t *surf)
{
_cairo_d2d_surface_entry *entry, *next;
cairo_list_foreach_entry_safe(entry, next, _cairo_d2d_surface_entry, &surf->dependent_surfaces, link) {
_cairo_d2d_flush(entry->surface);
cairo_surface_destroy(&entry->surface->base);
delete entry;
}
cairo_list_init(&surf->dependent_surfaces);
}
/**
* Enter the state where the surface is ready for drawing. This will guarantee
* the surface is in the correct state, and the correct clipping area is pushed.
@ -1062,6 +1081,7 @@ _cairo_d2d_set_clip (cairo_d2d_surface_t *d2dsurf, cairo_clip_t *clip)
static void _begin_draw_state(cairo_d2d_surface_t* surface)
{
if (!surface->isDrawing) {
_cairo_d2d_flush_dependent_surfaces(surface);
surface->rt->BeginDraw();
surface->isDrawing = true;
}
@ -1778,6 +1798,9 @@ _cairo_d2d_create_brush_for_pattern(cairo_d2d_surface_t *d2dsurf,
_cairo_d2d_update_surface_bitmap(srcSurf);
_cairo_d2d_flush(srcSurf);
// Mark a dependency on the source surface.
_cairo_d2d_add_dependent_surface(srcSurf, d2dsurf);
if (pattern->extend == CAIRO_EXTEND_NONE) {
ID2D1Bitmap *srcSurfBitmap = srcSurf->surfaceBitmap;
d2dsurf->rt->CreateBitmap(
@ -2327,6 +2350,18 @@ _cairo_d2d_surface_init(cairo_d2d_surface_t *newSurf, cairo_d2d_device_t *d2d_de
cairo_addref_device(&d2d_device->base);
d2d_device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(newSurf);
}
_cairo_d2d_surface::~_cairo_d2d_surface()
{
_cairo_d2d_surface_entry *entry, *next;
cairo_list_foreach_entry_safe(entry, next, _cairo_d2d_surface_entry, &dependent_surfaces, link) {
// We do not need to flush, the contents of our texture has not changed,
// our users have their own reference and can just use it later.
cairo_surface_destroy(&entry->surface->base);
delete entry;
}
}
// Implementation
static cairo_surface_t*
@ -2793,6 +2828,8 @@ _cairo_d2d_blend_surface(cairo_d2d_surface_t *dst,
needsTransform = true;
}
_cairo_d2d_add_dependent_surface(src, dst);
D2D1_BITMAP_INTERPOLATION_MODE interpMode =
D2D1_BITMAP_INTERPOLATION_MODE_LINEAR;
@ -2986,6 +3023,8 @@ _cairo_d2d_get_temp_rt(cairo_d2d_surface_t *surf, cairo_clip_t *clip)
static cairo_int_status_t
_cairo_d2d_blend_temp_surface(cairo_d2d_surface_t *surf, cairo_operator_t op, ID2D1RenderTarget *rt, cairo_clip_t *clip, const cairo_rectangle_int_t *bounds = NULL)
{
_cairo_d2d_flush_dependent_surfaces(surf);
int numPaths = 0;
if (clip) {
cairo_clip_path_t *path = clip->path;
@ -3590,6 +3629,10 @@ _cairo_dwrite_manual_show_glyphs_on_d2d_surface(void *surface,
}
}
if (!dst->isDrawing) {
_cairo_d2d_flush_dependent_surfaces(dst);
}
_cairo_d2d_set_clip(dst, NULL);
dst->rt->Flush();