d2d1: Implement d2d_d3d_render_target_RestoreDrawingState().
[wine.git] / dlls / d2d1 / render_target.c
blobda8937cf5133125bf7a7d2b0e77b03cf875244e6
1 /*
2 * Copyright 2014 Henri Verbeet for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
20 #include "wine/port.h"
22 #include "d2d1_private.h"
23 #include "wincodec.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(d2d);
27 #define INITIAL_CLIP_STACK_SIZE 4
29 struct d2d_draw_text_layout_ctx
31 ID2D1Brush *brush;
32 D2D1_DRAW_TEXT_OPTIONS options;
35 static void d2d_point_transform(D2D1_POINT_2F *dst, const D2D1_MATRIX_3X2_F *matrix, float x, float y)
37 dst->x = x * matrix->_11 + y * matrix->_21 + matrix->_31;
38 dst->y = x * matrix->_12 + y * matrix->_22 + matrix->_32;
41 static void d2d_rect_expand(D2D1_RECT_F *dst, const D2D1_POINT_2F *point)
43 if (point->x < dst->left)
44 dst->left = point->x;
45 if (point->y < dst->top)
46 dst->top = point->y;
47 if (point->x > dst->right)
48 dst->right = point->x;
49 if (point->y > dst->bottom)
50 dst->bottom = point->y;
53 static void d2d_rect_intersect(D2D1_RECT_F *dst, const D2D1_RECT_F *src)
55 if (src->left > dst->left)
56 dst->left = src->left;
57 if (src->top > dst->top)
58 dst->top = src->top;
59 if (src->right < dst->right)
60 dst->right = src->right;
61 if (src->bottom < dst->bottom)
62 dst->bottom = src->bottom;
65 static void d2d_rect_set(D2D1_RECT_F *dst, float left, float top, float right, float bottom)
67 dst->left = left;
68 dst->top = top;
69 dst->right = right;
70 dst->bottom = bottom;
73 static BOOL d2d_clip_stack_init(struct d2d_clip_stack *stack)
75 if (!(stack->stack = HeapAlloc(GetProcessHeap(), 0, INITIAL_CLIP_STACK_SIZE * sizeof(*stack->stack))))
76 return FALSE;
78 stack->size = INITIAL_CLIP_STACK_SIZE;
79 stack->count = 0;
81 return TRUE;
84 static void d2d_clip_stack_cleanup(struct d2d_clip_stack *stack)
86 HeapFree(GetProcessHeap(), 0, stack->stack);
89 static BOOL d2d_clip_stack_push(struct d2d_clip_stack *stack, const D2D1_RECT_F *rect)
91 D2D1_RECT_F r;
93 if (stack->count == stack->size)
95 D2D1_RECT_F *new_stack;
96 unsigned int new_size;
98 if (stack->size > UINT_MAX / 2)
99 return FALSE;
101 new_size = stack->size * 2;
102 if (!(new_stack = HeapReAlloc(GetProcessHeap(), 0, stack->stack, new_size * sizeof(*stack->stack))))
103 return FALSE;
105 stack->stack = new_stack;
106 stack->size = new_size;
109 r = *rect;
110 if (stack->count)
111 d2d_rect_intersect(&r, &stack->stack[stack->count - 1]);
112 stack->stack[stack->count++] = r;
114 return TRUE;
117 static void d2d_clip_stack_pop(struct d2d_clip_stack *stack)
119 if (!stack->count)
120 return;
121 --stack->count;
124 static void d2d_draw(struct d2d_d3d_render_target *render_target, ID3D10Buffer *vs_cb,
125 ID3D10PixelShader *ps, ID3D10Buffer *ps_cb, struct d2d_brush *brush)
127 ID3D10Device *device = render_target->device;
128 unsigned int offset;
129 D3D10_VIEWPORT vp;
130 HRESULT hr;
131 static const float blend_factor[] = {1.0f, 1.0f, 1.0f, 1.0f};
133 vp.TopLeftX = 0;
134 vp.TopLeftY = 0;
135 vp.Width = render_target->pixel_size.width;
136 vp.Height = render_target->pixel_size.height;
137 vp.MinDepth = 0.0f;
138 vp.MaxDepth = 1.0f;
140 if (FAILED(hr = render_target->stateblock->lpVtbl->Capture(render_target->stateblock)))
142 WARN("Failed to capture stateblock, hr %#x.\n", hr);
143 return;
146 ID3D10Device_ClearState(device);
148 ID3D10Device_IASetInputLayout(device, render_target->il);
149 ID3D10Device_IASetPrimitiveTopology(device, D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
150 offset = 0;
151 ID3D10Device_IASetVertexBuffers(device, 0, 1, &render_target->vb,
152 &render_target->vb_stride, &offset);
153 ID3D10Device_VSSetConstantBuffers(device, 0, 1, &vs_cb);
154 ID3D10Device_VSSetShader(device, render_target->vs);
155 ID3D10Device_PSSetConstantBuffers(device, 0, 1, &ps_cb);
156 ID3D10Device_PSSetShader(device, ps);
157 ID3D10Device_RSSetViewports(device, 1, &vp);
158 if (render_target->clip_stack.count)
160 const D2D1_RECT_F *clip_rect;
161 D3D10_RECT scissor_rect;
163 clip_rect = &render_target->clip_stack.stack[render_target->clip_stack.count - 1];
164 scissor_rect.left = clip_rect->left + 0.5f;
165 scissor_rect.top = clip_rect->top + 0.5f;
166 scissor_rect.right = clip_rect->right + 0.5f;
167 scissor_rect.bottom = clip_rect->bottom + 0.5f;
168 ID3D10Device_RSSetScissorRects(device, 1, &scissor_rect);
169 ID3D10Device_RSSetState(device, render_target->rs);
171 ID3D10Device_OMSetRenderTargets(device, 1, &render_target->view, NULL);
172 if (brush)
174 ID3D10Device_OMSetBlendState(device, render_target->bs, blend_factor, D3D10_DEFAULT_SAMPLE_MASK);
175 d2d_brush_bind_resources(brush, device);
178 ID3D10Device_Draw(device, 4, 0);
180 if (FAILED(hr = render_target->stateblock->lpVtbl->Apply(render_target->stateblock)))
181 WARN("Failed to apply stateblock, hr %#x.\n", hr);
184 static inline struct d2d_d3d_render_target *impl_from_ID2D1RenderTarget(ID2D1RenderTarget *iface)
186 return CONTAINING_RECORD(iface, struct d2d_d3d_render_target, ID2D1RenderTarget_iface);
189 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_QueryInterface(ID2D1RenderTarget *iface, REFIID iid, void **out)
191 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
193 if (IsEqualGUID(iid, &IID_ID2D1RenderTarget)
194 || IsEqualGUID(iid, &IID_ID2D1Resource)
195 || IsEqualGUID(iid, &IID_IUnknown))
197 ID2D1RenderTarget_AddRef(iface);
198 *out = iface;
199 return S_OK;
202 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
204 *out = NULL;
205 return E_NOINTERFACE;
208 static ULONG STDMETHODCALLTYPE d2d_d3d_render_target_AddRef(ID2D1RenderTarget *iface)
210 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
211 ULONG refcount = InterlockedIncrement(&render_target->refcount);
213 TRACE("%p increasing refcount to %u.\n", iface, refcount);
215 return refcount;
218 static ULONG STDMETHODCALLTYPE d2d_d3d_render_target_Release(ID2D1RenderTarget *iface)
220 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
221 ULONG refcount = InterlockedDecrement(&render_target->refcount);
223 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
225 if (!refcount)
227 d2d_clip_stack_cleanup(&render_target->clip_stack);
228 if (render_target->text_rendering_params)
229 IDWriteRenderingParams_Release(render_target->text_rendering_params);
230 ID3D10PixelShader_Release(render_target->rect_bitmap_ps);
231 ID3D10PixelShader_Release(render_target->rect_solid_ps);
232 ID3D10BlendState_Release(render_target->bs);
233 ID3D10RasterizerState_Release(render_target->rs);
234 ID3D10VertexShader_Release(render_target->vs);
235 ID3D10Buffer_Release(render_target->vb);
236 ID3D10InputLayout_Release(render_target->il);
237 render_target->stateblock->lpVtbl->Release(render_target->stateblock);
238 ID3D10RenderTargetView_Release(render_target->view);
239 ID3D10Device_Release(render_target->device);
240 ID2D1Factory_Release(render_target->factory);
241 HeapFree(GetProcessHeap(), 0, render_target);
244 return refcount;
247 static void STDMETHODCALLTYPE d2d_d3d_render_target_GetFactory(ID2D1RenderTarget *iface, ID2D1Factory **factory)
249 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
251 TRACE("iface %p, factory %p.\n", iface, factory);
253 *factory = render_target->factory;
254 ID2D1Factory_AddRef(*factory);
257 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateBitmap(ID2D1RenderTarget *iface,
258 D2D1_SIZE_U size, const void *src_data, UINT32 pitch, const D2D1_BITMAP_PROPERTIES *desc, ID2D1Bitmap **bitmap)
260 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
261 struct d2d_bitmap *object;
262 HRESULT hr;
264 TRACE("iface %p, size {%u, %u}, src_data %p, pitch %u, desc %p, bitmap %p.\n",
265 iface, size.width, size.height, src_data, pitch, desc, bitmap);
267 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
268 return E_OUTOFMEMORY;
270 if (FAILED(hr = d2d_bitmap_init(object, render_target, size, src_data, pitch, desc)))
272 WARN("Failed to initialize bitmap, hr %#x.\n", hr);
273 HeapFree(GetProcessHeap(), 0, object);
274 return hr;
277 TRACE("Created bitmap %p.\n", object);
278 *bitmap = &object->ID2D1Bitmap_iface;
280 return S_OK;
283 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateBitmapFromWicBitmap(ID2D1RenderTarget *iface,
284 IWICBitmapSource *bitmap_source, const D2D1_BITMAP_PROPERTIES *desc, ID2D1Bitmap **bitmap)
286 D2D1_BITMAP_PROPERTIES bitmap_desc;
287 unsigned int bpp, data_size;
288 D2D1_SIZE_U size;
289 WICRect rect;
290 UINT32 pitch;
291 HRESULT hr;
292 void *data;
294 TRACE("iface %p, bitmap_source %p, desc %p, bitmap %p.\n",
295 iface, bitmap_source, desc, bitmap);
297 if (FAILED(hr = IWICBitmapSource_GetSize(bitmap_source, &size.width, &size.height)))
299 WARN("Failed to get bitmap size, hr %#x.\n", hr);
300 return hr;
303 if (!desc)
305 bitmap_desc.pixelFormat.format = DXGI_FORMAT_UNKNOWN;
306 bitmap_desc.pixelFormat.alphaMode = D2D1_ALPHA_MODE_UNKNOWN;
307 bitmap_desc.dpiX = 0.0f;
308 bitmap_desc.dpiY = 0.0f;
310 else
312 bitmap_desc = *desc;
315 if (bitmap_desc.pixelFormat.format == DXGI_FORMAT_UNKNOWN)
317 WICPixelFormatGUID wic_format;
319 if (FAILED(hr = IWICBitmapSource_GetPixelFormat(bitmap_source, &wic_format)))
321 WARN("Failed to get bitmap format, hr %#x.\n", hr);
322 return hr;
325 if (IsEqualGUID(&wic_format, &GUID_WICPixelFormat32bppPBGRA)
326 || IsEqualGUID(&wic_format, &GUID_WICPixelFormat32bppBGR))
328 bitmap_desc.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
330 else
332 WARN("Unsupported WIC bitmap format %s.\n", debugstr_guid(&wic_format));
333 return D2DERR_UNSUPPORTED_PIXEL_FORMAT;
337 switch (bitmap_desc.pixelFormat.format)
339 case DXGI_FORMAT_B8G8R8A8_UNORM:
340 bpp = 4;
341 break;
343 default:
344 FIXME("Unhandled format %#x.\n", bitmap_desc.pixelFormat.format);
345 return D2DERR_UNSUPPORTED_PIXEL_FORMAT;
348 pitch = ((bpp * size.width) + 15) & ~15;
349 data_size = pitch * size.height;
350 if (!(data = HeapAlloc(GetProcessHeap(), 0, data_size)))
351 return E_OUTOFMEMORY;
353 rect.X = 0;
354 rect.Y = 0;
355 rect.Width = size.width;
356 rect.Height = size.height;
357 if (FAILED(hr = IWICBitmapSource_CopyPixels(bitmap_source, &rect, pitch, data_size, data)))
359 WARN("Failed to copy bitmap pixels, hr %#x.\n", hr);
360 HeapFree(GetProcessHeap(), 0, data);
361 return hr;
364 hr = d2d_d3d_render_target_CreateBitmap(iface, size, data, pitch, &bitmap_desc, bitmap);
366 HeapFree(GetProcessHeap(), 0, data);
368 return hr;
371 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateSharedBitmap(ID2D1RenderTarget *iface,
372 REFIID iid, void *data, const D2D1_BITMAP_PROPERTIES *desc, ID2D1Bitmap **bitmap)
374 FIXME("iface %p, iid %s, data %p, desc %p, bitmap %p stub!\n",
375 iface, debugstr_guid(iid), data, desc, bitmap);
377 return E_NOTIMPL;
380 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateBitmapBrush(ID2D1RenderTarget *iface,
381 ID2D1Bitmap *bitmap, const D2D1_BITMAP_BRUSH_PROPERTIES *bitmap_brush_desc,
382 const D2D1_BRUSH_PROPERTIES *brush_desc, ID2D1BitmapBrush **brush)
384 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
385 struct d2d_brush *object;
386 HRESULT hr;
388 TRACE("iface %p, bitmap %p, bitmap_brush_desc %p, brush_desc %p, brush %p.\n",
389 iface, bitmap, bitmap_brush_desc, brush_desc, brush);
391 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
392 return E_OUTOFMEMORY;
394 if (FAILED(hr = d2d_bitmap_brush_init(object, render_target, bitmap, bitmap_brush_desc, brush_desc)))
396 WARN("Failed to initialize brush, hr %#x.\n", hr);
397 HeapFree(GetProcessHeap(), 0, object);
398 return hr;
401 TRACE("Created brush %p.\n", object);
402 *brush = (ID2D1BitmapBrush *)&object->ID2D1Brush_iface;
404 return S_OK;
407 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateSolidColorBrush(ID2D1RenderTarget *iface,
408 const D2D1_COLOR_F *color, const D2D1_BRUSH_PROPERTIES *desc, ID2D1SolidColorBrush **brush)
410 struct d2d_brush *object;
412 TRACE("iface %p, color %p, desc %p, brush %p.\n", iface, color, desc, brush);
414 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
415 return E_OUTOFMEMORY;
417 d2d_solid_color_brush_init(object, iface, color, desc);
419 TRACE("Created brush %p.\n", object);
420 *brush = (ID2D1SolidColorBrush *)&object->ID2D1Brush_iface;
422 return S_OK;
425 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateGradientStopCollection(ID2D1RenderTarget *iface,
426 const D2D1_GRADIENT_STOP *stops, UINT32 stop_count, D2D1_GAMMA gamma, D2D1_EXTEND_MODE extend_mode,
427 ID2D1GradientStopCollection **gradient)
429 struct d2d_gradient *object;
430 HRESULT hr;
432 TRACE("iface %p, stops %p, stop_count %u, gamma %#x, extend_mode %#x, gradient %p.\n",
433 iface, stops, stop_count, gamma, extend_mode, gradient);
435 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
436 return E_OUTOFMEMORY;
438 if (FAILED(hr = d2d_gradient_init(object, iface, stops, stop_count, gamma, extend_mode)))
440 WARN("Failed to initialize gradient, hr %#x.\n", hr);
441 HeapFree(GetProcessHeap(), 0, object);
442 return hr;
445 TRACE("Created gradient %p.\n", object);
446 *gradient = &object->ID2D1GradientStopCollection_iface;
448 return S_OK;
451 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateLinearGradientBrush(ID2D1RenderTarget *iface,
452 const D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES *gradient_brush_desc, const D2D1_BRUSH_PROPERTIES *brush_desc,
453 ID2D1GradientStopCollection *gradient, ID2D1LinearGradientBrush **brush)
455 struct d2d_brush *object;
457 TRACE("iface %p, gradient_brush_desc %p, brush_desc %p, gradient %p, brush %p.\n",
458 iface, gradient_brush_desc, brush_desc, gradient, brush);
460 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
461 return E_OUTOFMEMORY;
463 d2d_linear_gradient_brush_init(object, iface, gradient_brush_desc, brush_desc, gradient);
465 TRACE("Created brush %p.\n", object);
466 *brush = (ID2D1LinearGradientBrush *)&object->ID2D1Brush_iface;
468 return S_OK;
471 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateRadialGradientBrush(ID2D1RenderTarget *iface,
472 const D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES *gradient_brush_desc, const D2D1_BRUSH_PROPERTIES *brush_desc,
473 ID2D1GradientStopCollection *gradient, ID2D1RadialGradientBrush **brush)
475 FIXME("iface %p, gradient_brush_desc %p, brush_desc %p, gradient %p, brush %p stub!\n",
476 iface, gradient_brush_desc, brush_desc, gradient, brush);
478 return E_NOTIMPL;
481 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateCompatibleRenderTarget(ID2D1RenderTarget *iface,
482 const D2D1_SIZE_F *size, const D2D1_SIZE_U *pixel_size, const D2D1_PIXEL_FORMAT *format,
483 D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS options, ID2D1BitmapRenderTarget **render_target)
485 FIXME("iface %p, size %p, pixel_size %p, format %p, options %#x, render_target %p stub!\n",
486 iface, size, pixel_size, format, options, render_target);
488 return E_NOTIMPL;
491 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateLayer(ID2D1RenderTarget *iface,
492 const D2D1_SIZE_F *size, ID2D1Layer **layer)
494 FIXME("iface %p, size %p, layer %p stub!\n", iface, size, layer);
496 return E_NOTIMPL;
499 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateMesh(ID2D1RenderTarget *iface, ID2D1Mesh **mesh)
501 struct d2d_mesh *object;
503 TRACE("iface %p, mesh %p.\n", iface, mesh);
505 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
506 return E_OUTOFMEMORY;
508 d2d_mesh_init(object);
510 TRACE("Created mesh %p.\n", object);
511 *mesh = &object->ID2D1Mesh_iface;
513 return S_OK;
516 static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawLine(ID2D1RenderTarget *iface,
517 D2D1_POINT_2F p0, D2D1_POINT_2F p1, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
519 FIXME("iface %p, p0 {%.8e, %.8e}, p1 {%.8e, %.8e}, brush %p, stroke_width %.8e, stroke_style %p stub!\n",
520 iface, p0.x, p0.y, p1.x, p1.y, brush, stroke_width, stroke_style);
523 static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawRectangle(ID2D1RenderTarget *iface,
524 const D2D1_RECT_F *rect, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
526 FIXME("iface %p, rect %p, brush %p, stroke_width %.8e, stroke_style %p stub!\n",
527 iface, rect, brush, stroke_width, stroke_style);
530 static void STDMETHODCALLTYPE d2d_d3d_render_target_FillRectangle(ID2D1RenderTarget *iface,
531 const D2D1_RECT_F *rect, ID2D1Brush *brush)
533 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
534 struct d2d_brush *brush_impl = unsafe_impl_from_ID2D1Brush(brush);
535 D3D10_SUBRESOURCE_DATA buffer_data;
536 D3D10_BUFFER_DESC buffer_desc;
537 ID3D10Buffer *vs_cb, *ps_cb;
538 ID3D10PixelShader *ps;
539 D2D1_COLOR_F color;
540 float tmp_x, tmp_y;
541 HRESULT hr;
542 struct
544 float _11, _21, _31, pad0;
545 float _12, _22, _32, pad1;
546 } transform, transform_inverse;
548 TRACE("iface %p, rect %p, brush %p.\n", iface, rect, brush);
550 if (brush_impl->type != D2D_BRUSH_TYPE_SOLID
551 && brush_impl->type != D2D_BRUSH_TYPE_BITMAP)
553 FIXME("Unhandled brush type %#x.\n", brush_impl->type);
554 return;
557 /* Translate from clip space to world (D2D rendertarget) space, taking the
558 * dpi and rendertarget transform into account. */
559 tmp_x = (2.0f * render_target->dpi_x) / (96.0f * render_target->pixel_size.width);
560 tmp_y = -(2.0f * render_target->dpi_y) / (96.0f * render_target->pixel_size.height);
561 transform._11 = render_target->drawing_state.transform._11 * tmp_x;
562 transform._21 = render_target->drawing_state.transform._21 * tmp_x;
563 transform._31 = render_target->drawing_state.transform._31 * tmp_x - 1.0f;
564 transform.pad0 = 0.0f;
565 transform._12 = render_target->drawing_state.transform._12 * tmp_y;
566 transform._22 = render_target->drawing_state.transform._22 * tmp_y;
567 transform._32 = render_target->drawing_state.transform._32 * tmp_y + 1.0f;
568 transform.pad1 = 0.0f;
570 /* Translate from world space to object space. */
571 tmp_x = rect->left + (rect->right - rect->left) / 2.0f;
572 tmp_y = rect->top + (rect->bottom - rect->top) / 2.0f;
573 transform._31 += tmp_x * transform._11 + tmp_y * transform._21;
574 transform._32 += tmp_x * transform._12 + tmp_y * transform._22;
575 tmp_x = (rect->right - rect->left) / 2.0f;
576 tmp_y = (rect->bottom - rect->top) / 2.0f;
577 transform._11 *= tmp_x;
578 transform._12 *= tmp_x;
579 transform._21 *= tmp_y;
580 transform._22 *= tmp_y;
582 buffer_desc.ByteWidth = sizeof(transform);
583 buffer_desc.Usage = D3D10_USAGE_DEFAULT;
584 buffer_desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
585 buffer_desc.CPUAccessFlags = 0;
586 buffer_desc.MiscFlags = 0;
588 buffer_data.pSysMem = &transform;
589 buffer_data.SysMemPitch = 0;
590 buffer_data.SysMemSlicePitch = 0;
592 if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &vs_cb)))
594 WARN("Failed to create constant buffer, hr %#x.\n", hr);
595 return;
598 if (brush_impl->type == D2D_BRUSH_TYPE_BITMAP)
600 struct d2d_bitmap *bitmap = brush_impl->u.bitmap.bitmap;
601 float rt_scale, rt_bitmap_scale, d;
603 ps = render_target->rect_bitmap_ps;
605 /* Scale for bitmap size and dpi. */
606 rt_scale = render_target->dpi_x / 96.0f;
607 rt_bitmap_scale = bitmap->pixel_size.width * (bitmap->dpi_x / 96.0f) * rt_scale;
608 transform._11 = brush_impl->transform._11 * rt_bitmap_scale;
609 transform._21 = brush_impl->transform._21 * rt_bitmap_scale;
610 transform._31 = brush_impl->transform._31 * rt_scale;
611 rt_scale = render_target->dpi_y / 96.0f;
612 rt_bitmap_scale = bitmap->pixel_size.height * (bitmap->dpi_y / 96.0f) * rt_scale;
613 transform._12 = brush_impl->transform._12 * rt_bitmap_scale;
614 transform._22 = brush_impl->transform._22 * rt_bitmap_scale;
615 transform._32 = brush_impl->transform._32 * rt_scale;
617 /* Invert the matrix. (Because the matrix is applied to the sampling
618 * coordinates. I.e., to scale the bitmap by 2 we need to divide the
619 * coordinates by 2.) */
620 d = transform._11 * transform._22 - transform._21 * transform._22;
621 if (d != 0.0f)
623 transform_inverse._11 = transform._22 / d;
624 transform_inverse._21 = -transform._21 / d;
625 transform_inverse._31 = (transform._21 * transform._32 - transform._31 * transform._22) / d;
626 transform_inverse._12 = -transform._12 / d;
627 transform_inverse._22 = transform._11 / d;
628 transform_inverse._32 = -(transform._11 * transform._32 - transform._31 * transform._12) / d;
631 buffer_desc.ByteWidth = sizeof(transform_inverse);
632 buffer_data.pSysMem = &transform_inverse;
634 else
636 ps = render_target->rect_solid_ps;
638 color = brush_impl->u.solid.color;
639 color.r *= brush_impl->opacity;
640 color.g *= brush_impl->opacity;
641 color.b *= brush_impl->opacity;
642 color.a *= brush_impl->opacity;
644 buffer_desc.ByteWidth = sizeof(color);
645 buffer_data.pSysMem = &color;
648 if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &ps_cb)))
650 WARN("Failed to create constant buffer, hr %#x.\n", hr);
651 ID3D10Buffer_Release(vs_cb);
652 return;
655 d2d_draw(render_target, vs_cb, ps, ps_cb, brush_impl);
657 ID3D10Buffer_Release(ps_cb);
658 ID3D10Buffer_Release(vs_cb);
661 static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawRoundedRectangle(ID2D1RenderTarget *iface,
662 const D2D1_ROUNDED_RECT *rect, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
664 FIXME("iface %p, rect %p, brush %p, stroke_width %.8e, stroke_style %p stub!\n",
665 iface, rect, brush, stroke_width, stroke_style);
668 static void STDMETHODCALLTYPE d2d_d3d_render_target_FillRoundedRectangle(ID2D1RenderTarget *iface,
669 const D2D1_ROUNDED_RECT *rect, ID2D1Brush *brush)
671 FIXME("iface %p, rect %p, brush %p stub!\n", iface, rect, brush);
674 static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawEllipse(ID2D1RenderTarget *iface,
675 const D2D1_ELLIPSE *ellipse, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
677 FIXME("iface %p, ellipse %p, brush %p, stroke_width %.8e, stroke_style %p stub!\n",
678 iface, ellipse, brush, stroke_width, stroke_style);
681 static void STDMETHODCALLTYPE d2d_d3d_render_target_FillEllipse(ID2D1RenderTarget *iface,
682 const D2D1_ELLIPSE *ellipse, ID2D1Brush *brush)
684 FIXME("iface %p, ellipse %p, brush %p stub!\n", iface, ellipse, brush);
687 static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawGeometry(ID2D1RenderTarget *iface,
688 ID2D1Geometry *geometry, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
690 FIXME("iface %p, geometry %p, brush %p, stroke_width %.8e, stroke_style %p stub!\n",
691 iface, geometry, brush, stroke_width, stroke_style);
694 static void STDMETHODCALLTYPE d2d_d3d_render_target_FillGeometry(ID2D1RenderTarget *iface,
695 ID2D1Geometry *geometry, ID2D1Brush *brush, ID2D1Brush *opacity_brush)
697 FIXME("iface %p, geometry %p, brush %p, opacity_brush %p stub!\n", iface, geometry, brush, opacity_brush);
700 static void STDMETHODCALLTYPE d2d_d3d_render_target_FillMesh(ID2D1RenderTarget *iface,
701 ID2D1Mesh *mesh, ID2D1Brush *brush)
703 FIXME("iface %p, mesh %p, brush %p stub!\n", iface, mesh, brush);
706 static void STDMETHODCALLTYPE d2d_d3d_render_target_FillOpacityMask(ID2D1RenderTarget *iface,
707 ID2D1Bitmap *mask, ID2D1Brush *brush, D2D1_OPACITY_MASK_CONTENT content,
708 const D2D1_RECT_F *dst_rect, const D2D1_RECT_F *src_rect)
710 FIXME("iface %p, mask %p, brush %p, content %#x, dst_rect %p, src_rect %p stub!\n",
711 iface, mask, brush, content, dst_rect, src_rect);
714 static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawBitmap(ID2D1RenderTarget *iface,
715 ID2D1Bitmap *bitmap, const D2D1_RECT_F *dst_rect, float opacity,
716 D2D1_BITMAP_INTERPOLATION_MODE interpolation_mode, const D2D1_RECT_F *src_rect)
718 D2D1_BITMAP_BRUSH_PROPERTIES bitmap_brush_desc;
719 D2D1_BRUSH_PROPERTIES brush_desc;
720 ID2D1BitmapBrush *brush;
721 D2D1_RECT_F s, d;
722 HRESULT hr;
724 TRACE("iface %p, bitmap %p, dst_rect %p, opacity %.8e, interpolation_mode %#x, src_rect %p.\n",
725 iface, bitmap, dst_rect, opacity, interpolation_mode, src_rect);
727 if (src_rect)
729 s = *src_rect;
731 else
733 D2D1_SIZE_F size;
735 size = ID2D1Bitmap_GetSize(bitmap);
736 s.left = 0.0f;
737 s.top = 0.0f;
738 s.right = size.width;
739 s.bottom = size.height;
742 if (dst_rect)
744 d = *dst_rect;
746 else
748 d.left = 0.0f;
749 d.top = 0.0f;
750 d.right = s.right - s.left;
751 d.bottom = s.bottom - s.top;
754 bitmap_brush_desc.extendModeX = D2D1_EXTEND_MODE_CLAMP;
755 bitmap_brush_desc.extendModeY = D2D1_EXTEND_MODE_CLAMP;
756 bitmap_brush_desc.interpolationMode = interpolation_mode;
758 brush_desc.opacity = opacity;
759 brush_desc.transform._11 = (d.right - d.left) / (s.right - s.left);
760 brush_desc.transform._21 = 0.0f;
761 brush_desc.transform._31 = d.left - s.left;
762 brush_desc.transform._12 = 0.0f;
763 brush_desc.transform._22 = (d.bottom - d.top) / (s.bottom - s.top);
764 brush_desc.transform._32 = d.top - s.top;
766 if (FAILED(hr = ID2D1RenderTarget_CreateBitmapBrush(iface, bitmap, &bitmap_brush_desc, &brush_desc, &brush)))
768 ERR("Failed to create bitmap brush, hr %#x.\n", hr);
769 return;
772 ID2D1RenderTarget_FillRectangle(iface, &d, (ID2D1Brush *)brush);
773 ID2D1BitmapBrush_Release(brush);
776 static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawText(ID2D1RenderTarget *iface,
777 const WCHAR *string, UINT32 string_len, IDWriteTextFormat *text_format, const D2D1_RECT_F *layout_rect,
778 ID2D1Brush *brush, D2D1_DRAW_TEXT_OPTIONS options, DWRITE_MEASURING_MODE measuring_mode)
780 FIXME("iface %p, string %s, string_len %u, text_format %p, layout_rect %p, "
781 "brush %p, options %#x, measuring_mode %#x stub!\n",
782 iface, debugstr_wn(string, string_len), string_len, text_format, layout_rect,
783 brush, options, measuring_mode);
786 static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawTextLayout(ID2D1RenderTarget *iface,
787 D2D1_POINT_2F origin, IDWriteTextLayout *layout, ID2D1Brush *brush, D2D1_DRAW_TEXT_OPTIONS options)
789 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
790 struct d2d_draw_text_layout_ctx ctx;
791 HRESULT hr;
793 TRACE("iface %p, origin {%.8e, %.8e}, layout %p, brush %p, options %#x.\n",
794 iface, origin.x, origin.y, layout, brush, options);
796 ctx.brush = brush;
797 ctx.options = options;
799 if (FAILED(hr = IDWriteTextLayout_Draw(layout,
800 &ctx, &render_target->IDWriteTextRenderer_iface, origin.x, origin.y)))
801 FIXME("Failed to draw text layout, hr %#x.\n", hr);
804 static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawGlyphRun(ID2D1RenderTarget *iface,
805 D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run, ID2D1Brush *brush,
806 DWRITE_MEASURING_MODE measuring_mode)
808 FIXME("iface %p, baseline_origin {%.8e, %.8e}, glyph_run %p, brush %p, measuring_mode %#x stub!\n",
809 iface, baseline_origin.x, baseline_origin.y, glyph_run, brush, measuring_mode);
812 static void STDMETHODCALLTYPE d2d_d3d_render_target_SetTransform(ID2D1RenderTarget *iface,
813 const D2D1_MATRIX_3X2_F *transform)
815 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
817 TRACE("iface %p, transform %p.\n", iface, transform);
819 render_target->drawing_state.transform = *transform;
822 static void STDMETHODCALLTYPE d2d_d3d_render_target_GetTransform(ID2D1RenderTarget *iface,
823 D2D1_MATRIX_3X2_F *transform)
825 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
827 TRACE("iface %p, transform %p.\n", iface, transform);
829 *transform = render_target->drawing_state.transform;
832 static void STDMETHODCALLTYPE d2d_d3d_render_target_SetAntialiasMode(ID2D1RenderTarget *iface,
833 D2D1_ANTIALIAS_MODE antialias_mode)
835 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
837 TRACE("iface %p, antialias_mode %#x stub!\n", iface, antialias_mode);
839 render_target->drawing_state.antialiasMode = antialias_mode;
842 static D2D1_ANTIALIAS_MODE STDMETHODCALLTYPE d2d_d3d_render_target_GetAntialiasMode(ID2D1RenderTarget *iface)
844 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
846 TRACE("iface %p.\n", iface);
848 return render_target->drawing_state.antialiasMode;
851 static void STDMETHODCALLTYPE d2d_d3d_render_target_SetTextAntialiasMode(ID2D1RenderTarget *iface,
852 D2D1_TEXT_ANTIALIAS_MODE antialias_mode)
854 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
856 TRACE("iface %p, antialias_mode %#x.\n", iface, antialias_mode);
858 render_target->drawing_state.textAntialiasMode = antialias_mode;
861 static D2D1_TEXT_ANTIALIAS_MODE STDMETHODCALLTYPE d2d_d3d_render_target_GetTextAntialiasMode(ID2D1RenderTarget *iface)
863 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
865 TRACE("iface %p.\n", iface);
867 return render_target->drawing_state.textAntialiasMode;
870 static void STDMETHODCALLTYPE d2d_d3d_render_target_SetTextRenderingParams(ID2D1RenderTarget *iface,
871 IDWriteRenderingParams *text_rendering_params)
873 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
875 TRACE("iface %p, text_rendering_params %p.\n", iface, text_rendering_params);
877 if (text_rendering_params)
878 IDWriteRenderingParams_AddRef(text_rendering_params);
879 if (render_target->text_rendering_params)
880 IDWriteRenderingParams_Release(render_target->text_rendering_params);
881 render_target->text_rendering_params = text_rendering_params;
884 static void STDMETHODCALLTYPE d2d_d3d_render_target_GetTextRenderingParams(ID2D1RenderTarget *iface,
885 IDWriteRenderingParams **text_rendering_params)
887 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
889 TRACE("iface %p, text_rendering_params %p.\n", iface, text_rendering_params);
891 if ((*text_rendering_params = render_target->text_rendering_params))
892 IDWriteRenderingParams_AddRef(*text_rendering_params);
895 static void STDMETHODCALLTYPE d2d_d3d_render_target_SetTags(ID2D1RenderTarget *iface, D2D1_TAG tag1, D2D1_TAG tag2)
897 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
899 TRACE("iface %p, tag1 %s, tag2 %s.\n", iface, wine_dbgstr_longlong(tag1), wine_dbgstr_longlong(tag2));
901 render_target->drawing_state.tag1 = tag1;
902 render_target->drawing_state.tag2 = tag2;
905 static void STDMETHODCALLTYPE d2d_d3d_render_target_GetTags(ID2D1RenderTarget *iface, D2D1_TAG *tag1, D2D1_TAG *tag2)
907 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
909 TRACE("iface %p, tag1 %p, tag2 %p.\n", iface, tag1, tag2);
911 *tag1 = render_target->drawing_state.tag1;
912 *tag2 = render_target->drawing_state.tag2;
915 static void STDMETHODCALLTYPE d2d_d3d_render_target_PushLayer(ID2D1RenderTarget *iface,
916 const D2D1_LAYER_PARAMETERS *layer_parameters, ID2D1Layer *layer)
918 FIXME("iface %p, layer_parameters %p, layer %p stub!\n", iface, layer_parameters, layer);
921 static void STDMETHODCALLTYPE d2d_d3d_render_target_PopLayer(ID2D1RenderTarget *iface)
923 FIXME("iface %p stub!\n", iface);
926 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_Flush(ID2D1RenderTarget *iface, D2D1_TAG *tag1, D2D1_TAG *tag2)
928 FIXME("iface %p, tag1 %p, tag2 %p stub!\n", iface, tag1, tag2);
930 return E_NOTIMPL;
933 static void STDMETHODCALLTYPE d2d_d3d_render_target_SaveDrawingState(ID2D1RenderTarget *iface,
934 ID2D1DrawingStateBlock *state_block)
936 struct d2d_state_block *state_block_impl = unsafe_impl_from_ID2D1DrawingStateBlock(state_block);
937 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
939 TRACE("iface %p, state_block %p.\n", iface, state_block);
941 state_block_impl->drawing_state = render_target->drawing_state;
942 if (render_target->text_rendering_params)
943 IDWriteRenderingParams_AddRef(render_target->text_rendering_params);
944 if (state_block_impl->text_rendering_params)
945 IDWriteRenderingParams_Release(state_block_impl->text_rendering_params);
946 state_block_impl->text_rendering_params = render_target->text_rendering_params;
949 static void STDMETHODCALLTYPE d2d_d3d_render_target_RestoreDrawingState(ID2D1RenderTarget *iface,
950 ID2D1DrawingStateBlock *state_block)
952 struct d2d_state_block *state_block_impl = unsafe_impl_from_ID2D1DrawingStateBlock(state_block);
953 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
955 TRACE("iface %p, state_block %p.\n", iface, state_block);
957 render_target->drawing_state = state_block_impl->drawing_state;
958 if (state_block_impl->text_rendering_params)
959 IDWriteRenderingParams_AddRef(state_block_impl->text_rendering_params);
960 if (render_target->text_rendering_params)
961 IDWriteRenderingParams_Release(render_target->text_rendering_params);
962 render_target->text_rendering_params = state_block_impl->text_rendering_params;
965 static void STDMETHODCALLTYPE d2d_d3d_render_target_PushAxisAlignedClip(ID2D1RenderTarget *iface,
966 const D2D1_RECT_F *clip_rect, D2D1_ANTIALIAS_MODE antialias_mode)
968 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
969 D2D1_RECT_F transformed_rect;
970 float x_scale, y_scale;
971 D2D1_POINT_2F point;
973 TRACE("iface %p, clip_rect %p, antialias_mode %#x.\n", iface, clip_rect, antialias_mode);
975 if (antialias_mode != D2D1_ANTIALIAS_MODE_ALIASED)
976 FIXME("Ignoring antialias_mode %#x.\n", antialias_mode);
978 x_scale = render_target->dpi_x / 96.0f;
979 y_scale = render_target->dpi_y / 96.0f;
980 d2d_point_transform(&point, &render_target->drawing_state.transform,
981 clip_rect->left * x_scale, clip_rect->top * y_scale);
982 d2d_rect_set(&transformed_rect, point.x, point.y, point.x, point.y);
983 d2d_point_transform(&point, &render_target->drawing_state.transform,
984 clip_rect->left * x_scale, clip_rect->bottom * y_scale);
985 d2d_rect_expand(&transformed_rect, &point);
986 d2d_point_transform(&point, &render_target->drawing_state.transform,
987 clip_rect->right * x_scale, clip_rect->top * y_scale);
988 d2d_rect_expand(&transformed_rect, &point);
989 d2d_point_transform(&point, &render_target->drawing_state.transform,
990 clip_rect->right * x_scale, clip_rect->bottom * y_scale);
991 d2d_rect_expand(&transformed_rect, &point);
993 if (!d2d_clip_stack_push(&render_target->clip_stack, &transformed_rect))
994 WARN("Failed to push clip rect.\n");
997 static void STDMETHODCALLTYPE d2d_d3d_render_target_PopAxisAlignedClip(ID2D1RenderTarget *iface)
999 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
1001 TRACE("iface %p.\n", iface);
1003 d2d_clip_stack_pop(&render_target->clip_stack);
1006 static void STDMETHODCALLTYPE d2d_d3d_render_target_Clear(ID2D1RenderTarget *iface, const D2D1_COLOR_F *color)
1008 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
1009 D3D10_SUBRESOURCE_DATA buffer_data;
1010 D3D10_BUFFER_DESC buffer_desc;
1011 ID3D10Buffer *vs_cb, *ps_cb;
1012 HRESULT hr;
1014 static const float transform[] =
1016 1.0f, 0.0f, 0.0f, 0.0f,
1017 0.0f, -1.0f, 0.0f, 0.0f,
1020 TRACE("iface %p, color %p.\n", iface, color);
1022 buffer_desc.ByteWidth = sizeof(transform);
1023 buffer_desc.Usage = D3D10_USAGE_DEFAULT;
1024 buffer_desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
1025 buffer_desc.CPUAccessFlags = 0;
1026 buffer_desc.MiscFlags = 0;
1028 buffer_data.pSysMem = transform;
1029 buffer_data.SysMemPitch = 0;
1030 buffer_data.SysMemSlicePitch = 0;
1032 if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &vs_cb)))
1034 WARN("Failed to create constant buffer, hr %#x.\n", hr);
1035 return;
1038 buffer_desc.ByteWidth = sizeof(*color);
1039 buffer_data.pSysMem = color;
1041 if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &ps_cb)))
1043 WARN("Failed to create constant buffer, hr %#x.\n", hr);
1044 ID3D10Buffer_Release(vs_cb);
1045 return;
1048 d2d_draw(render_target, vs_cb, render_target->rect_solid_ps, ps_cb, NULL);
1050 ID3D10Buffer_Release(ps_cb);
1051 ID3D10Buffer_Release(vs_cb);
1054 static void STDMETHODCALLTYPE d2d_d3d_render_target_BeginDraw(ID2D1RenderTarget *iface)
1056 TRACE("iface %p.\n", iface);
1059 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_EndDraw(ID2D1RenderTarget *iface,
1060 D2D1_TAG *tag1, D2D1_TAG *tag2)
1062 TRACE("iface %p, tag1 %p, tag2 %p.\n", iface, tag1, tag2);
1064 if (tag1)
1065 *tag1 = 0;
1066 if (tag2)
1067 *tag2 = 0;
1069 return S_OK;
1072 static D2D1_PIXEL_FORMAT * STDMETHODCALLTYPE d2d_d3d_render_target_GetPixelFormat(ID2D1RenderTarget *iface,
1073 D2D1_PIXEL_FORMAT *format)
1075 FIXME("iface %p, format %p stub!\n", iface, format);
1077 format->format = DXGI_FORMAT_UNKNOWN;
1078 format->alphaMode = D2D1_ALPHA_MODE_UNKNOWN;
1079 return format;
1082 static void STDMETHODCALLTYPE d2d_d3d_render_target_SetDpi(ID2D1RenderTarget *iface, float dpi_x, float dpi_y)
1084 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
1086 TRACE("iface %p, dpi_x %.8e, dpi_y %.8e.\n", iface, dpi_x, dpi_y);
1088 if (dpi_x == 0.0f && dpi_y == 0.0f)
1090 dpi_x = 96.0f;
1091 dpi_y = 96.0f;
1094 render_target->dpi_x = dpi_x;
1095 render_target->dpi_y = dpi_y;
1098 static void STDMETHODCALLTYPE d2d_d3d_render_target_GetDpi(ID2D1RenderTarget *iface, float *dpi_x, float *dpi_y)
1100 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
1102 TRACE("iface %p, dpi_x %p, dpi_y %p.\n", iface, dpi_x, dpi_y);
1104 *dpi_x = render_target->dpi_x;
1105 *dpi_y = render_target->dpi_y;
1108 static D2D1_SIZE_F * STDMETHODCALLTYPE d2d_d3d_render_target_GetSize(ID2D1RenderTarget *iface, D2D1_SIZE_F *size)
1110 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
1112 TRACE("iface %p, size %p.\n", iface, size);
1114 size->width = render_target->pixel_size.width / (render_target->dpi_x / 96.0f);
1115 size->height = render_target->pixel_size.height / (render_target->dpi_y / 96.0f);
1116 return size;
1119 static D2D1_SIZE_U * STDMETHODCALLTYPE d2d_d3d_render_target_GetPixelSize(ID2D1RenderTarget *iface,
1120 D2D1_SIZE_U *pixel_size)
1122 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
1124 TRACE("iface %p, pixel_size %p.\n", iface, pixel_size);
1126 *pixel_size = render_target->pixel_size;
1127 return pixel_size;
1130 static UINT32 STDMETHODCALLTYPE d2d_d3d_render_target_GetMaximumBitmapSize(ID2D1RenderTarget *iface)
1132 FIXME("iface %p stub!\n", iface);
1134 return 0;
1137 static BOOL STDMETHODCALLTYPE d2d_d3d_render_target_IsSupported(ID2D1RenderTarget *iface,
1138 const D2D1_RENDER_TARGET_PROPERTIES *desc)
1140 FIXME("iface %p, desc %p stub!\n", iface, desc);
1142 return FALSE;
1145 static const struct ID2D1RenderTargetVtbl d2d_d3d_render_target_vtbl =
1147 d2d_d3d_render_target_QueryInterface,
1148 d2d_d3d_render_target_AddRef,
1149 d2d_d3d_render_target_Release,
1150 d2d_d3d_render_target_GetFactory,
1151 d2d_d3d_render_target_CreateBitmap,
1152 d2d_d3d_render_target_CreateBitmapFromWicBitmap,
1153 d2d_d3d_render_target_CreateSharedBitmap,
1154 d2d_d3d_render_target_CreateBitmapBrush,
1155 d2d_d3d_render_target_CreateSolidColorBrush,
1156 d2d_d3d_render_target_CreateGradientStopCollection,
1157 d2d_d3d_render_target_CreateLinearGradientBrush,
1158 d2d_d3d_render_target_CreateRadialGradientBrush,
1159 d2d_d3d_render_target_CreateCompatibleRenderTarget,
1160 d2d_d3d_render_target_CreateLayer,
1161 d2d_d3d_render_target_CreateMesh,
1162 d2d_d3d_render_target_DrawLine,
1163 d2d_d3d_render_target_DrawRectangle,
1164 d2d_d3d_render_target_FillRectangle,
1165 d2d_d3d_render_target_DrawRoundedRectangle,
1166 d2d_d3d_render_target_FillRoundedRectangle,
1167 d2d_d3d_render_target_DrawEllipse,
1168 d2d_d3d_render_target_FillEllipse,
1169 d2d_d3d_render_target_DrawGeometry,
1170 d2d_d3d_render_target_FillGeometry,
1171 d2d_d3d_render_target_FillMesh,
1172 d2d_d3d_render_target_FillOpacityMask,
1173 d2d_d3d_render_target_DrawBitmap,
1174 d2d_d3d_render_target_DrawText,
1175 d2d_d3d_render_target_DrawTextLayout,
1176 d2d_d3d_render_target_DrawGlyphRun,
1177 d2d_d3d_render_target_SetTransform,
1178 d2d_d3d_render_target_GetTransform,
1179 d2d_d3d_render_target_SetAntialiasMode,
1180 d2d_d3d_render_target_GetAntialiasMode,
1181 d2d_d3d_render_target_SetTextAntialiasMode,
1182 d2d_d3d_render_target_GetTextAntialiasMode,
1183 d2d_d3d_render_target_SetTextRenderingParams,
1184 d2d_d3d_render_target_GetTextRenderingParams,
1185 d2d_d3d_render_target_SetTags,
1186 d2d_d3d_render_target_GetTags,
1187 d2d_d3d_render_target_PushLayer,
1188 d2d_d3d_render_target_PopLayer,
1189 d2d_d3d_render_target_Flush,
1190 d2d_d3d_render_target_SaveDrawingState,
1191 d2d_d3d_render_target_RestoreDrawingState,
1192 d2d_d3d_render_target_PushAxisAlignedClip,
1193 d2d_d3d_render_target_PopAxisAlignedClip,
1194 d2d_d3d_render_target_Clear,
1195 d2d_d3d_render_target_BeginDraw,
1196 d2d_d3d_render_target_EndDraw,
1197 d2d_d3d_render_target_GetPixelFormat,
1198 d2d_d3d_render_target_SetDpi,
1199 d2d_d3d_render_target_GetDpi,
1200 d2d_d3d_render_target_GetSize,
1201 d2d_d3d_render_target_GetPixelSize,
1202 d2d_d3d_render_target_GetMaximumBitmapSize,
1203 d2d_d3d_render_target_IsSupported,
1206 static inline struct d2d_d3d_render_target *impl_from_IDWriteTextRenderer(IDWriteTextRenderer *iface)
1208 return CONTAINING_RECORD(iface, struct d2d_d3d_render_target, IDWriteTextRenderer_iface);
1211 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_QueryInterface(IDWriteTextRenderer *iface, REFIID iid, void **out)
1213 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
1215 if (IsEqualGUID(iid, &IID_IDWriteTextRenderer)
1216 || IsEqualGUID(iid, &IID_IDWritePixelSnapping)
1217 || IsEqualGUID(iid, &IID_IUnknown))
1219 IDWriteTextRenderer_AddRef(iface);
1220 *out = iface;
1221 return S_OK;
1224 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1226 *out = NULL;
1227 return E_NOINTERFACE;
1230 static ULONG STDMETHODCALLTYPE d2d_text_renderer_AddRef(IDWriteTextRenderer *iface)
1232 struct d2d_d3d_render_target *render_target = impl_from_IDWriteTextRenderer(iface);
1234 TRACE("iface %p.\n", iface);
1236 return d2d_d3d_render_target_AddRef(&render_target->ID2D1RenderTarget_iface);
1239 static ULONG STDMETHODCALLTYPE d2d_text_renderer_Release(IDWriteTextRenderer *iface)
1241 struct d2d_d3d_render_target *render_target = impl_from_IDWriteTextRenderer(iface);
1243 TRACE("iface %p.\n", iface);
1245 return d2d_d3d_render_target_Release(&render_target->ID2D1RenderTarget_iface);
1248 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_IsPixelSnappingDisabled(IDWriteTextRenderer *iface,
1249 void *ctx, BOOL *disabled)
1251 FIXME("iface %p, ctx %p, disabled %p stub!\n", iface, ctx, disabled);
1253 return E_NOTIMPL;
1256 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_GetCurrentTransform(IDWriteTextRenderer *iface,
1257 void *ctx, DWRITE_MATRIX *transform)
1259 FIXME("iface %p, ctx %p, transform %p stub!\n", iface, ctx, transform);
1261 return E_NOTIMPL;
1264 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_GetPixelsPerDip(IDWriteTextRenderer *iface, void *ctx, float *ppd)
1266 FIXME("iface %p, ctx %p, ppd %p stub!\n", iface, ctx, ppd);
1268 return E_NOTIMPL;
1271 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawGlyphRun(IDWriteTextRenderer *iface, void *ctx,
1272 float baseline_origin_x, float baseline_origin_y, DWRITE_MEASURING_MODE measuring_mode,
1273 const DWRITE_GLYPH_RUN *glyph_run, const DWRITE_GLYPH_RUN_DESCRIPTION *desc, IUnknown *effect)
1275 FIXME("iface %p, ctx %p, baseline_origin_x %.8e, baseline_origin_y %.8e, "
1276 "measuring_mode %#x, glyph_run %p, desc %p, effect %p stub!\n",
1277 iface, ctx, baseline_origin_x, baseline_origin_y,
1278 measuring_mode, glyph_run, desc, effect);
1280 return E_NOTIMPL;
1283 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawUnderline(IDWriteTextRenderer *iface, void *ctx,
1284 float baseline_origin_x, float baseline_origin_y, const DWRITE_UNDERLINE *underline, IUnknown *effect)
1286 FIXME("iface %p, ctx %p, baseline_origin_x %.8e, baseline_origin_y %.8e, underline %p, effect %p stub!\n",
1287 iface, ctx, baseline_origin_x, baseline_origin_y, underline, effect);
1289 return E_NOTIMPL;
1292 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawStrikethrough(IDWriteTextRenderer *iface, void *ctx,
1293 float baseline_origin_x, float baseline_origin_y, const DWRITE_STRIKETHROUGH *strikethrough, IUnknown *effect)
1295 FIXME("iface %p, ctx %p, baseline_origin_x %.8e, baseline_origin_y %.8e, strikethrough %p, effect %p stub!\n",
1296 iface, ctx, baseline_origin_x, baseline_origin_y, strikethrough, effect);
1298 return E_NOTIMPL;
1301 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawInlineObject(IDWriteTextRenderer *iface, void *ctx,
1302 float origin_x, float origin_y, IDWriteInlineObject *object, BOOL is_sideways, BOOL is_rtl, IUnknown *effect)
1304 FIXME("iface %p, ctx %p, origin_x %.8e, origin_y %.8e, object %p, is_sideways %#x, is_rtl %#x, effect %p stub!\n",
1305 iface, ctx, origin_x, origin_y, object, is_sideways, is_rtl, effect);
1307 return E_NOTIMPL;
1310 static const struct IDWriteTextRendererVtbl d2d_text_renderer_vtbl =
1312 d2d_text_renderer_QueryInterface,
1313 d2d_text_renderer_AddRef,
1314 d2d_text_renderer_Release,
1315 d2d_text_renderer_IsPixelSnappingDisabled,
1316 d2d_text_renderer_GetCurrentTransform,
1317 d2d_text_renderer_GetPixelsPerDip,
1318 d2d_text_renderer_DrawGlyphRun,
1319 d2d_text_renderer_DrawUnderline,
1320 d2d_text_renderer_DrawStrikethrough,
1321 d2d_text_renderer_DrawInlineObject,
1324 HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target, ID2D1Factory *factory,
1325 IDXGISurface *surface, const D2D1_RENDER_TARGET_PROPERTIES *desc)
1327 D3D10_SUBRESOURCE_DATA buffer_data;
1328 D3D10_STATE_BLOCK_MASK state_mask;
1329 DXGI_SURFACE_DESC surface_desc;
1330 D3D10_RASTERIZER_DESC rs_desc;
1331 D3D10_BUFFER_DESC buffer_desc;
1332 D3D10_BLEND_DESC blend_desc;
1333 ID3D10Resource *resource;
1334 HRESULT hr;
1336 static const D3D10_INPUT_ELEMENT_DESC il_desc[] =
1338 {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
1340 static const DWORD vs_code[] =
1342 /* float3x2 transform;
1344 * float4 main(float4 position : POSITION) : SV_POSITION
1346 * return float4(mul(position.xyw, transform), position.zw);
1347 * } */
1348 0x43425844, 0x0add3194, 0x205f74ec, 0xab527fe7, 0xbe6ad704, 0x00000001, 0x00000128, 0x00000003,
1349 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
1350 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x49534f50, 0x4e4f4954, 0xababab00,
1351 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000001, 0x00000003,
1352 0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, 0x52444853, 0x0000008c, 0x00010040,
1353 0x00000023, 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0300005f, 0x001010f2, 0x00000000,
1354 0x04000067, 0x001020f2, 0x00000000, 0x00000001, 0x08000010, 0x00102012, 0x00000000, 0x00101346,
1355 0x00000000, 0x00208246, 0x00000000, 0x00000000, 0x08000010, 0x00102022, 0x00000000, 0x00101346,
1356 0x00000000, 0x00208246, 0x00000000, 0x00000001, 0x05000036, 0x001020c2, 0x00000000, 0x00101ea6,
1357 0x00000000, 0x0100003e,
1359 static const DWORD rect_solid_ps_code[] =
1361 /* float4 color;
1363 * float4 main(float4 position : SV_POSITION) : SV_Target
1365 * return color;
1366 * } */
1367 0x43425844, 0x88eefcfd, 0x93d6fd47, 0x173c242f, 0x0106d07a, 0x00000001, 0x000000dc, 0x00000003,
1368 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
1369 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49,
1370 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003,
1371 0x00000000, 0x0000000f, 0x545f5653, 0x65677261, 0xabab0074, 0x52444853, 0x00000040, 0x00000040,
1372 0x00000010, 0x04000059, 0x00208e46, 0x00000000, 0x00000001, 0x03000065, 0x001020f2, 0x00000000,
1373 0x06000036, 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x0100003e,
1375 static const DWORD rect_bitmap_ps_code[] =
1377 #if 0
1378 float3x2 transform;
1379 SamplerState s;
1380 Texture2D t;
1382 float4 main(float4 position : SV_POSITION) : SV_Target
1384 return t.Sample(s, mul(float3(position.xy, 1.0), transform));
1386 #endif
1387 0x43425844, 0x20fce5be, 0x138fa37f, 0x9554f03f, 0x3dbe9c02, 0x00000001, 0x00000184, 0x00000003,
1388 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
1389 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000030f, 0x505f5653, 0x5449534f, 0x004e4f49,
1390 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003,
1391 0x00000000, 0x0000000f, 0x545f5653, 0x65677261, 0xabab0074, 0x52444853, 0x000000e8, 0x00000040,
1392 0x0000003a, 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0300005a, 0x00106000, 0x00000000,
1393 0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x04002064, 0x00101032, 0x00000000, 0x00000001,
1394 0x03000065, 0x001020f2, 0x00000000, 0x02000068, 0x00000002, 0x05000036, 0x00100032, 0x00000000,
1395 0x00101046, 0x00000000, 0x05000036, 0x00100042, 0x00000000, 0x00004001, 0x3f800000, 0x08000010,
1396 0x00100012, 0x00000001, 0x00100246, 0x00000000, 0x00208246, 0x00000000, 0x00000000, 0x08000010,
1397 0x00100022, 0x00000001, 0x00100246, 0x00000000, 0x00208246, 0x00000000, 0x00000001, 0x09000045,
1398 0x001020f2, 0x00000000, 0x00100046, 0x00000001, 0x00107e46, 0x00000000, 0x00106000, 0x00000000,
1399 0x0100003e,
1401 static const struct
1403 float x, y;
1405 quad[] =
1407 {-1.0f, 1.0f},
1408 {-1.0f, -1.0f},
1409 { 1.0f, 1.0f},
1410 { 1.0f, -1.0f},
1412 static const D2D1_MATRIX_3X2_F identity =
1414 1.0f, 0.0f,
1415 0.0f, 1.0f,
1416 0.0f, 0.0f,
1419 FIXME("Ignoring render target properties.\n");
1421 render_target->ID2D1RenderTarget_iface.lpVtbl = &d2d_d3d_render_target_vtbl;
1422 render_target->IDWriteTextRenderer_iface.lpVtbl = &d2d_text_renderer_vtbl;
1423 render_target->refcount = 1;
1424 render_target->factory = factory;
1425 ID2D1Factory_AddRef(render_target->factory);
1427 if (FAILED(hr = IDXGISurface_GetDevice(surface, &IID_ID3D10Device, (void **)&render_target->device)))
1429 WARN("Failed to get device interface, hr %#x.\n", hr);
1430 ID2D1Factory_Release(render_target->factory);
1431 return hr;
1434 if (FAILED(hr = IDXGISurface_QueryInterface(surface, &IID_ID3D10Resource, (void **)&resource)))
1436 WARN("Failed to get ID3D10Resource interface, hr %#x.\n", hr);
1437 goto err;
1440 hr = ID3D10Device_CreateRenderTargetView(render_target->device, resource, NULL, &render_target->view);
1441 ID3D10Resource_Release(resource);
1442 if (FAILED(hr))
1444 WARN("Failed to create rendertarget view, hr %#x.\n", hr);
1445 goto err;
1448 if (FAILED(hr = D3D10StateBlockMaskEnableAll(&state_mask)))
1450 WARN("Failed to create stateblock mask, hr %#x.\n", hr);
1451 goto err;
1454 if (FAILED(hr = D3D10CreateStateBlock(render_target->device, &state_mask, &render_target->stateblock)))
1456 WARN("Failed to create stateblock, hr %#x.\n", hr);
1457 goto err;
1460 if (FAILED(hr = ID3D10Device_CreateInputLayout(render_target->device, il_desc,
1461 sizeof(il_desc) / sizeof(*il_desc), vs_code, sizeof(vs_code),
1462 &render_target->il)))
1464 WARN("Failed to create clear input layout, hr %#x.\n", hr);
1465 goto err;
1468 buffer_desc.ByteWidth = sizeof(quad);
1469 buffer_desc.Usage = D3D10_USAGE_DEFAULT;
1470 buffer_desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
1471 buffer_desc.CPUAccessFlags = 0;
1472 buffer_desc.MiscFlags = 0;
1474 buffer_data.pSysMem = quad;
1475 buffer_data.SysMemPitch = 0;
1476 buffer_data.SysMemSlicePitch = 0;
1478 render_target->vb_stride = sizeof(*quad);
1479 if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device,
1480 &buffer_desc, &buffer_data, &render_target->vb)))
1482 WARN("Failed to create clear vertex buffer, hr %#x.\n", hr);
1483 goto err;
1486 if (FAILED(hr = ID3D10Device_CreateVertexShader(render_target->device,
1487 vs_code, sizeof(vs_code), &render_target->vs)))
1489 WARN("Failed to create clear vertex shader, hr %#x.\n", hr);
1490 goto err;
1493 rs_desc.FillMode = D3D10_FILL_SOLID;
1494 rs_desc.CullMode = D3D10_CULL_BACK;
1495 rs_desc.FrontCounterClockwise = FALSE;
1496 rs_desc.DepthBias = 0;
1497 rs_desc.DepthBiasClamp = 0.0f;
1498 rs_desc.SlopeScaledDepthBias = 0.0f;
1499 rs_desc.DepthClipEnable = TRUE;
1500 rs_desc.ScissorEnable = TRUE;
1501 rs_desc.MultisampleEnable = FALSE;
1502 rs_desc.AntialiasedLineEnable = FALSE;
1503 if (FAILED(hr = ID3D10Device_CreateRasterizerState(render_target->device, &rs_desc, &render_target->rs)))
1505 WARN("Failed to create clear rasterizer state, hr %#x.\n", hr);
1506 goto err;
1509 memset(&blend_desc, 0, sizeof(blend_desc));
1510 blend_desc.BlendEnable[0] = TRUE;
1511 blend_desc.SrcBlend = D3D10_BLEND_SRC_ALPHA;
1512 blend_desc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
1513 blend_desc.BlendOp = D3D10_BLEND_OP_ADD;
1514 blend_desc.SrcBlendAlpha = D3D10_BLEND_ZERO;
1515 blend_desc.DestBlendAlpha = D3D10_BLEND_ONE;
1516 blend_desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
1517 blend_desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
1518 if (FAILED(hr = ID3D10Device_CreateBlendState(render_target->device, &blend_desc, &render_target->bs)))
1520 WARN("Failed to create blend state, hr %#x.\n", hr);
1521 goto err;
1524 if (FAILED(hr = ID3D10Device_CreatePixelShader(render_target->device,
1525 rect_solid_ps_code, sizeof(rect_solid_ps_code), &render_target->rect_solid_ps)))
1527 WARN("Failed to create pixel shader, hr %#x.\n", hr);
1528 goto err;
1531 if (FAILED(hr = ID3D10Device_CreatePixelShader(render_target->device,
1532 rect_bitmap_ps_code, sizeof(rect_bitmap_ps_code), &render_target->rect_bitmap_ps)))
1534 WARN("Failed to create pixel shader, hr %#x.\n", hr);
1535 goto err;
1538 if (FAILED(hr = IDXGISurface_GetDesc(surface, &surface_desc)))
1540 WARN("Failed to get surface desc, hr %#x.\n", hr);
1541 goto err;
1544 render_target->pixel_size.width = surface_desc.Width;
1545 render_target->pixel_size.height = surface_desc.Height;
1546 render_target->drawing_state.transform = identity;
1548 if (!d2d_clip_stack_init(&render_target->clip_stack))
1550 WARN("Failed to initialize clip stack.\n");
1551 hr = E_FAIL;
1552 goto err;
1555 render_target->dpi_x = desc->dpiX;
1556 render_target->dpi_y = desc->dpiY;
1558 if (render_target->dpi_x == 0.0f && render_target->dpi_y == 0.0f)
1560 render_target->dpi_x = 96.0f;
1561 render_target->dpi_y = 96.0f;
1564 return S_OK;
1566 err:
1567 if (render_target->rect_bitmap_ps)
1568 ID3D10PixelShader_Release(render_target->rect_bitmap_ps);
1569 if (render_target->rect_solid_ps)
1570 ID3D10PixelShader_Release(render_target->rect_solid_ps);
1571 if (render_target->bs)
1572 ID3D10BlendState_Release(render_target->bs);
1573 if (render_target->rs)
1574 ID3D10RasterizerState_Release(render_target->rs);
1575 if (render_target->vs)
1576 ID3D10VertexShader_Release(render_target->vs);
1577 if (render_target->vb)
1578 ID3D10Buffer_Release(render_target->vb);
1579 if (render_target->il)
1580 ID3D10InputLayout_Release(render_target->il);
1581 if (render_target->stateblock)
1582 render_target->stateblock->lpVtbl->Release(render_target->stateblock);
1583 if (render_target->view)
1584 ID3D10RenderTargetView_Release(render_target->view);
1585 if (render_target->device)
1586 ID3D10Device_Release(render_target->device);
1587 ID2D1Factory_Release(render_target->factory);
1588 return hr;