Closed
Bug 580765
Opened 14 years ago
Closed 14 years ago
Support different porter duff operators with D2D
Categories
(Core :: Graphics, defect)
Tracking
()
RESOLVED
FIXED
People
(Reporter: bas.schouten, Assigned: bas.schouten)
References
Details
Attachments
(2 files, 3 obsolete files)
537 bytes,
patch
|
jrmuizel
:
review+
|
Details | Diff | Splinter Review |
88.96 KB,
patch
|
jrmuizel
:
review+
|
Details | Diff | Splinter Review |
With D2D we should really have proper support for the ADD operator and others. We have a good idea on how to approach this by rendering to a temporary surface and then blending back using D3D10 to use the operator we'd like to.
Assignee | ||
Comment 1•14 years ago
|
||
I've attached the majority of the code needed to do this. The patch currently attached is not done though: - Different BlendStates should be used to apply different operators (right now it still just does OVER, just in a more complicated way) - Support other operations than just fill - We may want to refactor all the static globals to go in a better place. - The final composition operation should just be bound to the extents of the mask of the operation that was executed. Rather than to the full surface, to conserve fill-rate
Assignee | ||
Comment 2•14 years ago
|
||
Another iteration, not finished yet.
Attachment #459142 -
Attachment is obsolete: true
Attachment #459454 -
Flags: review?(jmuizelaar)
Comment 3•14 years ago
|
||
Comment on attachment 459454 [details] [diff] [review] Manual composition support v0.2 > static ID3D10Device1 *mDeviceInstance; >+ static ID3D10Effect *mSampleEffect; >+ static ID3D10InputLayout *mInputLayout; >+ static ID3D10Buffer *mQuadBuffer; >+ static ID3D10RasterizerState *mRasterizerState; >+ static ID3D10BlendState *mBlendStates[MAX_OPERATORS]; This seems like stuff that should hang off a cairo_d2d_device_t
Updated•14 years ago
|
Attachment #459454 -
Flags: review?(jmuizelaar) → review-
Assignee | ||
Comment 4•14 years ago
|
||
Attachment #459454 -
Attachment is obsolete: true
Attachment #463063 -
Flags: review?(jmuizelaar)
Comment 5•14 years ago
|
||
(In reply to comment #4) > Created attachment 463063 [details] [diff] [review] > Add custom operator support and cairo_d2d_device_t v1 As you know, it would've been nice if these were separated out.
Comment 6•14 years ago
|
||
Comment on attachment 463063 [details] [diff] [review] Add custom operator support and cairo_d2d_device_t v1 >diff --git a/gfx/cairo/cairo/src/cairo-d2d-private.fx b/gfx/cairo/cairo/src/cairo-d2d-private.fx >new file mode 100644 >--- /dev/null >+++ b/gfx/cairo/cairo/src/cairo-d2d-private.fx >@@ -0,0 +1,46 @@ >+cbuffer cb0 >+{ >+ float4 QuadDesc; >+ float4 TexCoords; >+} Storing the vertex and texcoords ina constant buffer is a little unconventional. How about adding a comment about why you chose this approach. >diff --git a/gfx/cairo/cairo/src/cairo-d2d-private.h b/gfx/cairo/cairo/src/cairo-d2d-private.h >--- a/gfx/cairo/cairo/src/cairo-d2d-private.h >+++ b/gfx/cairo/cairo/src/cairo-d2d-private.h >@@ -44,28 +44,49 @@ >+ RefPtr<ID3D10RasterizerState> mRasterizerState; >+ RefPtr<ID3D10BlendState> mBlendStates[MAX_OPERATORS]; >+}; >+typedef struct _cairo_d2d_device cairo_d2d_device_t; >+ > struct _cairo_d2d_surface { > _cairo_d2d_surface() : d2d_clip(NULL), clipping(false), isDrawing(false), > textRenderingInit(true) > { > _cairo_clip_init (&this->clip); > } > > cairo_surface_t base; >+ /** Device used by this surface */ >+ cairo_d2d_device_t *device; In upstream cairo the device is in surface base class. It's probably worth making a note of that here. >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 >@@ -42,20 +42,310 @@ > extern "C" { > #include "cairo-win32.h" > #include "cairo-analysis-surface-private.h" > } > > // Required for using placement new. > #include <new> > >-ID2D1Factory *D2DSurfFactory::mFactoryInstance = NULL; >-ID3D10Device1 *D3D10Factory::mDeviceInstance = NULL; >+#define CAIRO_INT_STATUS_SUCCESS (cairo_int_status_t)CAIRO_STATUS_SUCCESS > >-#define CAIRO_INT_STATUS_SUCCESS (cairo_int_status_t)CAIRO_STATUS_SUCCESS >+struct Vertex >+{ >+ float position[2]; >+}; >+ >+/** >+ * Set a blending mode for an operator. This will also return a boolean that >+ * reports if for this blend mode the entire surface needs to be blended. This >+ * is true whenever the DEST blend is not ONE when src alpha is 0. >+ */ >+static cairo_int_status_t >+_cairo_d2d_set_operator(cairo_d2d_device_t *device, >+ cairo_operator_t op, >+ bool *require_full_blend) >+{ >+ if (op > MAX_OPERATORS) { Perhaps assert()? >+ // Eep! Someone forgot to update MAX_OPERATORS probably. >+ return CAIRO_INT_STATUS_UNSUPPORTED; >+ } >+ >+ if (device->mBlendStates[op]) { >+ device->mD3D10Device->OMSetBlendState(device->mBlendStates[op], NULL, 0xffffffff); >+ return CAIRO_INT_STATUS_SUCCESS; >+ } >+ >+ *require_full_blend = false; Seems like the caller can just call _cairo_operator_bounded_by_mask (op) or something similar instead of using the require_full_blend parameter. >+RefPtr<ID2D1RenderTarget> _cairo_d2d_get_temp_rt(cairo_d2d_surface_t *surf, cairo_clip_t *clip) >+{ >+ if (clip) { >+ cairo_clip_path_t *path = clip->path; >+ while (path) { Add a comment about the differences between this code and the existing code for pushing a clip. >+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) >+{ >+ int numPaths = 0; >+ cairo_clip_path_t *paths[128]; Where does 128 come from? >+ ID3D10EffectVectorVariable *texCoords = effect->GetVariableByName("TexCoords")->AsVector(); >+ >+ float quadDescVal[] = { -1.0f, 1.0f, 2.0f, -2.0f }; What is 2.0? Overall the drawing method could use some higher level documentation about how it works. The .fx file might be a good place to put it. > static cairo_int_status_t > _cairo_d2d_mask(void *surface, > cairo_operator_t op, >@@ -2460,63 +2952,79 @@ _cairo_d2d_stroke(void *surface, > RefPtr<ID2D1TransformedGeometry> trans_geom; >- D2DSurfFactory::Instance()->CreateTransformedGeometry(d2dpath, &inverse_mat, &trans_geom); >+ sD2DFactory->CreateTransformedGeometry(d2dpath, &inverse_mat, &trans_geom); > >- d2dsurf->rt->SetTransform(mat); >+ target_rt->SetTransform(mat); > > RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, > source); > if (!brush) { > return CAIRO_INT_STATUS_UNSUPPORTED; > } > >- d2dsurf->rt->DrawGeometry(trans_geom, brush, (FLOAT)style->line_width, strokeStyle); >+ target_rt->DrawGeometry(trans_geom, brush, (FLOAT)style->line_width, strokeStyle); > >- d2dsurf->rt->SetTransform(D2D1::Matrix3x2F::Identity()); >+ target_rt->SetTransform(D2D1::Matrix3x2F::Identity()); add a new line here >+ if (target_rt.get() != d2dsurf->rt.get()) { >+ D2D1_RECT_F bounds; >+ trans_geom->GetWidenedBounds((FLOAT)style->line_width, strokeStyle, D2D1::IdentityMatrix(), &bounds); >+ cairo_rectangle_int_t bound_rect; >+ bound_rect.x = (int)floor(bounds.left); >+ bound_rect.y = (int)floor(bounds.top); >+ bound_rect.width = (int)ceil(bounds.right) - bound_rect.x; >+ bound_rect.height = (int)ceil(bounds.bottom) - bound_rect.y; seems like you could use a function that constructed cairo_rectangle_int_t's from floating point values. >+ return _cairo_d2d_blend_temp_surface(d2dsurf, op, target_rt, clip, &bound_rect); >+ } >+ >@@ -2807,16 +3331,23 @@ cairo_d2d_surface_create(cairo_format_t > sizePixels.height = height; > >+ if (!sizePixels.width) { >+ sizePixels.width = 1; >+ } >+ if (!sizePixels.height) { >+ sizePixels.height = 1; >+ } >+ What's the relation of this change? > 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; > cairo_bool_t > 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; > } This seems broken. :) >diff --git a/gfx/cairo/cairo/src/cairo-dwrite-font.cpp b/gfx/cairo/cairo/src/cairo-dwrite-font.cpp >--- a/gfx/cairo/cairo/src/cairo-dwrite-font.cpp >+++ b/gfx/cairo/cairo/src/cairo-dwrite-font.cpp >@@ -1258,41 +1258,97 @@ _cairo_dwrite_show_glyphs_on_d2d_surface > cairo_d2d_surface_t *dst = reinterpret_cast<cairo_d2d_surface_t*>(surface); > > /* We can only handle dwrite fonts */ > //XXX: this is checked by at least one caller > if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_DWRITE) > return CAIRO_INT_STATUS_UNSUPPORTED; > > >- /* We can only handle operator SOURCE or OVER with the destination >+ /* We can only handle operator SOURCE, OVER or ADD with the destination > * having no alpha */ Why only ADD? >- if (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) >- return CAIRO_INT_STATUS_UNSUPPORTED; >+ if (op == CAIRO_OPERATOR_SOURCE) { >+ return CAIRO_INT_STATUS_UNSUPPORTED; >+ } > >- _cairo_d2d_begin_draw_state (dst); >- _cairo_d2d_set_clip (dst, clip); >+ RefPtr<ID2D1RenderTarget> target_rt = dst->rt; >+ cairo_rectangle_int_t fontArea; >+#ifndef ALWAYS_MANUAL_COMPOSITE >+ if (op != CAIRO_OPERATOR_OVER) { >+#endif >+ target_rt = _cairo_d2d_get_temp_rt(dst, clip); >+ >+ if (!target_rt) { >+ return CAIRO_INT_STATUS_UNSUPPORTED; >+ } >+ >+ /* Needed to calculate bounding box for efficient blitting */ [snip] Why don't we use CreateGlyphRunAnalysis for computing this area? >+ >+#ifndef ALWAYS_MANUAL_COMPOSITE >+ } else { >+ _cairo_d2d_begin_draw_state(dst); >+ status = (cairo_int_status_t)_cairo_d2d_set_clip (dst, clip); >+ >+ if (unlikely(status)) >+ return status; >+ } >+#endif > > D2D1_TEXT_ANTIALIAS_MODE cleartype = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; > >- if (dst->base.content != CAIRO_CONTENT_COLOR) { >+ if (dst->base.content != CAIRO_CONTENT_COLOR || dst->rt.get() != target_rt.get()) { probably worth adding a comment about the new condition. It might also be worth giving this condition a name. i.e. store it in a variable with a more meaningful name. >@@ -1344,17 +1400,17 @@ _cairo_dwrite_show_glyphs_on_d2d_surface >diff --git a/gfx/cairo/cairo/src/cairo-win32-refptr.h b/gfx/cairo/cairo/src/cairo-win32-refptr.h >--- a/gfx/cairo/cairo/src/cairo-win32-refptr.h >+++ b/gfx/cairo/cairo/src/cairo-win32-refptr.h Looks like this could be a separate patch?
Attachment #463063 -
Flags: review?(jmuizelaar) → review-
Assignee | ||
Comment 7•14 years ago
|
||
Attachment #464207 -
Flags: review?(jmuizelaar)
Assignee | ||
Comment 8•14 years ago
|
||
Updated in accordance with comments.
Attachment #463063 -
Attachment is obsolete: true
Attachment #464208 -
Flags: review?(jmuizelaar)
Comment 9•14 years ago
|
||
(In reply to comment #7) > Created attachment 464207 [details] [diff] [review] > Allow dereferencing const What's the use case for this?
Comment 10•14 years ago
|
||
Comment on attachment 464208 [details] [diff] [review] Add custom operator support and cairo_d2d_device_t v2 >+++ b/gfx/cairo/cairo/src/cairo-d2d-private.fx >@@ -0,0 +1,56 @@ >+// We store vertex coordinates and the quad shape in a constant buffer, this is >+// easy to update and will prevent us from having to reshape the vertex buffer >+// feeding the pipeline. What does reshape the vertex buffer mean?
Assignee | ||
Comment 11•14 years ago
|
||
(In reply to comment #10) > Comment on attachment 464208 [details] [diff] [review] > Add custom operator support and cairo_d2d_device_t v2 > > > >+++ b/gfx/cairo/cairo/src/cairo-d2d-private.fx > >@@ -0,0 +1,56 @@ > >+// We store vertex coordinates and the quad shape in a constant buffer, this is > >+// easy to update and will prevent us from having to reshape the vertex buffer > >+// feeding the pipeline. > > What does reshape the vertex buffer mean? Locking it and changing the coordinates of the vertices.
Comment 12•14 years ago
|
||
(In reply to comment #11) > (In reply to comment #10) > > Comment on attachment 464208 [details] [diff] [review] [details] > > Add custom operator support and cairo_d2d_device_t v2 > > > > > > >+++ b/gfx/cairo/cairo/src/cairo-d2d-private.fx > > >@@ -0,0 +1,56 @@ > > >+// We store vertex coordinates and the quad shape in a constant buffer, this is > > >+// easy to update and will prevent us from having to reshape the vertex buffer > > >+// feeding the pipeline. > > > > What does reshape the vertex buffer mean? > > Locking it and changing the coordinates of the vertices. I wouldn't expect this to be any more expensive than updating a constant buffer. Do you have reason to believe that it is?
Assignee | ||
Comment 13•14 years ago
|
||
(In reply to comment #12) > (In reply to comment #11) > > (In reply to comment #10) > > > Comment on attachment 464208 [details] [diff] [review] [details] [details] > > > Add custom operator support and cairo_d2d_device_t v2 > > > > > > > > > >+++ b/gfx/cairo/cairo/src/cairo-d2d-private.fx > > > >@@ -0,0 +1,56 @@ > > > >+// We store vertex coordinates and the quad shape in a constant buffer, this is > > > >+// easy to update and will prevent us from having to reshape the vertex buffer > > > >+// feeding the pipeline. > > > > > > What does reshape the vertex buffer mean? > > > > Locking it and changing the coordinates of the vertices. > > I wouldn't expect this to be any more expensive than updating a constant > buffer. Do you have reason to believe that it is? Updating a constant buffer used to be more expensive, but it's been ages since I tested. Possibly allocating a constant buffer in D3DPOOL_DEFAULT with D3DUSAGE_DYNAMIC where the hardware allows this, would be just as fast. I might note this method also allows a slightly prettier API as it can be set in a single call rather than a combination of Lock, set all the bits after some casting, Unlock.
Assignee | ||
Comment 14•14 years ago
|
||
(In reply to comment #13) > (In reply to comment #12) > > (In reply to comment #11) > > > (In reply to comment #10) > Updating a constant buffer used to be more expensive, but it's been ages since > I tested. Used to be less expensive, that is.
Comment 15•14 years ago
|
||
(In reply to comment #13) > (In reply to comment #12) > Updating a constant buffer used to be more expensive, but it's been ages since > I tested. Possibly allocating a constant buffer in D3DPOOL_DEFAULT with > D3DUSAGE_DYNAMIC where the hardware allows this, would be just as fast. I might > note this method also allows a slightly prettier API as it can be set in a > single call rather than a combination of Lock, set all the bits after some > casting, Unlock. Perhaps, adjust the comment to focus more on the aesthetics then instead of "reshaping" because it's not clear that "reshaping" is something we want to avoid.
Comment 16•14 years ago
|
||
Comment on attachment 464207 [details] [diff] [review] Allow dereferencing const As discussed this isn't needed anymore but doesn't hurt either.
Attachment #464207 -
Flags: review?(jmuizelaar) → review+
Comment 17•14 years ago
|
||
Comment on attachment 464208 [details] [diff] [review] Add custom operator support and cairo_d2d_device_t v2 I only did a quick review this time through, but things seem sane enough.
Attachment #464208 -
Flags: review?(jmuizelaar) → review+
Assignee | ||
Comment 18•14 years ago
|
||
Pushed http://hg.mozilla.org/mozilla-central/rev/da79df639747. Pushed http://hg.mozilla.org/mozilla-central/rev/55fd62eef09e.
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.
Description
•