From: Francisco Casas fcasas@codeweavers.com
Some applications generate many device contexts each render frame. Thus, compling these shaders each time this happens might make them laggy. --- dlls/d2d1/d2d1_private.h | 5 +- dlls/d2d1/device.c | 1049 +++++++++++++++++++------------------- dlls/d2d1/factory.c | 6 +- 3 files changed, 543 insertions(+), 517 deletions(-)
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index d6dad474cf3..46999eaa272 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -615,6 +615,9 @@ struct d2d_device IDXGIDevice *dxgi_device; bool allow_get_dxgi_device;
+ ID3D10Blob *precompiled_shape_vs[D2D_SHAPE_TYPE_COUNT]; + ID3D10Blob *precompiled_shape_ps; + struct d2d_indexed_objects shaders; };
@@ -715,7 +718,7 @@ void d2d_factory_register_effect(struct d2d_factory *factory, struct d2d_effect_registration *effect); HRESULT d2d_effect_property_get_uint32_value(const struct d2d_effect_properties *properties, const struct d2d_effect_property *prop, UINT32 *value); -void d2d_device_init(struct d2d_device *device, ID2D1Factory1 *factory, IDXGIDevice *dxgi_device, +HRESULT d2d_device_init(struct d2d_device *device, ID2D1Factory1 *factory, IDXGIDevice *dxgi_device, bool allow_get_dxgi_device);
struct d2d_transform diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c index 99f1fc10450..4780acb3bec 100644 --- a/dlls/d2d1/device.c +++ b/dlls/d2d1/device.c @@ -3454,6 +3454,498 @@ static const struct ID2D1GdiInteropRenderTargetVtbl d2d_gdi_interop_render_targe d2d_gdi_interop_render_target_ReleaseDC, };
+ +static const D3D11_INPUT_ELEMENT_DESC shape_il_desc_outline[] = +{ + {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"PREV", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"NEXT", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0}, +}; +static const D3D11_INPUT_ELEMENT_DESC shape_il_desc_curve_outline[] = +{ + {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"P", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"P", 1, DXGI_FORMAT_R32G32_FLOAT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"P", 2, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"PREV", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"NEXT", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 40, D3D11_INPUT_PER_VERTEX_DATA, 0}, +}; +static const D3D11_INPUT_ELEMENT_DESC shape_il_desc_triangle[] = +{ + {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, +}; +static const D3D11_INPUT_ELEMENT_DESC shape_il_desc_curve[] = +{ + {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0}, +}; +static const char shape_vs_code_outline[] = + "float3x2 transform_geometry;\n" + "float stroke_width;\n" + "float4 transform_rtx;\n" + "float4 transform_rty;\n" + "\n" + "struct output\n" + "{\n" + " float2 p : WORLD_POSITION;\n" + " float4 b : BEZIER;\n" + " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n" + " float4 position : SV_POSITION;\n" + "};\n" + "\n" + "/* The lines PₚᵣₑᵥP₀ and P₀Pₙₑₓₜ, both offset by ±½w, intersect each other at:\n" + " *\n" + " * Pᵢ = P₀ ± w · ½q⃑ᵢ.\n" + " *\n" + " * Where:\n" + " *\n" + " * q⃑ᵢ = q̂ₚᵣₑᵥ⊥ + tan(½θ) · -q̂ₚᵣₑᵥ\n" + " * θ = ∠PₚᵣₑᵥP₀Pₙₑₓₜ\n" + " * q⃑ₚᵣₑᵥ = P₀ - Pₚᵣₑᵥ */\n" + "void main(float2 position : POSITION, float2 prev : PREV, float2 next : NEXT, out struct output o)\n" + "{\n" + " float2 q_prev, q_next, v_p, q_i;\n" + " float2x2 geom;\n" + " float l;\n" + "\n" + " o.stroke_transform = float2x2(transform_rtx.xy, transform_rty.xy) * stroke_width * 0.5f;\n" + "\n" + " geom = float2x2(transform_geometry._11_21, transform_geometry._12_22);\n" + " q_prev = normalize(mul(geom, prev));\n" + " q_next = normalize(mul(geom, next));\n" + "\n" + " /* tan(½θ) = sin(θ) / (1 + cos(θ))\n" + " * = (q̂ₚᵣₑᵥ⊥ · q̂ₙₑₓₜ) / (1 + (q̂ₚᵣₑᵥ · q̂ₙₑₓₜ)) */\n" + " v_p = float2(-q_prev.y, q_prev.x);\n" + " l = -dot(v_p, q_next) / (1.0f + dot(q_prev, q_next));\n" + " q_i = l * q_prev + v_p;\n" + "\n" + " o.b = float4(0.0, 0.0, 0.0, 0.0);\n" + "\n" + " o.p = mul(float3(position, 1.0f), transform_geometry) + stroke_width * 0.5f * q_i;\n" + " position = mul(float2x3(transform_rtx.xyz, transform_rty.xyz), float3(o.p, 1.0f))\n" + " * float2(transform_rtx.w, transform_rty.w);\n" + " o.position = float4(position + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n" + "}\n"; +/* ⎡p0.x p0.y 1⎤ + * A = ⎢p1.x p1.y 1⎥ + * ⎣p2.x p2.y 1⎦ + * + * ⎡0 0⎤ + * B = ⎢½ 0⎥ + * ⎣1 1⎦ + * + * A' = ⎡p1.x-p0.x p1.y-p0.y⎤ + * ⎣p2.x-p0.x p2.y-p0.y⎦ + * + * B' = ⎡½ 0⎤ + * ⎣1 1⎦ + * + * A'T = B' + * T = A'⁻¹B' + */ +static const char shape_vs_code_bezier_outline[] = + "float3x2 transform_geometry;\n" + "float stroke_width;\n" + "float4 transform_rtx;\n" + "float4 transform_rty;\n" + "\n" + "struct output\n" + "{\n" + " float2 p : WORLD_POSITION;\n" + " float4 b : BEZIER;\n" + " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n" + " float4 position : SV_POSITION;\n" + "};\n" + "\n" + "void main(float2 position : POSITION, float2 p0 : P0, float2 p1 : P1, float2 p2 : P2,\n" + " float2 prev : PREV, float2 next : NEXT, out struct output o)\n" + "{\n" + " float2 q_prev, q_next, v_p, q_i, p;\n" + " float2x2 geom, rt;\n" + " float l;\n" + "\n" + " geom = float2x2(transform_geometry._11_21, transform_geometry._12_22);\n" + " rt = float2x2(transform_rtx.xy, transform_rty.xy);\n" + " o.stroke_transform = rt * stroke_width * 0.5f;\n" + "\n" + " p = mul(geom, position);\n" + " p0 = mul(geom, p0);\n" + " p1 = mul(geom, p1);\n" + " p2 = mul(geom, p2);\n" + "\n" + " p -= p0;\n" + " p1 -= p0;\n" + " p2 -= p0;\n" + "\n" + " q_prev = normalize(mul(geom, prev));\n" + " q_next = normalize(mul(geom, next));\n" + "\n" + " v_p = float2(-q_prev.y, q_prev.x);\n" + " l = -dot(v_p, q_next) / (1.0f + dot(q_prev, q_next));\n" + " q_i = l * q_prev + v_p;\n" + " p += 0.5f * stroke_width * q_i;\n" + "\n" + " v_p = mul(rt, p2);\n" + " v_p = normalize(float2(-v_p.y, v_p.x));\n" + " if (abs(dot(mul(rt, p1), v_p)) < 1.0f)\n" + " {\n" + " o.b.xzw = float3(0.0f, 0.0f, 0.0f);\n" + " o.b.y = dot(mul(rt, p), v_p);\n" + " }\n" + " else\n" + " {\n" + " o.b.zw = sign(dot(mul(rt, p1), v_p)) * v_p;\n" + " v_p = -float2(-p.y, p.x) / dot(float2(-p1.y, p1.x), p2);\n" + " o.b.x = dot(v_p, p1 - 0.5f * p2);\n" + " o.b.y = dot(v_p, p1);\n" + " }\n" + "\n" + " o.p = mul(float3(position, 1.0f), transform_geometry) + 0.5f * stroke_width * q_i;\n" + " position = mul(float2x3(transform_rtx.xyz, transform_rty.xyz), float3(o.p, 1.0f))\n" + " * float2(transform_rtx.w, transform_rty.w);\n" + " o.position = float4(position + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n" + "}\n"; +/* ⎡p0.x p0.y 1⎤ + * A = ⎢p1.x p1.y 1⎥ + * ⎣p2.x p2.y 1⎦ + * + * ⎡1 0⎤ + * B = ⎢1 1⎥ + * ⎣0 1⎦ + * + * A' = ⎡p1.x-p0.x p1.y-p0.y⎤ + * ⎣p2.x-p0.x p2.y-p0.y⎦ + * + * B' = ⎡ 0 1⎤ + * ⎣-1 1⎦ + * + * A'T = B' + * T = A'⁻¹B' = (B'⁻¹A')⁻¹ + */ +static const char shape_vs_code_arc_outline[] = + "float3x2 transform_geometry;\n" + "float stroke_width;\n" + "float4 transform_rtx;\n" + "float4 transform_rty;\n" + "\n" + "struct output\n" + "{\n" + " float2 p : WORLD_POSITION;\n" + " float4 b : BEZIER;\n" + " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n" + " float4 position : SV_POSITION;\n" + "};\n" + "\n" + "void main(float2 position : POSITION, float2 p0 : P0, float2 p1 : P1, float2 p2 : P2,\n" + " float2 prev : PREV, float2 next : NEXT, out struct output o)\n" + "{\n" + " float2 q_prev, q_next, v_p, q_i, p;\n" + " float2x2 geom, rt, p_inv;\n" + " float l;\n" + " float a;\n" + " float2 bc;\n" + "\n" + " geom = float2x2(transform_geometry._11_21, transform_geometry._12_22);\n" + " rt = float2x2(transform_rtx.xy, transform_rty.xy);\n" + " o.stroke_transform = rt * stroke_width * 0.5f;\n" + "\n" + " p = mul(geom, position);\n" + " p0 = mul(geom, p0);\n" + " p1 = mul(geom, p1);\n" + " p2 = mul(geom, p2);\n" + "\n" + " p -= p0;\n" + " p1 -= p0;\n" + " p2 -= p0;\n" + "\n" + " q_prev = normalize(mul(geom, prev));\n" + " q_next = normalize(mul(geom, next));\n" + "\n" + " v_p = float2(-q_prev.y, q_prev.x);\n" + " l = -dot(v_p, q_next) / (1.0f + dot(q_prev, q_next));\n" + " q_i = l * q_prev + v_p;\n" + " p += 0.5f * stroke_width * q_i;\n" + "\n" + " p_inv = float2x2(p1.y, -p1.x, p2.y - p1.y, p1.x - p2.x) / (p1.x * p2.y - p2.x * p1.y);\n" + " o.b.xy = mul(p_inv, p) + float2(1.0f, 0.0f);\n" + " o.b.zw = 0.0f;\n" + "\n" + " o.p = mul(float3(position, 1.0f), transform_geometry) + 0.5f * stroke_width * q_i;\n" + " position = mul(float2x3(transform_rtx.xyz, transform_rty.xyz), float3(o.p, 1.0f))\n" + " * float2(transform_rtx.w, transform_rty.w);\n" + " o.position = float4(position + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n" + "}\n"; +static const char shape_vs_code_triangle[] = + "float3x2 transform_geometry;\n" + "float4 transform_rtx;\n" + "float4 transform_rty;\n" + "\n" + "struct output\n" + "{\n" + " float2 p : WORLD_POSITION;\n" + " float4 b : BEZIER;\n" + " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n" + " float4 position : SV_POSITION;\n" + "};\n" + "\n" + "void main(float2 position : POSITION, out struct output o)\n" + "{\n" + " o.p = mul(float3(position, 1.0f), transform_geometry);\n" + " o.b = float4(1.0, 0.0, 1.0, 1.0);\n" + " o.stroke_transform = float2x2(1.0, 0.0, 0.0, 1.0);\n" + " position = mul(float2x3(transform_rtx.xyz, transform_rty.xyz), float3(o.p, 1.0f))\n" + " * float2(transform_rtx.w, transform_rty.w);\n" + " o.position = float4(position + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n" + "}\n"; +static const char shape_vs_code_curve[] = + "float3x2 transform_geometry;\n" + "float4 transform_rtx;\n" + "float4 transform_rty;\n" + "\n" + "struct output\n" + "{\n" + " float2 p : WORLD_POSITION;\n" + " float4 b : BEZIER;\n" + " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n" + " float4 position : SV_POSITION;\n" + "};\n" + "\n" + "void main(float2 position : POSITION, float3 texcoord : TEXCOORD0, out struct output o)\n" + "{\n" + " o.p = mul(float3(position, 1.0f), transform_geometry);\n" + " o.b = float4(texcoord, 1.0);\n" + " o.stroke_transform = float2x2(1.0, 0.0, 0.0, 1.0);\n" + " position = mul(float2x3(transform_rtx.xyz, transform_rty.xyz), float3(o.p, 1.0f))\n" + " * float2(transform_rtx.w, transform_rty.w);\n" + " o.position = float4(position + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n" + "}\n"; +static const char shape_ps_code[] = + "#define BRUSH_TYPE_SOLID 0\n" + "#define BRUSH_TYPE_LINEAR 1\n" + "#define BRUSH_TYPE_RADIAL 2\n" + "#define BRUSH_TYPE_BITMAP 3\n" + "#define BRUSH_TYPE_COUNT 4\n" + "\n" + "bool outline;\n" + "bool is_arc;\n" + "struct brush\n" + "{\n" + " uint type;\n" + " float opacity;\n" + " float4 data[3];\n" + "} colour_brush, opacity_brush;\n" + "\n" + "SamplerState s0, s1;\n" + "Texture2D t0, t1;\n" + "Buffer<float4> b0, b1;\n" + "\n" + "struct input\n" + "{\n" + " float2 p : WORLD_POSITION;\n" + " float4 b : BEZIER;\n" + " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n" + "};\n" + "\n" + "float4 sample_gradient(Buffer<float4> gradient, uint stop_count, float position)\n" + "{\n" + " float4 c_low, c_high;\n" + " float p_low, p_high;\n" + " uint i;\n" + "\n" + " p_low = gradient.Load(0).x;\n" + " c_low = gradient.Load(1);\n" + " c_high = c_low;\n" + "\n" + " if (position < p_low)\n" + " return c_low;\n" + "\n" + " [loop]\n" + " for (i = 1; i < stop_count; ++i)\n" + " {\n" + " p_high = gradient.Load(i * 2).x;\n" + " c_high = gradient.Load(i * 2 + 1);\n" + "\n" + " if (position >= p_low && position <= p_high)\n" + " return lerp(c_low, c_high, (position - p_low) / (p_high - p_low));\n" + "\n" + " p_low = p_high;\n" + " c_low = c_high;\n" + " }\n" + "\n" + " return c_high;\n" + "}\n" + "\n" + "float4 brush_linear(struct brush brush, Buffer<float4> gradient, float2 position)\n" + "{\n" + " float2 start, end, v_p, v_q;\n" + " uint stop_count;\n" + " float p;\n" + "\n" + " start = brush.data[0].xy;\n" + " end = brush.data[0].zw;\n" + " stop_count = asuint(brush.data[1].x);\n" + "\n" + " v_p = position - start;\n" + " v_q = end - start;\n" + " p = dot(v_q, v_p) / dot(v_q, v_q);\n" + "\n" + " return sample_gradient(gradient, stop_count, p);\n" + "}\n" + "\n" + "float4 brush_radial(struct brush brush, Buffer<float4> gradient, float2 position)\n" + "{\n" + " float2 centre, offset, ra, rb, v_p, v_q, r;\n" + " float b, c, l, t;\n" + " uint stop_count;\n" + "\n" + " centre = brush.data[0].xy;\n" + " offset = brush.data[0].zw;\n" + " ra = brush.data[1].xy;\n" + " rb = brush.data[1].zw;\n" + " stop_count = asuint(brush.data[2].x);\n" + "\n" + " /* Project onto ra, rb. */\n" + " r = float2(dot(ra, ra), dot(rb, rb));\n" + " v_p = position - (centre + offset);\n" + " v_p = float2(dot(v_p, ra), dot(v_p, rb)) / r;\n" + " v_q = float2(dot(offset, ra), dot(offset, rb)) / r;\n" + "\n" + " /* ‖t·p̂ + q⃑‖ = 1\n" + " * (t·p̂ + q⃑) · (t·p̂ + q⃑) = 1\n" + " * t² + 2·(p̂·q⃑)·t + (q⃑·q⃑) = 1\n" + " *\n" + " * b = p̂·q⃑\n" + " * c = q⃑·q⃑ - 1\n" + " * t = -b + √(b² - c) */\n" + " l = length(v_p);\n" + " b = dot(v_p, v_q) / l;\n" + " c = dot(v_q, v_q) - 1.0;\n" + " t = -b + sqrt(b * b - c);\n" + "\n" + " return sample_gradient(gradient, stop_count, l / t);\n" + "}\n" + "\n" + "float4 brush_bitmap(struct brush brush, Texture2D t, SamplerState s, float2 position)\n" + "{\n" + " float3 transform[2];\n" + " bool ignore_alpha;\n" + " float2 texcoord;\n" + " float4 colour;\n" + "\n" + " transform[0] = brush.data[0].xyz;\n" + " transform[1] = brush.data[1].xyz;\n" + " ignore_alpha = asuint(brush.data[1].w);\n" + "\n" + " texcoord.x = dot(position.xy, transform[0].xy) + transform[0].z;\n" + " texcoord.y = dot(position.xy, transform[1].xy) + transform[1].z;\n" + " colour = t.Sample(s, texcoord);\n" + " if (ignore_alpha)\n" + " colour.a = 1.0;\n" + " return colour;\n" + "}\n" + "\n" + "float4 sample_brush(struct brush brush, Texture2D t, SamplerState s, Buffer<float4> b, float2 position)\n" + "{\n" + " if (brush.type == BRUSH_TYPE_SOLID)\n" + " return brush.data[0] * brush.opacity;\n" + " if (brush.type == BRUSH_TYPE_LINEAR)\n" + " return brush_linear(brush, b, position) * brush.opacity;\n" + " if (brush.type == BRUSH_TYPE_RADIAL)\n" + " return brush_radial(brush, b, position) * brush.opacity;\n" + " if (brush.type == BRUSH_TYPE_BITMAP)\n" + " return brush_bitmap(brush, t, s, position) * brush.opacity;\n" + " return float4(0.0, 0.0, 0.0, brush.opacity);\n" + "}\n" + "\n" + "float4 main(struct input i) : SV_Target\n" + "{\n" + " float4 colour;\n" + "\n" + " colour = sample_brush(colour_brush, t0, s0, b0, i.p);\n" + " if (opacity_brush.type < BRUSH_TYPE_COUNT)\n" + " colour *= sample_brush(opacity_brush, t1, s1, b1, i.p).a;\n" + "\n" + " if (outline)\n" + " {\n" + " float2 du, dv, df;\n" + " float4 uv;\n" + "\n" + " /* Evaluate the implicit form of the curve (u² - v = 0\n" + " * for Béziers, u² + v² - 1 = 0 for arcs) in texture\n" + " * space, using the screen-space partial derivatives\n" + " * to convert the calculated distance to object space.\n" + " *\n" + " * d(x, y) = |f(x, y)| / ‖∇f(x, y)‖\n" + " * = |f(x, y)| / √((∂f/∂x)² + (∂f/∂y)²)\n" + " *\n" + " * For Béziers:\n" + " * f(x, y) = u(x, y)² - v(x, y)\n" + " * ∂f/∂x = 2u · ∂u/∂x - ∂v/∂x\n" + " * ∂f/∂y = 2u · ∂u/∂y - ∂v/∂y\n" + " *\n" + " * For arcs:\n" + " * f(x, y) = u(x, y)² + v(x, y)² - 1\n" + " * ∂f/∂x = 2u · ∂u/∂x + 2v · ∂v/∂x\n" + " * ∂f/∂y = 2u · ∂u/∂y + 2v · ∂v/∂y */\n" + " uv = i.b;\n" + " du = float2(ddx(uv.x), ddy(uv.x));\n" + " dv = float2(ddx(uv.y), ddy(uv.y));\n" + "\n" + " if (!is_arc)\n" + " {\n" + " df = 2.0f * uv.x * du - dv;\n" + "\n" + " clip(dot(df, uv.zw));\n" + " clip(length(mul(i.stroke_transform, df)) - abs(uv.x * uv.x - uv.y));\n" + " }\n" + " else\n" + " {\n" + " df = 2.0f * uv.x * du + 2.0f * uv.y * dv;\n" + "\n" + " clip(dot(df, uv.zw));\n" + " clip(length(mul(i.stroke_transform, df)) - abs(uv.x * uv.x + uv.y * uv.y - 1.0f));\n" + " }\n" + " }\n" + " else\n" + " {\n" + " /* Evaluate the implicit form of the curve in texture space.\n" + " * "i.b.z" determines which side of the curve is shaded. */\n" + " if (!is_arc)\n" + " {\n" + " clip((i.b.x * i.b.x - i.b.y) * i.b.z);\n" + " }\n" + " else\n" + " {\n" + " clip((i.b.x * i.b.x + i.b.y * i.b.y - 1.0) * i.b.z);\n" + " }\n" + " }\n" + "\n" + " return colour;\n" + "}\n"; +static const struct shape_info +{ + enum d2d_shape_type shape_type; + const D3D11_INPUT_ELEMENT_DESC *il_desc; + unsigned int il_element_count; + const char *name; + const char *vs_code; + size_t vs_code_size; +} +shape_info[] = +{ + {D2D_SHAPE_TYPE_OUTLINE, shape_il_desc_outline, ARRAY_SIZE(shape_il_desc_outline), + "outline", shape_vs_code_outline, sizeof(shape_vs_code_outline) - 1}, + {D2D_SHAPE_TYPE_BEZIER_OUTLINE, shape_il_desc_curve_outline, ARRAY_SIZE(shape_il_desc_curve_outline), + "bezier_outline", shape_vs_code_bezier_outline, sizeof(shape_vs_code_bezier_outline) - 1}, + {D2D_SHAPE_TYPE_ARC_OUTLINE, shape_il_desc_curve_outline, ARRAY_SIZE(shape_il_desc_curve_outline), + "arc_outline", shape_vs_code_arc_outline, sizeof(shape_vs_code_arc_outline) - 1}, + {D2D_SHAPE_TYPE_TRIANGLE, shape_il_desc_triangle, ARRAY_SIZE(shape_il_desc_triangle), + "triangle", shape_vs_code_triangle, sizeof(shape_vs_code_triangle) - 1}, + {D2D_SHAPE_TYPE_CURVE, shape_il_desc_curve, ARRAY_SIZE(shape_il_desc_curve), + "curve", shape_vs_code_curve, sizeof(shape_vs_code_curve) - 1}, +}; + static HRESULT d2d_device_context_init(struct d2d_device_context *render_target, struct d2d_device *device, IUnknown *outer_unknown, const struct d2d_device_context_ops *ops) { @@ -3462,500 +3954,10 @@ static HRESULT d2d_device_context_init(struct d2d_device_context *render_target, D3D11_RASTERIZER_DESC rs_desc; D3D11_BUFFER_DESC buffer_desc; struct d2d_factory *factory; - ID3D10Blob *compiled; + ID3D10Blob *precompiled; unsigned int i; HRESULT hr;
- static const D3D11_INPUT_ELEMENT_DESC il_desc_outline[] = - { - {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"PREV", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"NEXT", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0}, - }; - static const D3D11_INPUT_ELEMENT_DESC il_desc_curve_outline[] = - { - {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"P", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"P", 1, DXGI_FORMAT_R32G32_FLOAT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"P", 2, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"PREV", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"NEXT", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 40, D3D11_INPUT_PER_VERTEX_DATA, 0}, - }; - static const D3D11_INPUT_ELEMENT_DESC il_desc_triangle[] = - { - {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, - }; - static const D3D11_INPUT_ELEMENT_DESC il_desc_curve[] = - { - {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0}, - }; - static const char vs_code_outline[] = - "float3x2 transform_geometry;\n" - "float stroke_width;\n" - "float4 transform_rtx;\n" - "float4 transform_rty;\n" - "\n" - "struct output\n" - "{\n" - " float2 p : WORLD_POSITION;\n" - " float4 b : BEZIER;\n" - " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n" - " float4 position : SV_POSITION;\n" - "};\n" - "\n" - "/* The lines PₚᵣₑᵥP₀ and P₀Pₙₑₓₜ, both offset by ±½w, intersect each other at:\n" - " *\n" - " * Pᵢ = P₀ ± w · ½q⃑ᵢ.\n" - " *\n" - " * Where:\n" - " *\n" - " * q⃑ᵢ = q̂ₚᵣₑᵥ⊥ + tan(½θ) · -q̂ₚᵣₑᵥ\n" - " * θ = ∠PₚᵣₑᵥP₀Pₙₑₓₜ\n" - " * q⃑ₚᵣₑᵥ = P₀ - Pₚᵣₑᵥ */\n" - "void main(float2 position : POSITION, float2 prev : PREV, float2 next : NEXT, out struct output o)\n" - "{\n" - " float2 q_prev, q_next, v_p, q_i;\n" - " float2x2 geom;\n" - " float l;\n" - "\n" - " o.stroke_transform = float2x2(transform_rtx.xy, transform_rty.xy) * stroke_width * 0.5f;\n" - "\n" - " geom = float2x2(transform_geometry._11_21, transform_geometry._12_22);\n" - " q_prev = normalize(mul(geom, prev));\n" - " q_next = normalize(mul(geom, next));\n" - "\n" - " /* tan(½θ) = sin(θ) / (1 + cos(θ))\n" - " * = (q̂ₚᵣₑᵥ⊥ · q̂ₙₑₓₜ) / (1 + (q̂ₚᵣₑᵥ · q̂ₙₑₓₜ)) */\n" - " v_p = float2(-q_prev.y, q_prev.x);\n" - " l = -dot(v_p, q_next) / (1.0f + dot(q_prev, q_next));\n" - " q_i = l * q_prev + v_p;\n" - "\n" - " o.b = float4(0.0, 0.0, 0.0, 0.0);\n" - "\n" - " o.p = mul(float3(position, 1.0f), transform_geometry) + stroke_width * 0.5f * q_i;\n" - " position = mul(float2x3(transform_rtx.xyz, transform_rty.xyz), float3(o.p, 1.0f))\n" - " * float2(transform_rtx.w, transform_rty.w);\n" - " o.position = float4(position + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n" - "}\n"; - /* ⎡p0.x p0.y 1⎤ - * A = ⎢p1.x p1.y 1⎥ - * ⎣p2.x p2.y 1⎦ - * - * ⎡0 0⎤ - * B = ⎢½ 0⎥ - * ⎣1 1⎦ - * - * A' = ⎡p1.x-p0.x p1.y-p0.y⎤ - * ⎣p2.x-p0.x p2.y-p0.y⎦ - * - * B' = ⎡½ 0⎤ - * ⎣1 1⎦ - * - * A'T = B' - * T = A'⁻¹B' - */ - static const char vs_code_bezier_outline[] = - "float3x2 transform_geometry;\n" - "float stroke_width;\n" - "float4 transform_rtx;\n" - "float4 transform_rty;\n" - "\n" - "struct output\n" - "{\n" - " float2 p : WORLD_POSITION;\n" - " float4 b : BEZIER;\n" - " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n" - " float4 position : SV_POSITION;\n" - "};\n" - "\n" - "void main(float2 position : POSITION, float2 p0 : P0, float2 p1 : P1, float2 p2 : P2,\n" - " float2 prev : PREV, float2 next : NEXT, out struct output o)\n" - "{\n" - " float2 q_prev, q_next, v_p, q_i, p;\n" - " float2x2 geom, rt;\n" - " float l;\n" - "\n" - " geom = float2x2(transform_geometry._11_21, transform_geometry._12_22);\n" - " rt = float2x2(transform_rtx.xy, transform_rty.xy);\n" - " o.stroke_transform = rt * stroke_width * 0.5f;\n" - "\n" - " p = mul(geom, position);\n" - " p0 = mul(geom, p0);\n" - " p1 = mul(geom, p1);\n" - " p2 = mul(geom, p2);\n" - "\n" - " p -= p0;\n" - " p1 -= p0;\n" - " p2 -= p0;\n" - "\n" - " q_prev = normalize(mul(geom, prev));\n" - " q_next = normalize(mul(geom, next));\n" - "\n" - " v_p = float2(-q_prev.y, q_prev.x);\n" - " l = -dot(v_p, q_next) / (1.0f + dot(q_prev, q_next));\n" - " q_i = l * q_prev + v_p;\n" - " p += 0.5f * stroke_width * q_i;\n" - "\n" - " v_p = mul(rt, p2);\n" - " v_p = normalize(float2(-v_p.y, v_p.x));\n" - " if (abs(dot(mul(rt, p1), v_p)) < 1.0f)\n" - " {\n" - " o.b.xzw = float3(0.0f, 0.0f, 0.0f);\n" - " o.b.y = dot(mul(rt, p), v_p);\n" - " }\n" - " else\n" - " {\n" - " o.b.zw = sign(dot(mul(rt, p1), v_p)) * v_p;\n" - " v_p = -float2(-p.y, p.x) / dot(float2(-p1.y, p1.x), p2);\n" - " o.b.x = dot(v_p, p1 - 0.5f * p2);\n" - " o.b.y = dot(v_p, p1);\n" - " }\n" - "\n" - " o.p = mul(float3(position, 1.0f), transform_geometry) + 0.5f * stroke_width * q_i;\n" - " position = mul(float2x3(transform_rtx.xyz, transform_rty.xyz), float3(o.p, 1.0f))\n" - " * float2(transform_rtx.w, transform_rty.w);\n" - " o.position = float4(position + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n" - "}\n"; - /* ⎡p0.x p0.y 1⎤ - * A = ⎢p1.x p1.y 1⎥ - * ⎣p2.x p2.y 1⎦ - * - * ⎡1 0⎤ - * B = ⎢1 1⎥ - * ⎣0 1⎦ - * - * A' = ⎡p1.x-p0.x p1.y-p0.y⎤ - * ⎣p2.x-p0.x p2.y-p0.y⎦ - * - * B' = ⎡ 0 1⎤ - * ⎣-1 1⎦ - * - * A'T = B' - * T = A'⁻¹B' = (B'⁻¹A')⁻¹ - */ - static const char vs_code_arc_outline[] = - "float3x2 transform_geometry;\n" - "float stroke_width;\n" - "float4 transform_rtx;\n" - "float4 transform_rty;\n" - "\n" - "struct output\n" - "{\n" - " float2 p : WORLD_POSITION;\n" - " float4 b : BEZIER;\n" - " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n" - " float4 position : SV_POSITION;\n" - "};\n" - "\n" - "void main(float2 position : POSITION, float2 p0 : P0, float2 p1 : P1, float2 p2 : P2,\n" - " float2 prev : PREV, float2 next : NEXT, out struct output o)\n" - "{\n" - " float2 q_prev, q_next, v_p, q_i, p;\n" - " float2x2 geom, rt, p_inv;\n" - " float l;\n" - " float a;\n" - " float2 bc;\n" - "\n" - " geom = float2x2(transform_geometry._11_21, transform_geometry._12_22);\n" - " rt = float2x2(transform_rtx.xy, transform_rty.xy);\n" - " o.stroke_transform = rt * stroke_width * 0.5f;\n" - "\n" - " p = mul(geom, position);\n" - " p0 = mul(geom, p0);\n" - " p1 = mul(geom, p1);\n" - " p2 = mul(geom, p2);\n" - "\n" - " p -= p0;\n" - " p1 -= p0;\n" - " p2 -= p0;\n" - "\n" - " q_prev = normalize(mul(geom, prev));\n" - " q_next = normalize(mul(geom, next));\n" - "\n" - " v_p = float2(-q_prev.y, q_prev.x);\n" - " l = -dot(v_p, q_next) / (1.0f + dot(q_prev, q_next));\n" - " q_i = l * q_prev + v_p;\n" - " p += 0.5f * stroke_width * q_i;\n" - "\n" - " p_inv = float2x2(p1.y, -p1.x, p2.y - p1.y, p1.x - p2.x) / (p1.x * p2.y - p2.x * p1.y);\n" - " o.b.xy = mul(p_inv, p) + float2(1.0f, 0.0f);\n" - " o.b.zw = 0.0f;\n" - "\n" - " o.p = mul(float3(position, 1.0f), transform_geometry) + 0.5f * stroke_width * q_i;\n" - " position = mul(float2x3(transform_rtx.xyz, transform_rty.xyz), float3(o.p, 1.0f))\n" - " * float2(transform_rtx.w, transform_rty.w);\n" - " o.position = float4(position + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n" - "}\n"; - static const char vs_code_triangle[] = - "float3x2 transform_geometry;\n" - "float4 transform_rtx;\n" - "float4 transform_rty;\n" - "\n" - "struct output\n" - "{\n" - " float2 p : WORLD_POSITION;\n" - " float4 b : BEZIER;\n" - " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n" - " float4 position : SV_POSITION;\n" - "};\n" - "\n" - "void main(float2 position : POSITION, out struct output o)\n" - "{\n" - " o.p = mul(float3(position, 1.0f), transform_geometry);\n" - " o.b = float4(1.0, 0.0, 1.0, 1.0);\n" - " o.stroke_transform = float2x2(1.0, 0.0, 0.0, 1.0);\n" - " position = mul(float2x3(transform_rtx.xyz, transform_rty.xyz), float3(o.p, 1.0f))\n" - " * float2(transform_rtx.w, transform_rty.w);\n" - " o.position = float4(position + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n" - "}\n"; - static const char vs_code_curve[] = - "float3x2 transform_geometry;\n" - "float4 transform_rtx;\n" - "float4 transform_rty;\n" - "\n" - "struct output\n" - "{\n" - " float2 p : WORLD_POSITION;\n" - " float4 b : BEZIER;\n" - " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n" - " float4 position : SV_POSITION;\n" - "};\n" - "\n" - "void main(float2 position : POSITION, float3 texcoord : TEXCOORD0, out struct output o)\n" - "{\n" - " o.p = mul(float3(position, 1.0f), transform_geometry);\n" - " o.b = float4(texcoord, 1.0);\n" - " o.stroke_transform = float2x2(1.0, 0.0, 0.0, 1.0);\n" - " position = mul(float2x3(transform_rtx.xyz, transform_rty.xyz), float3(o.p, 1.0f))\n" - " * float2(transform_rtx.w, transform_rty.w);\n" - " o.position = float4(position + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n" - "}\n"; - static const char ps_code[] = - "#define BRUSH_TYPE_SOLID 0\n" - "#define BRUSH_TYPE_LINEAR 1\n" - "#define BRUSH_TYPE_RADIAL 2\n" - "#define BRUSH_TYPE_BITMAP 3\n" - "#define BRUSH_TYPE_COUNT 4\n" - "\n" - "bool outline;\n" - "bool is_arc;\n" - "struct brush\n" - "{\n" - " uint type;\n" - " float opacity;\n" - " float4 data[3];\n" - "} colour_brush, opacity_brush;\n" - "\n" - "SamplerState s0, s1;\n" - "Texture2D t0, t1;\n" - "Buffer<float4> b0, b1;\n" - "\n" - "struct input\n" - "{\n" - " float2 p : WORLD_POSITION;\n" - " float4 b : BEZIER;\n" - " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n" - "};\n" - "\n" - "float4 sample_gradient(Buffer<float4> gradient, uint stop_count, float position)\n" - "{\n" - " float4 c_low, c_high;\n" - " float p_low, p_high;\n" - " uint i;\n" - "\n" - " p_low = gradient.Load(0).x;\n" - " c_low = gradient.Load(1);\n" - " c_high = c_low;\n" - "\n" - " if (position < p_low)\n" - " return c_low;\n" - "\n" - " [loop]\n" - " for (i = 1; i < stop_count; ++i)\n" - " {\n" - " p_high = gradient.Load(i * 2).x;\n" - " c_high = gradient.Load(i * 2 + 1);\n" - "\n" - " if (position >= p_low && position <= p_high)\n" - " return lerp(c_low, c_high, (position - p_low) / (p_high - p_low));\n" - "\n" - " p_low = p_high;\n" - " c_low = c_high;\n" - " }\n" - "\n" - " return c_high;\n" - "}\n" - "\n" - "float4 brush_linear(struct brush brush, Buffer<float4> gradient, float2 position)\n" - "{\n" - " float2 start, end, v_p, v_q;\n" - " uint stop_count;\n" - " float p;\n" - "\n" - " start = brush.data[0].xy;\n" - " end = brush.data[0].zw;\n" - " stop_count = asuint(brush.data[1].x);\n" - "\n" - " v_p = position - start;\n" - " v_q = end - start;\n" - " p = dot(v_q, v_p) / dot(v_q, v_q);\n" - "\n" - " return sample_gradient(gradient, stop_count, p);\n" - "}\n" - "\n" - "float4 brush_radial(struct brush brush, Buffer<float4> gradient, float2 position)\n" - "{\n" - " float2 centre, offset, ra, rb, v_p, v_q, r;\n" - " float b, c, l, t;\n" - " uint stop_count;\n" - "\n" - " centre = brush.data[0].xy;\n" - " offset = brush.data[0].zw;\n" - " ra = brush.data[1].xy;\n" - " rb = brush.data[1].zw;\n" - " stop_count = asuint(brush.data[2].x);\n" - "\n" - " /* Project onto ra, rb. */\n" - " r = float2(dot(ra, ra), dot(rb, rb));\n" - " v_p = position - (centre + offset);\n" - " v_p = float2(dot(v_p, ra), dot(v_p, rb)) / r;\n" - " v_q = float2(dot(offset, ra), dot(offset, rb)) / r;\n" - "\n" - " /* ‖t·p̂ + q⃑‖ = 1\n" - " * (t·p̂ + q⃑) · (t·p̂ + q⃑) = 1\n" - " * t² + 2·(p̂·q⃑)·t + (q⃑·q⃑) = 1\n" - " *\n" - " * b = p̂·q⃑\n" - " * c = q⃑·q⃑ - 1\n" - " * t = -b + √(b² - c) */\n" - " l = length(v_p);\n" - " b = dot(v_p, v_q) / l;\n" - " c = dot(v_q, v_q) - 1.0;\n" - " t = -b + sqrt(b * b - c);\n" - "\n" - " return sample_gradient(gradient, stop_count, l / t);\n" - "}\n" - "\n" - "float4 brush_bitmap(struct brush brush, Texture2D t, SamplerState s, float2 position)\n" - "{\n" - " float3 transform[2];\n" - " bool ignore_alpha;\n" - " float2 texcoord;\n" - " float4 colour;\n" - "\n" - " transform[0] = brush.data[0].xyz;\n" - " transform[1] = brush.data[1].xyz;\n" - " ignore_alpha = asuint(brush.data[1].w);\n" - "\n" - " texcoord.x = dot(position.xy, transform[0].xy) + transform[0].z;\n" - " texcoord.y = dot(position.xy, transform[1].xy) + transform[1].z;\n" - " colour = t.Sample(s, texcoord);\n" - " if (ignore_alpha)\n" - " colour.a = 1.0;\n" - " return colour;\n" - "}\n" - "\n" - "float4 sample_brush(struct brush brush, Texture2D t, SamplerState s, Buffer<float4> b, float2 position)\n" - "{\n" - " if (brush.type == BRUSH_TYPE_SOLID)\n" - " return brush.data[0] * brush.opacity;\n" - " if (brush.type == BRUSH_TYPE_LINEAR)\n" - " return brush_linear(brush, b, position) * brush.opacity;\n" - " if (brush.type == BRUSH_TYPE_RADIAL)\n" - " return brush_radial(brush, b, position) * brush.opacity;\n" - " if (brush.type == BRUSH_TYPE_BITMAP)\n" - " return brush_bitmap(brush, t, s, position) * brush.opacity;\n" - " return float4(0.0, 0.0, 0.0, brush.opacity);\n" - "}\n" - "\n" - "float4 main(struct input i) : SV_Target\n" - "{\n" - " float4 colour;\n" - "\n" - " colour = sample_brush(colour_brush, t0, s0, b0, i.p);\n" - " if (opacity_brush.type < BRUSH_TYPE_COUNT)\n" - " colour *= sample_brush(opacity_brush, t1, s1, b1, i.p).a;\n" - "\n" - " if (outline)\n" - " {\n" - " float2 du, dv, df;\n" - " float4 uv;\n" - "\n" - " /* Evaluate the implicit form of the curve (u² - v = 0\n" - " * for Béziers, u² + v² - 1 = 0 for arcs) in texture\n" - " * space, using the screen-space partial derivatives\n" - " * to convert the calculated distance to object space.\n" - " *\n" - " * d(x, y) = |f(x, y)| / ‖∇f(x, y)‖\n" - " * = |f(x, y)| / √((∂f/∂x)² + (∂f/∂y)²)\n" - " *\n" - " * For Béziers:\n" - " * f(x, y) = u(x, y)² - v(x, y)\n" - " * ∂f/∂x = 2u · ∂u/∂x - ∂v/∂x\n" - " * ∂f/∂y = 2u · ∂u/∂y - ∂v/∂y\n" - " *\n" - " * For arcs:\n" - " * f(x, y) = u(x, y)² + v(x, y)² - 1\n" - " * ∂f/∂x = 2u · ∂u/∂x + 2v · ∂v/∂x\n" - " * ∂f/∂y = 2u · ∂u/∂y + 2v · ∂v/∂y */\n" - " uv = i.b;\n" - " du = float2(ddx(uv.x), ddy(uv.x));\n" - " dv = float2(ddx(uv.y), ddy(uv.y));\n" - "\n" - " if (!is_arc)\n" - " {\n" - " df = 2.0f * uv.x * du - dv;\n" - "\n" - " clip(dot(df, uv.zw));\n" - " clip(length(mul(i.stroke_transform, df)) - abs(uv.x * uv.x - uv.y));\n" - " }\n" - " else\n" - " {\n" - " df = 2.0f * uv.x * du + 2.0f * uv.y * dv;\n" - "\n" - " clip(dot(df, uv.zw));\n" - " clip(length(mul(i.stroke_transform, df)) - abs(uv.x * uv.x + uv.y * uv.y - 1.0f));\n" - " }\n" - " }\n" - " else\n" - " {\n" - " /* Evaluate the implicit form of the curve in texture space.\n" - " * "i.b.z" determines which side of the curve is shaded. */\n" - " if (!is_arc)\n" - " {\n" - " clip((i.b.x * i.b.x - i.b.y) * i.b.z);\n" - " }\n" - " else\n" - " {\n" - " clip((i.b.x * i.b.x + i.b.y * i.b.y - 1.0) * i.b.z);\n" - " }\n" - " }\n" - "\n" - " return colour;\n" - "}\n"; - static const struct shape_info - { - enum d2d_shape_type shape_type; - const D3D11_INPUT_ELEMENT_DESC *il_desc; - unsigned int il_element_count; - const char *name; - const char *vs_code; - size_t vs_code_size; - } - shape_info[] = - { - {D2D_SHAPE_TYPE_OUTLINE, il_desc_outline, ARRAY_SIZE(il_desc_outline), - "outline", vs_code_outline, sizeof(vs_code_outline) - 1}, - {D2D_SHAPE_TYPE_BEZIER_OUTLINE, il_desc_curve_outline, ARRAY_SIZE(il_desc_curve_outline), - "bezier_outline", vs_code_bezier_outline, sizeof(vs_code_bezier_outline) - 1}, - {D2D_SHAPE_TYPE_ARC_OUTLINE, il_desc_curve_outline, ARRAY_SIZE(il_desc_curve_outline), - "arc_outline", vs_code_arc_outline, sizeof(vs_code_arc_outline) - 1}, - {D2D_SHAPE_TYPE_TRIANGLE, il_desc_triangle, ARRAY_SIZE(il_desc_triangle), - "triangle", vs_code_triangle, sizeof(vs_code_triangle) - 1}, - {D2D_SHAPE_TYPE_CURVE, il_desc_curve, ARRAY_SIZE(il_desc_curve), - "curve", vs_code_curve, sizeof(vs_code_curve) - 1}, - }; static const struct { float x, y; @@ -4005,32 +4007,23 @@ static HRESULT d2d_device_context_init(struct d2d_device_context *render_target, { const struct shape_info *si = &shape_info[i];
- if (FAILED(hr = D3DCompile(si->vs_code, si->vs_code_size, si->name, NULL, NULL, - "main", "vs_4_0", 0, 0, &compiled, NULL))) - { - WARN("Failed to compile shader for shape type %#x, hr %#lx.\n", si->shape_type, hr); - goto err; - } - + assert(device->precompiled_shape_vs[i]); + precompiled = device->precompiled_shape_vs[i]; if (FAILED(hr = ID3D11Device1_CreateInputLayout(render_target->d3d_device, si->il_desc, si->il_element_count, - ID3D10Blob_GetBufferPointer(compiled), ID3D10Blob_GetBufferSize(compiled), + ID3D10Blob_GetBufferPointer(precompiled), ID3D10Blob_GetBufferSize(precompiled), &render_target->shape_resources[si->shape_type].il))) { WARN("Failed to create input layout for shape type %#x, hr %#lx.\n", si->shape_type, hr); - ID3D10Blob_Release(compiled); goto err; }
if (FAILED(hr = ID3D11Device1_CreateVertexShader(render_target->d3d_device, - ID3D10Blob_GetBufferPointer(compiled), ID3D10Blob_GetBufferSize(compiled), + ID3D10Blob_GetBufferPointer(precompiled), ID3D10Blob_GetBufferSize(precompiled), NULL, &render_target->shape_resources[si->shape_type].vs))) { WARN("Failed to create vertex shader for shape type %#x, hr %#lx.\n", si->shape_type, hr); - ID3D10Blob_Release(compiled); goto err; } - - ID3D10Blob_Release(compiled); }
buffer_desc.ByteWidth = sizeof(struct d2d_vs_cb); @@ -4046,23 +4039,16 @@ static HRESULT d2d_device_context_init(struct d2d_device_context *render_target, goto err; }
- if (FAILED(hr = D3DCompile(ps_code, sizeof(ps_code) - 1, "ps", NULL, NULL, "main", "ps_4_0", 0, 0, &compiled, NULL))) - { - WARN("Failed to compile the pixel shader, hr %#lx.\n", hr); - goto err; - } - + assert(device->precompiled_shape_ps); + precompiled = device->precompiled_shape_ps; if (FAILED(hr = ID3D11Device1_CreatePixelShader(render_target->d3d_device, - ID3D10Blob_GetBufferPointer(compiled), ID3D10Blob_GetBufferSize(compiled), + ID3D10Blob_GetBufferPointer(precompiled), ID3D10Blob_GetBufferSize(precompiled), NULL, &render_target->ps))) { WARN("Failed to create pixel shader, hr %#lx.\n", hr); - ID3D10Blob_Release(compiled); goto err; }
- ID3D10Blob_Release(compiled); - buffer_desc.ByteWidth = sizeof(struct d2d_ps_cb); buffer_desc.Usage = D3D11_USAGE_DYNAMIC; buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; @@ -4304,6 +4290,13 @@ static ULONG WINAPI d2d_device_Release(ID2D1Device6 *iface) IDXGIDevice_Release(device->dxgi_device); ID2D1Factory1_Release(device->factory); d2d_device_indexed_objects_clear(&device->shaders); + for (unsigned int i = 0; i < D2D_SHAPE_TYPE_COUNT; ++i) + { + if (device->precompiled_shape_vs[i]) + ID3D10Blob_Release(device->precompiled_shape_vs[i]); + } + if (device->precompiled_shape_ps) + ID3D10Blob_Release(device->precompiled_shape_ps); free(device); }
@@ -4528,9 +4521,12 @@ struct d2d_device *unsafe_impl_from_ID2D1Device(ID2D1Device1 *iface) return CONTAINING_RECORD(iface, struct d2d_device, ID2D1Device6_iface); }
-void d2d_device_init(struct d2d_device *device, ID2D1Factory1 *factory, IDXGIDevice *dxgi_device, +HRESULT d2d_device_init(struct d2d_device *device, ID2D1Factory1 *factory, IDXGIDevice *dxgi_device, bool allow_get_dxgi_device) { + HRESULT hr; + ID3D10Blob *compiled; + device->ID2D1Device6_iface.lpVtbl = &d2d_device_vtbl; device->refcount = 1; device->factory = factory; @@ -4538,6 +4534,29 @@ void d2d_device_init(struct d2d_device *device, ID2D1Factory1 *factory, IDXGIDev device->dxgi_device = dxgi_device; IDXGIDevice_AddRef(device->dxgi_device); device->allow_get_dxgi_device = allow_get_dxgi_device; + + for (unsigned int i = 0; i < ARRAY_SIZE(shape_info); ++i) + { + const struct shape_info *si = &shape_info[i]; + + if (FAILED(hr = D3DCompile(si->vs_code, si->vs_code_size, si->name, NULL, NULL, + "main", "vs_4_0", 0, 0, &compiled, NULL))) + { + WARN("Failed to compile shader for shape type %#x, hr %#lx.\n", si->shape_type, hr); + return hr; + } + device->precompiled_shape_vs[i] = compiled; + } + + if (FAILED(hr = D3DCompile(shape_ps_code, sizeof(shape_ps_code) - 1, "ps", NULL, NULL, + "main", "ps_4_0", 0, 0, &compiled, NULL))) + { + WARN("Failed to compile the pixel shader, hr %#lx.\n", hr); + return hr; + } + device->precompiled_shape_ps = compiled; + + return S_OK; }
HRESULT d2d_device_add_indexed_object(struct d2d_indexed_objects *objects, diff --git a/dlls/d2d1/factory.c b/dlls/d2d1/factory.c index aa0fef713d1..1294d8c8fa3 100644 --- a/dlls/d2d1/factory.c +++ b/dlls/d2d1/factory.c @@ -522,7 +522,11 @@ HRESULT d2d_factory_create_device(ID2D1Factory1 *factory, IDXGIDevice *dxgi_devi if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY;
- d2d_device_init(object, factory, dxgi_device, allow_get_dxgi_device); + if (FAILED(hr = d2d_device_init(object, factory, dxgi_device, allow_get_dxgi_device))) + { + ID2D1Device6_Release(&object->ID2D1Device6_iface); + return hr; + }
TRACE("Create device %p.\n", object);