comparison src/render/direct3d/SDL_d3drender.c @ 5157:fb424691cfc7

Moved the rendering code out to a separate directory in the hope that it can someday be completely decoupled from the rest of the library and be expanded to an awesome 2D on 3D library.
author Sam Lantinga <slouken@libsdl.org>
date Wed, 02 Feb 2011 14:34:54 -0800
parents src/video/windows/SDL_d3drender.c@be02be2ea897
children 307ccc9c135e
comparison
equal deleted inserted replaced
5156:3e4086b3bcd2 5157:fb424691cfc7
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2010 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21 */
22 #include "SDL_config.h"
23
24 #if SDL_VIDEO_RENDER_D3D
25
26 #include "../../core/windows/SDL_windows.h"
27
28 #include "SDL_loadso.h"
29 #include "SDL_syswm.h"
30 #include "../SDL_sysrender.h"
31 #include "../../video/SDL_yuv_sw_c.h"
32
33 #if SDL_VIDEO_RENDER_D3D
34 #define D3D_DEBUG_INFO
35 #include <d3d9.h>
36 #endif
37
38 #ifdef ASSEMBLE_SHADER
39 ///////////////////////////////////////////////////////////////////////////
40 // ID3DXBuffer:
41 // ------------
42 // The buffer object is used by D3DX to return arbitrary size data.
43 //
44 // GetBufferPointer -
45 // Returns a pointer to the beginning of the buffer.
46 //
47 // GetBufferSize -
48 // Returns the size of the buffer, in bytes.
49 ///////////////////////////////////////////////////////////////////////////
50
51 typedef interface ID3DXBuffer ID3DXBuffer;
52 typedef interface ID3DXBuffer *LPD3DXBUFFER;
53
54 // {8BA5FB08-5195-40e2-AC58-0D989C3A0102}
55 DEFINE_GUID(IID_ID3DXBuffer,
56 0x8ba5fb08, 0x5195, 0x40e2, 0xac, 0x58, 0xd, 0x98, 0x9c, 0x3a, 0x1, 0x2);
57
58 #undef INTERFACE
59 #define INTERFACE ID3DXBuffer
60
61 typedef interface ID3DXBuffer {
62 const struct ID3DXBufferVtbl FAR* lpVtbl;
63 } ID3DXBuffer;
64 typedef const struct ID3DXBufferVtbl ID3DXBufferVtbl;
65 const struct ID3DXBufferVtbl
66 {
67 // IUnknown
68 STDMETHOD(QueryInterface)(THIS_ REFIID iid, LPVOID *ppv) PURE;
69 STDMETHOD_(ULONG, AddRef)(THIS) PURE;
70 STDMETHOD_(ULONG, Release)(THIS) PURE;
71
72 // ID3DXBuffer
73 STDMETHOD_(LPVOID, GetBufferPointer)(THIS) PURE;
74 STDMETHOD_(DWORD, GetBufferSize)(THIS) PURE;
75 };
76
77 HRESULT WINAPI
78 D3DXAssembleShader(
79 LPCSTR pSrcData,
80 UINT SrcDataLen,
81 CONST LPVOID* pDefines,
82 LPVOID pInclude,
83 DWORD Flags,
84 LPD3DXBUFFER* ppShader,
85 LPD3DXBUFFER* ppErrorMsgs);
86
87 #endif /* ASSEMBLE_SHADER */
88
89
90 /* Direct3D renderer implementation */
91
92 #if 1 /* This takes more memory but you won't lose your texture data */
93 #define D3DPOOL_SDL D3DPOOL_MANAGED
94 #define SDL_MEMORY_POOL_MANAGED
95 #else
96 #define D3DPOOL_SDL D3DPOOL_DEFAULT
97 #define SDL_MEMORY_POOL_DEFAULT
98 #endif
99
100 static SDL_Renderer *D3D_CreateRenderer(SDL_Window * window, Uint32 flags);
101 static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
102 static int D3D_QueryTexturePixels(SDL_Renderer * renderer,
103 SDL_Texture * texture, void **pixels,
104 int *pitch);
105 static int D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
106 const SDL_Rect * rect, const void *pixels,
107 int pitch);
108 static int D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
109 const SDL_Rect * rect, int markDirty,
110 void **pixels, int *pitch);
111 static void D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
112 static void D3D_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
113 int numrects, const SDL_Rect * rects);
114 static int D3D_RenderDrawPoints(SDL_Renderer * renderer,
115 const SDL_Point * points, int count);
116 static int D3D_RenderDrawLines(SDL_Renderer * renderer,
117 const SDL_Point * points, int count);
118 static int D3D_RenderFillRects(SDL_Renderer * renderer,
119 const SDL_Rect ** rects, int count);
120 static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
121 const SDL_Rect * srcrect, const SDL_Rect * dstrect);
122 static int D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
123 Uint32 format, void * pixels, int pitch);
124 static int D3D_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
125 Uint32 format, const void * pixels, int pitch);
126 static void D3D_RenderPresent(SDL_Renderer * renderer);
127 static void D3D_DestroyTexture(SDL_Renderer * renderer,
128 SDL_Texture * texture);
129 static void D3D_DestroyRenderer(SDL_Renderer * renderer);
130
131
132 SDL_RenderDriver D3D_RenderDriver = {
133 D3D_CreateRenderer,
134 {
135 "d3d",
136 (SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED),
137 0,
138 {0},
139 0,
140 0}
141 };
142
143 typedef struct
144 {
145 void* d3dDLL;
146 IDirect3D9 *d3d;
147 IDirect3DDevice9 *device;
148 UINT adapter;
149 D3DPRESENT_PARAMETERS pparams;
150 SDL_bool beginScene;
151 } D3D_RenderData;
152
153 typedef struct
154 {
155 SDL_SW_YUVTexture *yuv;
156 Uint32 format;
157 IDirect3DTexture9 *texture;
158 } D3D_TextureData;
159
160 typedef struct
161 {
162 float x, y, z;
163 float rhw;
164 DWORD color;
165 float u, v;
166 } Vertex;
167
168 static void
169 D3D_SetError(const char *prefix, HRESULT result)
170 {
171 const char *error;
172
173 switch (result) {
174 case D3DERR_WRONGTEXTUREFORMAT:
175 error = "WRONGTEXTUREFORMAT";
176 break;
177 case D3DERR_UNSUPPORTEDCOLOROPERATION:
178 error = "UNSUPPORTEDCOLOROPERATION";
179 break;
180 case D3DERR_UNSUPPORTEDCOLORARG:
181 error = "UNSUPPORTEDCOLORARG";
182 break;
183 case D3DERR_UNSUPPORTEDALPHAOPERATION:
184 error = "UNSUPPORTEDALPHAOPERATION";
185 break;
186 case D3DERR_UNSUPPORTEDALPHAARG:
187 error = "UNSUPPORTEDALPHAARG";
188 break;
189 case D3DERR_TOOMANYOPERATIONS:
190 error = "TOOMANYOPERATIONS";
191 break;
192 case D3DERR_CONFLICTINGTEXTUREFILTER:
193 error = "CONFLICTINGTEXTUREFILTER";
194 break;
195 case D3DERR_UNSUPPORTEDFACTORVALUE:
196 error = "UNSUPPORTEDFACTORVALUE";
197 break;
198 case D3DERR_CONFLICTINGRENDERSTATE:
199 error = "CONFLICTINGRENDERSTATE";
200 break;
201 case D3DERR_UNSUPPORTEDTEXTUREFILTER:
202 error = "UNSUPPORTEDTEXTUREFILTER";
203 break;
204 case D3DERR_CONFLICTINGTEXTUREPALETTE:
205 error = "CONFLICTINGTEXTUREPALETTE";
206 break;
207 case D3DERR_DRIVERINTERNALERROR:
208 error = "DRIVERINTERNALERROR";
209 break;
210 case D3DERR_NOTFOUND:
211 error = "NOTFOUND";
212 break;
213 case D3DERR_MOREDATA:
214 error = "MOREDATA";
215 break;
216 case D3DERR_DEVICELOST:
217 error = "DEVICELOST";
218 break;
219 case D3DERR_DEVICENOTRESET:
220 error = "DEVICENOTRESET";
221 break;
222 case D3DERR_NOTAVAILABLE:
223 error = "NOTAVAILABLE";
224 break;
225 case D3DERR_OUTOFVIDEOMEMORY:
226 error = "OUTOFVIDEOMEMORY";
227 break;
228 case D3DERR_INVALIDDEVICE:
229 error = "INVALIDDEVICE";
230 break;
231 case D3DERR_INVALIDCALL:
232 error = "INVALIDCALL";
233 break;
234 case D3DERR_DRIVERINVALIDCALL:
235 error = "DRIVERINVALIDCALL";
236 break;
237 case D3DERR_WASSTILLDRAWING:
238 error = "WASSTILLDRAWING";
239 break;
240 default:
241 error = "UNKNOWN";
242 break;
243 }
244 SDL_SetError("%s: %s", prefix, error);
245 }
246
247 static D3DFORMAT
248 PixelFormatToD3DFMT(Uint32 format)
249 {
250 switch (format) {
251 case SDL_PIXELFORMAT_INDEX8:
252 return D3DFMT_P8;
253 case SDL_PIXELFORMAT_RGB332:
254 return D3DFMT_R3G3B2;
255 case SDL_PIXELFORMAT_RGB444:
256 return D3DFMT_X4R4G4B4;
257 case SDL_PIXELFORMAT_RGB555:
258 return D3DFMT_X1R5G5B5;
259 case SDL_PIXELFORMAT_ARGB4444:
260 return D3DFMT_A4R4G4B4;
261 case SDL_PIXELFORMAT_ARGB1555:
262 return D3DFMT_A1R5G5B5;
263 case SDL_PIXELFORMAT_RGB565:
264 return D3DFMT_R5G6B5;
265 case SDL_PIXELFORMAT_RGB888:
266 return D3DFMT_X8R8G8B8;
267 case SDL_PIXELFORMAT_ARGB8888:
268 return D3DFMT_A8R8G8B8;
269 case SDL_PIXELFORMAT_ARGB2101010:
270 return D3DFMT_A2R10G10B10;
271 case SDL_PIXELFORMAT_YV12:
272 return MAKEFOURCC('Y','V','1','2');
273 case SDL_PIXELFORMAT_IYUV:
274 return MAKEFOURCC('I','4','2','0');
275 case SDL_PIXELFORMAT_UYVY:
276 return D3DFMT_UYVY;
277 case SDL_PIXELFORMAT_YUY2:
278 return D3DFMT_YUY2;
279 default:
280 return D3DFMT_UNKNOWN;
281 }
282 }
283
284 static SDL_bool
285 D3D_IsTextureFormatAvailable(IDirect3D9 * d3d, UINT adapter,
286 D3DFORMAT display_format,
287 D3DFORMAT texture_format)
288 {
289 HRESULT result;
290
291 result = IDirect3D9_CheckDeviceFormat(d3d, adapter,
292 D3DDEVTYPE_HAL,
293 display_format,
294 0,
295 D3DRTYPE_TEXTURE,
296 texture_format);
297 return FAILED(result) ? SDL_FALSE : SDL_TRUE;
298 }
299
300 static void
301 UpdateYUVTextureData(SDL_Texture * texture)
302 {
303 D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
304 SDL_Rect rect;
305 RECT d3drect;
306 D3DLOCKED_RECT locked;
307 HRESULT result;
308
309 d3drect.left = 0;
310 d3drect.right = texture->w;
311 d3drect.top = 0;
312 d3drect.bottom = texture->h;
313
314 result =
315 IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect, 0);
316 if (FAILED(result)) {
317 return;
318 }
319
320 rect.x = 0;
321 rect.y = 0;
322 rect.w = texture->w;
323 rect.h = texture->h;
324 SDL_SW_CopyYUVToRGB(data->yuv, &rect, data->format, texture->w,
325 texture->h, locked.pBits, locked.Pitch);
326
327 IDirect3DTexture9_UnlockRect(data->texture, 0);
328 }
329
330 static void
331 D3D_AddTextureFormats(D3D_RenderData *data, SDL_RendererInfo *info)
332 {
333 int i;
334 int formats[] = {
335 SDL_PIXELFORMAT_RGB332,
336 SDL_PIXELFORMAT_RGB444,
337 SDL_PIXELFORMAT_RGB555,
338 SDL_PIXELFORMAT_ARGB4444,
339 SDL_PIXELFORMAT_ARGB1555,
340 SDL_PIXELFORMAT_RGB565,
341 SDL_PIXELFORMAT_RGB888,
342 SDL_PIXELFORMAT_ARGB8888,
343 SDL_PIXELFORMAT_ARGB2101010,
344 };
345
346 info->num_texture_formats = 0;
347 for (i = 0; i < SDL_arraysize(formats); ++i) {
348 if (D3D_IsTextureFormatAvailable
349 (data->d3d, data->adapter, data->pparams.BackBufferFormat, PixelFormatToD3DFMT(formats[i]))) {
350 info->texture_formats[info->num_texture_formats++] = formats[i];
351 }
352 }
353 info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_YV12;
354 info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
355 info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_YUY2;
356 info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_UYVY;
357 info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_YVYU;
358 }
359
360 SDL_Renderer *
361 D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
362 {
363 SDL_Renderer *renderer;
364 D3D_RenderData *data;
365 SDL_SysWMinfo windowinfo;
366 HRESULT result;
367 D3DPRESENT_PARAMETERS pparams;
368 IDirect3DSwapChain9 *chain;
369 D3DCAPS9 caps;
370
371 renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
372 if (!renderer) {
373 SDL_OutOfMemory();
374 return NULL;
375 }
376
377 data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data));
378 if (!data) {
379 SDL_free(renderer);
380 SDL_OutOfMemory();
381 return NULL;
382 }
383
384 data->d3dDLL = SDL_LoadObject("D3D9.DLL");
385 if (data->d3dDLL) {
386 IDirect3D9 *(WINAPI * D3DCreate) (UINT SDKVersion);
387
388 D3DCreate =
389 (IDirect3D9 * (WINAPI *) (UINT)) SDL_LoadFunction(data->d3dDLL,
390 "Direct3DCreate9");
391 if (D3DCreate) {
392 data->d3d = D3DCreate(D3D_SDK_VERSION);
393 }
394 if (!data->d3d) {
395 SDL_UnloadObject(data->d3dDLL);
396 data->d3dDLL = NULL;
397 }
398 }
399 if (!data->d3d) {
400 SDL_free(renderer);
401 SDL_free(data);
402 SDL_SetError("Unable to create Direct3D interface");
403 return NULL;
404 }
405
406 renderer->CreateTexture = D3D_CreateTexture;
407 renderer->QueryTexturePixels = D3D_QueryTexturePixels;
408 renderer->UpdateTexture = D3D_UpdateTexture;
409 renderer->LockTexture = D3D_LockTexture;
410 renderer->UnlockTexture = D3D_UnlockTexture;
411 renderer->DirtyTexture = D3D_DirtyTexture;
412 renderer->RenderDrawPoints = D3D_RenderDrawPoints;
413 renderer->RenderDrawLines = D3D_RenderDrawLines;
414 renderer->RenderFillRects = D3D_RenderFillRects;
415 renderer->RenderCopy = D3D_RenderCopy;
416 renderer->RenderReadPixels = D3D_RenderReadPixels;
417 renderer->RenderWritePixels = D3D_RenderWritePixels;
418 renderer->RenderPresent = D3D_RenderPresent;
419 renderer->DestroyTexture = D3D_DestroyTexture;
420 renderer->DestroyRenderer = D3D_DestroyRenderer;
421 renderer->info = D3D_RenderDriver.info;
422 renderer->window = window;
423 renderer->driverdata = data;
424
425 renderer->info.flags = SDL_RENDERER_ACCELERATED;
426
427 SDL_VERSION(&windowinfo.version);
428 SDL_GetWindowWMInfo(window, &windowinfo);
429
430 SDL_zero(pparams);
431 pparams.hDeviceWindow = windowinfo.info.win.window;
432 pparams.BackBufferWidth = window->w;
433 pparams.BackBufferHeight = window->h;
434 if (window->flags & SDL_WINDOW_FULLSCREEN) {
435 pparams.BackBufferFormat =
436 PixelFormatToD3DFMT(window->fullscreen_mode.format);
437 } else {
438 pparams.BackBufferFormat = D3DFMT_UNKNOWN;
439 }
440 pparams.BackBufferCount = 1;
441 pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
442
443 if (window->flags & SDL_WINDOW_FULLSCREEN) {
444 pparams.Windowed = FALSE;
445 pparams.FullScreen_RefreshRateInHz =
446 window->fullscreen_mode.refresh_rate;
447 } else {
448 pparams.Windowed = TRUE;
449 pparams.FullScreen_RefreshRateInHz = 0;
450 }
451 if (flags & SDL_RENDERER_PRESENTVSYNC) {
452 pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
453 } else {
454 pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
455 }
456
457 /* FIXME: Which adapter? */
458 data->adapter = D3DADAPTER_DEFAULT;
459 IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);
460
461 result = IDirect3D9_CreateDevice(data->d3d, data->adapter,
462 D3DDEVTYPE_HAL,
463 pparams.hDeviceWindow,
464 (caps.
465 DevCaps &
466 D3DDEVCAPS_HWTRANSFORMANDLIGHT) ?
467 D3DCREATE_HARDWARE_VERTEXPROCESSING :
468 D3DCREATE_SOFTWARE_VERTEXPROCESSING,
469 &pparams, &data->device);
470 if (FAILED(result)) {
471 D3D_DestroyRenderer(renderer);
472 D3D_SetError("CreateDevice()", result);
473 return NULL;
474 }
475 data->beginScene = SDL_TRUE;
476
477 /* Get presentation parameters to fill info */
478 result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
479 if (FAILED(result)) {
480 D3D_DestroyRenderer(renderer);
481 D3D_SetError("GetSwapChain()", result);
482 return NULL;
483 }
484 result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
485 if (FAILED(result)) {
486 IDirect3DSwapChain9_Release(chain);
487 D3D_DestroyRenderer(renderer);
488 D3D_SetError("GetPresentParameters()", result);
489 return NULL;
490 }
491 IDirect3DSwapChain9_Release(chain);
492 if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
493 renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
494 }
495 data->pparams = pparams;
496
497 D3D_AddTextureFormats(data, &renderer->info);
498
499 IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
500 renderer->info.max_texture_width = caps.MaxTextureWidth;
501 renderer->info.max_texture_height = caps.MaxTextureHeight;
502
503 /* Set up parameters for rendering */
504 IDirect3DDevice9_SetVertexShader(data->device, NULL);
505 IDirect3DDevice9_SetFVF(data->device,
506 D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1);
507 IDirect3DDevice9_SetRenderState(data->device, D3DRS_ZENABLE, D3DZB_FALSE);
508 IDirect3DDevice9_SetRenderState(data->device, D3DRS_CULLMODE,
509 D3DCULL_NONE);
510 IDirect3DDevice9_SetRenderState(data->device, D3DRS_LIGHTING, FALSE);
511 /* Enable color modulation by diffuse color */
512 IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLOROP,
513 D3DTOP_MODULATE);
514 IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLORARG1,
515 D3DTA_TEXTURE);
516 IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLORARG2,
517 D3DTA_DIFFUSE);
518 /* Enable alpha modulation by diffuse alpha */
519 IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAOP,
520 D3DTOP_MODULATE);
521 IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAARG1,
522 D3DTA_TEXTURE);
523 IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAARG2,
524 D3DTA_DIFFUSE);
525 /* Disable second texture stage, since we're done */
526 IDirect3DDevice9_SetTextureStageState(data->device, 1, D3DTSS_COLOROP,
527 D3DTOP_DISABLE);
528 IDirect3DDevice9_SetTextureStageState(data->device, 1, D3DTSS_ALPHAOP,
529 D3DTOP_DISABLE);
530
531 return renderer;
532 }
533
534 static int
535 D3D_Reset(SDL_Renderer * renderer)
536 {
537 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
538 HRESULT result;
539
540 result = IDirect3DDevice9_Reset(data->device, &data->pparams);
541 if (FAILED(result)) {
542 if (result == D3DERR_DEVICELOST) {
543 /* Don't worry about it, we'll reset later... */
544 return 0;
545 } else {
546 D3D_SetError("Reset()", result);
547 return -1;
548 }
549 }
550 IDirect3DDevice9_SetVertexShader(data->device, NULL);
551 IDirect3DDevice9_SetFVF(data->device,
552 D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1);
553 IDirect3DDevice9_SetRenderState(data->device, D3DRS_CULLMODE,
554 D3DCULL_NONE);
555 IDirect3DDevice9_SetRenderState(data->device, D3DRS_LIGHTING, FALSE);
556 return 0;
557 }
558
559 /* FIXME: This needs to be called... when? */
560 #if 0
561 static int
562 D3D_DisplayModeChanged(SDL_Renderer * renderer)
563 {
564 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
565 SDL_Window *window = renderer->window;
566 SDL_VideoDisplay *display = window->display;
567
568 data->pparams.BackBufferWidth = window->w;
569 data->pparams.BackBufferHeight = window->h;
570 if (window->flags & SDL_WINDOW_FULLSCREEN) {
571 data->pparams.BackBufferFormat =
572 PixelFormatToD3DFMT(window->fullscreen_mode.format);
573 } else {
574 data->pparams.BackBufferFormat = D3DFMT_UNKNOWN;
575 }
576 return D3D_Reset(renderer);
577 }
578 #endif
579
580 static int
581 D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
582 {
583 D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
584 SDL_Window *window = renderer->window;
585 D3DFORMAT display_format = renderdata->pparams.BackBufferFormat;
586 D3D_TextureData *data;
587 HRESULT result;
588
589 data = (D3D_TextureData *) SDL_calloc(1, sizeof(*data));
590 if (!data) {
591 SDL_OutOfMemory();
592 return -1;
593 }
594
595 texture->driverdata = data;
596
597 if (SDL_ISPIXELFORMAT_FOURCC(texture->format) &&
598 (texture->format != SDL_PIXELFORMAT_YUY2 ||
599 !D3D_IsTextureFormatAvailable(renderdata->d3d, renderdata->adapter,
600 display_format, PixelFormatToD3DFMT(texture->format)))
601 && (texture->format != SDL_PIXELFORMAT_YVYU
602 || !D3D_IsTextureFormatAvailable(renderdata->d3d, renderdata->adapter,
603 display_format, PixelFormatToD3DFMT(texture->format)))) {
604 data->yuv =
605 SDL_SW_CreateYUVTexture(texture->format, texture->w, texture->h);
606 if (!data->yuv) {
607 return -1;
608 }
609 data->format = SDL_GetWindowPixelFormat(window);
610 } else {
611 data->format = texture->format;
612 }
613
614 result =
615 IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,
616 texture->h, 1, 0,
617 PixelFormatToD3DFMT(data->format),
618 D3DPOOL_SDL, &data->texture, NULL);
619 if (FAILED(result)) {
620 D3D_SetError("CreateTexture()", result);
621 return -1;
622 }
623
624 return 0;
625 }
626
627 static int
628 D3D_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
629 void **pixels, int *pitch)
630 {
631 D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
632
633 if (data->yuv) {
634 return SDL_SW_QueryYUVTexturePixels(data->yuv, pixels, pitch);
635 } else {
636 /* D3D textures don't have their pixels hanging out */
637 return -1;
638 }
639 }
640
641 static int
642 D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
643 const SDL_Rect * rect, const void *pixels, int pitch)
644 {
645 D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
646 D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
647
648 if (data->yuv) {
649 if (SDL_SW_UpdateYUVTexture(data->yuv, rect, pixels, pitch) < 0) {
650 return -1;
651 }
652 UpdateYUVTextureData(texture);
653 return 0;
654 } else {
655 #ifdef SDL_MEMORY_POOL_DEFAULT
656 IDirect3DTexture9 *temp;
657 RECT d3drect;
658 D3DLOCKED_RECT locked;
659 const Uint8 *src;
660 Uint8 *dst;
661 int row, length;
662 HRESULT result;
663
664 result =
665 IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,
666 texture->h, 1, 0,
667 PixelFormatToD3DFMT(texture->
668 format),
669 D3DPOOL_SYSTEMMEM, &temp, NULL);
670 if (FAILED(result)) {
671 D3D_SetError("CreateTexture()", result);
672 return -1;
673 }
674
675 d3drect.left = rect->x;
676 d3drect.right = rect->x + rect->w;
677 d3drect.top = rect->y;
678 d3drect.bottom = rect->y + rect->h;
679
680 result = IDirect3DTexture9_LockRect(temp, 0, &locked, &d3drect, 0);
681 if (FAILED(result)) {
682 IDirect3DTexture9_Release(temp);
683 D3D_SetError("LockRect()", result);
684 return -1;
685 }
686
687 src = pixels;
688 dst = locked.pBits;
689 length = rect->w * SDL_BYTESPERPIXEL(texture->format);
690 for (row = 0; row < rect->h; ++row) {
691 SDL_memcpy(dst, src, length);
692 src += pitch;
693 dst += locked.Pitch;
694 }
695 IDirect3DTexture9_UnlockRect(temp, 0);
696
697 result =
698 IDirect3DDevice9_UpdateTexture(renderdata->device,
699 (IDirect3DBaseTexture9 *) temp,
700 (IDirect3DBaseTexture9 *)
701 data->texture);
702 IDirect3DTexture9_Release(temp);
703 if (FAILED(result)) {
704 D3D_SetError("UpdateTexture()", result);
705 return -1;
706 }
707 #else
708 RECT d3drect;
709 D3DLOCKED_RECT locked;
710 const Uint8 *src;
711 Uint8 *dst;
712 int row, length;
713 HRESULT result;
714
715 d3drect.left = rect->x;
716 d3drect.right = rect->x + rect->w;
717 d3drect.top = rect->y;
718 d3drect.bottom = rect->y + rect->h;
719
720 result =
721 IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect,
722 0);
723 if (FAILED(result)) {
724 D3D_SetError("LockRect()", result);
725 return -1;
726 }
727
728 src = pixels;
729 dst = locked.pBits;
730 length = rect->w * SDL_BYTESPERPIXEL(texture->format);
731 for (row = 0; row < rect->h; ++row) {
732 SDL_memcpy(dst, src, length);
733 src += pitch;
734 dst += locked.Pitch;
735 }
736 IDirect3DTexture9_UnlockRect(data->texture, 0);
737 #endif // SDL_MEMORY_POOL_DEFAULT
738
739 return 0;
740 }
741 }
742
743 static int
744 D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
745 const SDL_Rect * rect, int markDirty, void **pixels,
746 int *pitch)
747 {
748 D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
749
750 if (data->yuv) {
751 return SDL_SW_LockYUVTexture(data->yuv, rect, markDirty, pixels,
752 pitch);
753 } else {
754 RECT d3drect;
755 D3DLOCKED_RECT locked;
756 HRESULT result;
757
758 d3drect.left = rect->x;
759 d3drect.right = rect->x + rect->w;
760 d3drect.top = rect->y;
761 d3drect.bottom = rect->y + rect->h;
762
763 result =
764 IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect,
765 markDirty ? 0 :
766 D3DLOCK_NO_DIRTY_UPDATE);
767 if (FAILED(result)) {
768 D3D_SetError("LockRect()", result);
769 return -1;
770 }
771 *pixels = locked.pBits;
772 *pitch = locked.Pitch;
773 return 0;
774 }
775 }
776
777 static void
778 D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
779 {
780 D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
781
782 if (data->yuv) {
783 SDL_SW_UnlockYUVTexture(data->yuv);
784 UpdateYUVTextureData(texture);
785 } else {
786 IDirect3DTexture9_UnlockRect(data->texture, 0);
787 }
788 }
789
790 static void
791 D3D_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects,
792 const SDL_Rect * rects)
793 {
794 D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
795 RECT d3drect;
796 int i;
797
798 for (i = 0; i < numrects; ++i) {
799 const SDL_Rect *rect = &rects[i];
800
801 d3drect.left = rect->x;
802 d3drect.right = rect->x + rect->w;
803 d3drect.top = rect->y;
804 d3drect.bottom = rect->y + rect->h;
805
806 IDirect3DTexture9_AddDirtyRect(data->texture, &d3drect);
807 }
808 }
809
810 static void
811 D3D_SetBlendMode(D3D_RenderData * data, int blendMode)
812 {
813 switch (blendMode) {
814 case SDL_BLENDMODE_NONE:
815 IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
816 FALSE);
817 break;
818 case SDL_BLENDMODE_BLEND:
819 IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
820 TRUE);
821 IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
822 D3DBLEND_SRCALPHA);
823 IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
824 D3DBLEND_INVSRCALPHA);
825 break;
826 case SDL_BLENDMODE_ADD:
827 IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
828 TRUE);
829 IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
830 D3DBLEND_SRCALPHA);
831 IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
832 D3DBLEND_ONE);
833 break;
834 }
835 }
836
837 static int
838 D3D_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
839 int count)
840 {
841 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
842 DWORD color;
843 Vertex *vertices;
844 int i;
845 HRESULT result;
846
847 if (data->beginScene) {
848 IDirect3DDevice9_BeginScene(data->device);
849 data->beginScene = SDL_FALSE;
850 }
851
852 D3D_SetBlendMode(data, renderer->blendMode);
853
854 result =
855 IDirect3DDevice9_SetTexture(data->device, 0,
856 (IDirect3DBaseTexture9 *) 0);
857 if (FAILED(result)) {
858 D3D_SetError("SetTexture()", result);
859 return -1;
860 }
861
862 color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
863
864 vertices = SDL_stack_alloc(Vertex, count);
865 for (i = 0; i < count; ++i) {
866 vertices[i].x = (float) points[i].x;
867 vertices[i].y = (float) points[i].y;
868 vertices[i].z = 0.0f;
869 vertices[i].rhw = 1.0f;
870 vertices[i].color = color;
871 vertices[i].u = 0.0f;
872 vertices[i].v = 0.0f;
873 }
874 result =
875 IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count,
876 vertices, sizeof(*vertices));
877 SDL_stack_free(vertices);
878 if (FAILED(result)) {
879 D3D_SetError("DrawPrimitiveUP()", result);
880 return -1;
881 }
882 return 0;
883 }
884
885 static int
886 D3D_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
887 int count)
888 {
889 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
890 DWORD color;
891 Vertex *vertices;
892 int i;
893 HRESULT result;
894
895 if (data->beginScene) {
896 IDirect3DDevice9_BeginScene(data->device);
897 data->beginScene = SDL_FALSE;
898 }
899
900 D3D_SetBlendMode(data, renderer->blendMode);
901
902 result =
903 IDirect3DDevice9_SetTexture(data->device, 0,
904 (IDirect3DBaseTexture9 *) 0);
905 if (FAILED(result)) {
906 D3D_SetError("SetTexture()", result);
907 return -1;
908 }
909
910 color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
911
912 vertices = SDL_stack_alloc(Vertex, count);
913 for (i = 0; i < count; ++i) {
914 vertices[i].x = (float) points[i].x;
915 vertices[i].y = (float) points[i].y;
916 vertices[i].z = 0.0f;
917 vertices[i].rhw = 1.0f;
918 vertices[i].color = color;
919 vertices[i].u = 0.0f;
920 vertices[i].v = 0.0f;
921 }
922 result =
923 IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count-1,
924 vertices, sizeof(*vertices));
925
926 /* DirectX 9 has the same line rasterization semantics as GDI,
927 so we need to close the endpoint of the line */
928 if (points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
929 vertices[0].x = (float) points[count-1].x;
930 vertices[0].y = (float) points[count-1].y;
931 result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, vertices, sizeof(*vertices));
932 }
933
934 SDL_stack_free(vertices);
935 if (FAILED(result)) {
936 D3D_SetError("DrawPrimitiveUP()", result);
937 return -1;
938 }
939 return 0;
940 }
941
942 static int
943 D3D_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects,
944 int count)
945 {
946 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
947 DWORD color;
948 int i;
949 float minx, miny, maxx, maxy;
950 Vertex vertices[4];
951 HRESULT result;
952
953 if (data->beginScene) {
954 IDirect3DDevice9_BeginScene(data->device);
955 data->beginScene = SDL_FALSE;
956 }
957
958 D3D_SetBlendMode(data, renderer->blendMode);
959
960 result =
961 IDirect3DDevice9_SetTexture(data->device, 0,
962 (IDirect3DBaseTexture9 *) 0);
963 if (FAILED(result)) {
964 D3D_SetError("SetTexture()", result);
965 return -1;
966 }
967
968 color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
969
970 for (i = 0; i < count; ++i) {
971 const SDL_Rect *rect = rects[i];
972
973 minx = (float) rect->x;
974 miny = (float) rect->y;
975 maxx = (float) rect->x + rect->w;
976 maxy = (float) rect->y + rect->h;
977
978 vertices[0].x = minx;
979 vertices[0].y = miny;
980 vertices[0].z = 0.0f;
981 vertices[0].rhw = 1.0f;
982 vertices[0].color = color;
983 vertices[0].u = 0.0f;
984 vertices[0].v = 0.0f;
985
986 vertices[1].x = maxx;
987 vertices[1].y = miny;
988 vertices[1].z = 0.0f;
989 vertices[1].rhw = 1.0f;
990 vertices[1].color = color;
991 vertices[1].u = 0.0f;
992 vertices[1].v = 0.0f;
993
994 vertices[2].x = maxx;
995 vertices[2].y = maxy;
996 vertices[2].z = 0.0f;
997 vertices[2].rhw = 1.0f;
998 vertices[2].color = color;
999 vertices[2].u = 0.0f;
1000 vertices[2].v = 0.0f;
1001
1002 vertices[3].x = minx;
1003 vertices[3].y = maxy;
1004 vertices[3].z = 0.0f;
1005 vertices[3].rhw = 1.0f;
1006 vertices[3].color = color;
1007 vertices[3].u = 0.0f;
1008 vertices[3].v = 0.0f;
1009
1010 result =
1011 IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN,
1012 2, vertices, sizeof(*vertices));
1013 if (FAILED(result)) {
1014 D3D_SetError("DrawPrimitiveUP()", result);
1015 return -1;
1016 }
1017 }
1018 return 0;
1019 }
1020
1021 static int
1022 D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
1023 const SDL_Rect * srcrect, const SDL_Rect * dstrect)
1024 {
1025 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1026 D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
1027 LPDIRECT3DPIXELSHADER9 shader = NULL;
1028 float minx, miny, maxx, maxy;
1029 float minu, maxu, minv, maxv;
1030 DWORD color;
1031 Vertex vertices[4];
1032 HRESULT result;
1033
1034 if (data->beginScene) {
1035 IDirect3DDevice9_BeginScene(data->device);
1036 data->beginScene = SDL_FALSE;
1037 }
1038
1039 minx = (float) dstrect->x - 0.5f;
1040 miny = (float) dstrect->y - 0.5f;
1041 maxx = (float) dstrect->x + dstrect->w - 0.5f;
1042 maxy = (float) dstrect->y + dstrect->h - 0.5f;
1043
1044 minu = (float) srcrect->x / texture->w;
1045 maxu = (float) (srcrect->x + srcrect->w) / texture->w;
1046 minv = (float) srcrect->y / texture->h;
1047 maxv = (float) (srcrect->y + srcrect->h) / texture->h;
1048
1049 color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
1050
1051 vertices[0].x = minx;
1052 vertices[0].y = miny;
1053 vertices[0].z = 0.0f;
1054 vertices[0].rhw = 1.0f;
1055 vertices[0].color = color;
1056 vertices[0].u = minu;
1057 vertices[0].v = minv;
1058
1059 vertices[1].x = maxx;
1060 vertices[1].y = miny;
1061 vertices[1].z = 0.0f;
1062 vertices[1].rhw = 1.0f;
1063 vertices[1].color = color;
1064 vertices[1].u = maxu;
1065 vertices[1].v = minv;
1066
1067 vertices[2].x = maxx;
1068 vertices[2].y = maxy;
1069 vertices[2].z = 0.0f;
1070 vertices[2].rhw = 1.0f;
1071 vertices[2].color = color;
1072 vertices[2].u = maxu;
1073 vertices[2].v = maxv;
1074
1075 vertices[3].x = minx;
1076 vertices[3].y = maxy;
1077 vertices[3].z = 0.0f;
1078 vertices[3].rhw = 1.0f;
1079 vertices[3].color = color;
1080 vertices[3].u = minu;
1081 vertices[3].v = maxv;
1082
1083 D3D_SetBlendMode(data, texture->blendMode);
1084
1085 IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MINFILTER,
1086 D3DTEXF_LINEAR);
1087 IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MAGFILTER,
1088 D3DTEXF_LINEAR);
1089
1090 result =
1091 IDirect3DDevice9_SetTexture(data->device, 0, (IDirect3DBaseTexture9 *)
1092 texturedata->texture);
1093 if (FAILED(result)) {
1094 D3D_SetError("SetTexture()", result);
1095 return -1;
1096 }
1097 if (shader) {
1098 result = IDirect3DDevice9_SetPixelShader(data->device, shader);
1099 if (FAILED(result)) {
1100 D3D_SetError("SetShader()", result);
1101 return -1;
1102 }
1103 }
1104 result =
1105 IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
1106 vertices, sizeof(*vertices));
1107 if (FAILED(result)) {
1108 D3D_SetError("DrawPrimitiveUP()", result);
1109 return -1;
1110 }
1111 if (shader) {
1112 result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
1113 if (FAILED(result)) {
1114 D3D_SetError("SetShader()", result);
1115 return -1;
1116 }
1117 }
1118 return 0;
1119 }
1120
1121 static int
1122 D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
1123 Uint32 format, void * pixels, int pitch)
1124 {
1125 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1126 SDL_Window *window = renderer->window;
1127 SDL_VideoDisplay *display = window->display;
1128 D3DSURFACE_DESC desc;
1129 LPDIRECT3DSURFACE9 backBuffer;
1130 LPDIRECT3DSURFACE9 surface;
1131 RECT d3drect;
1132 D3DLOCKED_RECT locked;
1133 HRESULT result;
1134
1135 result = IDirect3DDevice9_GetBackBuffer(data->device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuffer);
1136 if (FAILED(result)) {
1137 D3D_SetError("GetBackBuffer()", result);
1138 return -1;
1139 }
1140
1141 result = IDirect3DSurface9_GetDesc(backBuffer, &desc);
1142 if (FAILED(result)) {
1143 D3D_SetError("GetDesc()", result);
1144 IDirect3DSurface9_Release(backBuffer);
1145 return -1;
1146 }
1147
1148 result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
1149 if (FAILED(result)) {
1150 D3D_SetError("CreateOffscreenPlainSurface()", result);
1151 IDirect3DSurface9_Release(backBuffer);
1152 return -1;
1153 }
1154
1155 result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface);
1156 if (FAILED(result)) {
1157 D3D_SetError("GetRenderTargetData()", result);
1158 IDirect3DSurface9_Release(surface);
1159 IDirect3DSurface9_Release(backBuffer);
1160 return -1;
1161 }
1162
1163 d3drect.left = rect->x;
1164 d3drect.right = rect->x + rect->w;
1165 d3drect.top = rect->y;
1166 d3drect.bottom = rect->y + rect->h;
1167
1168 result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY);
1169 if (FAILED(result)) {
1170 D3D_SetError("LockRect()", result);
1171 IDirect3DSurface9_Release(surface);
1172 IDirect3DSurface9_Release(backBuffer);
1173 return -1;
1174 }
1175
1176 SDL_ConvertPixels(rect->w, rect->h,
1177 display->current_mode.format, locked.pBits, locked.Pitch,
1178 format, pixels, pitch);
1179
1180 IDirect3DSurface9_UnlockRect(surface);
1181
1182 IDirect3DSurface9_Release(surface);
1183 IDirect3DSurface9_Release(backBuffer);
1184
1185 return 0;
1186 }
1187
1188 static int
1189 D3D_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
1190 Uint32 format, const void * pixels, int pitch)
1191 {
1192 /* Work in progress */
1193 SDL_Unsupported();
1194 return -1;
1195 }
1196
1197 static void
1198 D3D_RenderPresent(SDL_Renderer * renderer)
1199 {
1200 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1201 HRESULT result;
1202
1203 if (!data->beginScene) {
1204 IDirect3DDevice9_EndScene(data->device);
1205 data->beginScene = SDL_TRUE;
1206 }
1207
1208 result = IDirect3DDevice9_TestCooperativeLevel(data->device);
1209 if (result == D3DERR_DEVICELOST) {
1210 /* We'll reset later */
1211 return;
1212 }
1213 if (result == D3DERR_DEVICENOTRESET) {
1214 D3D_Reset(renderer);
1215 }
1216 result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
1217 if (FAILED(result)) {
1218 D3D_SetError("Present()", result);
1219 }
1220 }
1221
1222 static void
1223 D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
1224 {
1225 D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
1226
1227 if (!data) {
1228 return;
1229 }
1230 if (data->yuv) {
1231 SDL_SW_DestroyYUVTexture(data->yuv);
1232 }
1233 if (data->texture) {
1234 IDirect3DTexture9_Release(data->texture);
1235 }
1236 SDL_free(data);
1237 texture->driverdata = NULL;
1238 }
1239
1240 static void
1241 D3D_DestroyRenderer(SDL_Renderer * renderer)
1242 {
1243 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1244
1245 if (data) {
1246 if (data->device) {
1247 IDirect3DDevice9_Release(data->device);
1248 }
1249 if (data->d3d) {
1250 IDirect3D9_Release(data->d3d);
1251 SDL_UnloadObject(data->d3dDLL);
1252 }
1253 SDL_free(data);
1254 }
1255 SDL_free(renderer);
1256 }
1257
1258 #endif /* SDL_VIDEO_RENDER_D3D */
1259
1260 /* vi: set ts=4 sw=4 expandtab: */