Closed Bug 573506 Opened 14 years ago Closed 14 years ago

[D2D] Expose GetDC and ReleaseDC on D2D surfaces

Categories

(Core :: Graphics, defect)

x86
Windows Vista
defect
Not set
normal

Tracking

()

RESOLVED FIXED

People

(Reporter: bas.schouten, Assigned: bas.schouten)

References

Details

Attachments

(1 file)

We should expose GetDC and ReleaseDC on D2D surfaces from thebes. In general past experiments have shown that performance characteristics of the interop is pretty bad. But we need them for rendering with WS_EX_LAYERED to support transparent surfaces and exposing them will also allow easier experimentation with using them in the future in some other places (like plugin rendering)
Blocks: 573507
Comment on attachment 452822 [details] [diff] [review] Expose GetDC and ReleaseDC from gfxD2DSurface >diff --git a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp >--- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp >+++ b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp >@@ -1435,17 +1435,18 @@ _cairo_d2d_create_similar(void *surfac > size.width = sizePixels.width * dpiX; > size.height = sizePixels.height * dpiY; > D2D1_BITMAP_PROPERTIES bitProps = D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, > alpha)); > D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, > D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, > alpha), > dpiX, >- dpiY); >+ dpiY, >+ D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE); inconsistent whitespace > if (sizePixels.width < 1) { > sizePixels.width = 1; > } > if (sizePixels.height < 1) { > sizePixels.height = 1; > } > RefPtr<IDXGISurface> oldDxgiSurface; >@@ -1460,16 +1461,17 @@ _cairo_d2d_create_similar(void *surfac > > if (content == CAIRO_CONTENT_ALPHA) { > desc.Format = DXGI_FORMAT_A8_UNORM; > } > > desc.MipLevels = 1; > desc.Usage = D3D10_USAGE_DEFAULT; > desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; >+ desc.MiscFlags = D3D10_RESOURCE_MISC_GDI_COMPATIBLE; > RefPtr<ID3D10Texture2D> texture; > RefPtr<IDXGISurface> dxgiSurface; > > hr = D3D10Factory::Device()->CreateTexture2D(&desc, NULL, &texture); > if (FAILED(hr)) { > goto FAIL_CREATESIMILAR; > } > >@@ -2243,16 +2245,17 @@ cairo_d2d_surface_create_for_hwnd(HWND w > swapDesc.BufferDesc.Height = sizePixels.height; > swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; > swapDesc.BufferDesc.RefreshRate.Numerator = 60; > swapDesc.BufferDesc.RefreshRate.Denominator = 1; > swapDesc.SampleDesc.Count = 1; > swapDesc.SampleDesc.Quality = 0; > swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; > swapDesc.BufferCount = 1; >+ swapDesc.Flags = DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE; > swapDesc.OutputWindow = wnd; > swapDesc.Windowed = TRUE; > > /** > * Create a swap chain, this swap chain will contain the backbuffer for > * the window we draw to. The front buffer is the full screen front > * buffer. > */ >@@ -2280,17 +2283,17 @@ cairo_d2d_surface_create_for_hwnd(HWND w > > size.width = sizePixels.width * dpiX; > size.height = sizePixels.height * dpiY; > > props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, > D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED), > dpiX, > dpiY, >- D2D1_RENDER_TARGET_USAGE_NONE); >+ D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE); > hr = D2DSurfFactory::Instance()->CreateDxgiSurfaceRenderTarget(newSurf->backBuf, > props, > &newSurf->rt); > if (FAILED(hr)) { > goto FAIL_HWND; > } > > bitProps = D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, >@@ -2348,16 +2351,17 @@ cairo_d2d_surface_create(cairo_format_t > CD3D10_TEXTURE2D_DESC desc( > dxgiformat, > sizePixels.width, > sizePixels.height > ); > desc.MipLevels = 1; > desc.Usage = D3D10_USAGE_DEFAULT; > desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; >+ desc.MiscFlags = D3D10_RESOURCE_MISC_GDI_COMPATIBLE; > > RefPtr<ID3D10Texture2D> texture; > RefPtr<IDXGISurface> dxgiSurface; > D2D1_BITMAP_PROPERTIES bitProps; > D2D1_RENDER_TARGET_PROPERTIES props; > > hr = D3D10Factory::Device()->CreateTexture2D(&desc, NULL, &texture); > >@@ -2370,16 +2374,17 @@ cairo_d2d_surface_create(cairo_format_t > /** Create the DXGI surface. */ > hr = newSurf->surface->QueryInterface(IID_IDXGISurface, (void**)&dxgiSurface); > if (FAILED(hr)) { > goto FAIL_CREATE; > } > > props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, > D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, alpha)); >+ props.usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE; > hr = D2DSurfFactory::Instance()->CreateDxgiSurfaceRenderTarget(dxgiSurface, > props, > &newSurf->rt); > > if (FAILED(hr)) { > goto FAIL_CREATE; > } > >@@ -2481,8 +2486,70 @@ cairo_d2d_has_support() > * FIXME: We should be able to fix this in the near future when we pass in > * a cairo_device_t to our surface creation functions. > */ > if (!D3D10Factory::Device() || !D2DSurfFactory::Instance()) { > return false; > } > return true; > } >+ >+HDC >+cairo_d2d_get_dc(cairo_surface_t *surface, cairo_bool_t retain_contents) >+{ >+ if (surface->type != CAIRO_SURFACE_TYPE_D2D) { >+ return NULL; >+ } >+ cairo_d2d_surface_t *d2dsurf = reinterpret_cast<cairo_d2d_surface_t*>(surface); >+ >+ /* We'll prevent a redundant begin/end draw calls here, only clips will be popped */ This comment doesn't make sense to me. >+ /* Clips aren't allowed as per MSDN docs */ >+ _cairo_d2d_surface_pop_clip(d2dsurf); >+ >+ if (!d2dsurf->isDrawing) { >+ /* GetDC must be called between BeginDraw/EndDraw */ >+ d2dsurf->rt->BeginDraw(); >+ d2dsurf->isDrawing = true; >+ } >+ >+ RefPtr<ID2D1GdiInteropRenderTarget> interopRT; >+ >+ d2dsurf->rt->QueryInterface(&interopRT); >+ >+ HDC retval; >+ HRESULT rv; >+ >+ rv = interopRT->GetDC(retain_contents ? D2D1_DC_INITIALIZE_MODE_COPY : >+ D2D1_DC_INITIALIZE_MODE_CLEAR, &retval); >+ >+ if (FAILED(rv)) { >+ return NULL; >+ } >+ >+ return retval; >+} >+ >+void >+cairo_d2d_release_dc(cairo_surface_t *surface, const cairo_rectangle_int_t *updated_rect) >+{ >+ if (surface->type != CAIRO_SURFACE_TYPE_D2D) { >+ return; >+ } >+ cairo_d2d_surface_t *d2dsurf = reinterpret_cast<cairo_d2d_surface_t*>(surface); >+ >+ RefPtr<ID2D1GdiInteropRenderTarget> interopRT; >+ >+ d2dsurf->rt->QueryInterface(&interopRT); >+ >+ if (!updated_rect) { >+ interopRT->ReleaseDC(NULL); >+ return; >+ } >+ >+ RECT r; >+ r.left = updated_rect->x; >+ r.top = updated_rect->y; >+ r.right = r.left + updated_rect->width; >+ r.bottom = r.top + updated_rect->height; >+ >+ interopRT->ReleaseDC(&r); >+} >\ No newline at end of file >diff --git a/gfx/cairo/cairo/src/cairo-win32.h b/gfx/cairo/cairo/src/cairo-win32.h >--- a/gfx/cairo/cairo/src/cairo-win32.h >+++ b/gfx/cairo/cairo/src/cairo-win32.h >@@ -172,16 +172,36 @@ void cairo_d2d_scroll(cairo_surface_t *s > /** > * Verify if D2D surfaces are actually supported. This will confirm the needed > * hardware is available. > * > * \return True if the support is available. If false surface creation will > * return error surfaces. > */ > cairo_bool_t cairo_d2d_has_support(); >+ >+/** >+ * Get a DC for the current render target. When selecting the retention option this >+ * call can be relatively slow, since it may require reading back contents from the >+ * hardware surface. >+ * >+ * \note This must be matched by a call to ReleaseDC! >+ * >+ * \param retain_contents If true the current contents of the RT is copied to the DC, >+ * otherwise the DC is initialized to transparent black. >+ */ >+HDC cairo_d2d_get_dc(cairo_surface_t *surface, cairo_bool_t retain_contents); >+ >+/** >+ * Release the DC acquired through GetDC(). Optionally an update region may be specified >+ * >+ * \param updated_rect The area of the DC that was updated, if null the entire dc will >+ * be updated. >+ */ >+void cairo_d2d_release_dc(cairo_surface_t *surcace, const cairo_rectangle_int_t *updated_rect); > #endif > > CAIRO_END_DECLS > > #else /* CAIRO_HAS_WIN32_SURFACE */ > # error Cairo was not compiled with support for the win32 backend > #endif /* CAIRO_HAS_WIN32_SURFACE */ > >diff --git a/gfx/thebes/public/gfxD2DSurface.h b/gfx/thebes/public/gfxD2DSurface.h >--- a/gfx/thebes/public/gfxD2DSurface.h >+++ b/gfx/thebes/public/gfxD2DSurface.h >@@ -55,11 +55,13 @@ public: > gfxD2DSurface(cairo_surface_t *csurf); > > virtual ~gfxD2DSurface(); > > > void Present(); > void Scroll(const nsIntPoint &aDelta, const nsIntRect &aClip); > >+ HDC GetDC(PRBool aRetainContents); >+ void ReleaseDC(const nsIntRect *aUpdatedRect); > }; > > #endif /* GFX_D2DSURFACE_H */ >diff --git a/gfx/thebes/src/gfxD2DSurface.cpp b/gfx/thebes/src/gfxD2DSurface.cpp >--- a/gfx/thebes/src/gfxD2DSurface.cpp >+++ b/gfx/thebes/src/gfxD2DSurface.cpp >@@ -68,8 +68,29 @@ gfxD2DSurface::Scroll(const nsIntPoint & > { > cairo_rectangle_t rect; > rect.x = aClip.x; > rect.y = aClip.y; > rect.width = aClip.width; > rect.height = aClip.height; > cairo_d2d_scroll(CairoSurface(), aDelta.x, aDelta.y, &rect); > } >+ >+HDC >+gfxD2DSurface::GetDC(PRBool aRetainContents) >+{ >+ return cairo_d2d_get_dc(CairoSurface(), aRetainContents); >+} >+ >+void >+gfxD2DSurface::ReleaseDC(const nsIntRect *aUpdatedRect) >+{ >+ if (!aUpdatedRect) { >+ return cairo_d2d_release_dc(CairoSurface(), NULL); >+ } >+ >+ cairo_rectangle_int_t rect; >+ rect.x = aUpdatedRect->x; >+ rect.y = aUpdatedRect->y; >+ rect.width = aUpdatedRect->width; >+ rect.height = aUpdatedRect->height; >+ cairo_d2d_release_dc(CairoSurface(), &rect); >+} >\ No newline at end of file
Attachment #452822 - Flags: review?(jmuizelaar) → review+
Status: ASSIGNED → RESOLVED
Closed: 14 years ago
Resolution: --- → FIXED
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: