SDL_render_d3d.c (64903B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "../../SDL_internal.h" 22 23#include "SDL_render.h" 24#include "SDL_system.h" 25 26#if SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED 27 28#include "../../core/windows/SDL_windows.h" 29 30#include "SDL_hints.h" 31#include "SDL_loadso.h" 32#include "SDL_syswm.h" 33#include "../SDL_sysrender.h" 34#include "../SDL_d3dmath.h" 35#include "../../video/windows/SDL_windowsvideo.h" 36 37#if SDL_VIDEO_RENDER_D3D 38#define D3D_DEBUG_INFO 39#include <d3d9.h> 40#endif 41 42 43#ifdef ASSEMBLE_SHADER 44#pragma comment(lib, "d3dx9.lib") 45 46/************************************************************************** 47 * ID3DXBuffer: 48 * ------------ 49 * The buffer object is used by D3DX to return arbitrary size data. 50 * 51 * GetBufferPointer - 52 * Returns a pointer to the beginning of the buffer. 53 * 54 * GetBufferSize - 55 * Returns the size of the buffer, in bytes. 56 **************************************************************************/ 57 58typedef interface ID3DXBuffer ID3DXBuffer; 59typedef interface ID3DXBuffer *LPD3DXBUFFER; 60 61/* {8BA5FB08-5195-40e2-AC58-0D989C3A0102} */ 62DEFINE_GUID(IID_ID3DXBuffer, 630x8ba5fb08, 0x5195, 0x40e2, 0xac, 0x58, 0xd, 0x98, 0x9c, 0x3a, 0x1, 0x2); 64 65#undef INTERFACE 66#define INTERFACE ID3DXBuffer 67 68typedef interface ID3DXBuffer { 69 const struct ID3DXBufferVtbl FAR* lpVtbl; 70} ID3DXBuffer; 71typedef const struct ID3DXBufferVtbl ID3DXBufferVtbl; 72const struct ID3DXBufferVtbl 73{ 74 /* IUnknown */ 75 STDMETHOD(QueryInterface)(THIS_ REFIID iid, LPVOID *ppv) PURE; 76 STDMETHOD_(ULONG, AddRef)(THIS) PURE; 77 STDMETHOD_(ULONG, Release)(THIS) PURE; 78 79 /* ID3DXBuffer */ 80 STDMETHOD_(LPVOID, GetBufferPointer)(THIS) PURE; 81 STDMETHOD_(DWORD, GetBufferSize)(THIS) PURE; 82}; 83 84HRESULT WINAPI 85 D3DXAssembleShader( 86 LPCSTR pSrcData, 87 UINT SrcDataLen, 88 CONST LPVOID* pDefines, 89 LPVOID pInclude, 90 DWORD Flags, 91 LPD3DXBUFFER* ppShader, 92 LPD3DXBUFFER* ppErrorMsgs); 93 94static void PrintShaderData(LPDWORD shader_data, DWORD shader_size) 95{ 96 OutputDebugStringA("const DWORD shader_data[] = {\n\t"); 97 { 98 SDL_bool newline = SDL_FALSE; 99 unsigned i; 100 for (i = 0; i < shader_size / sizeof(DWORD); ++i) { 101 char dword[11]; 102 if (i > 0) { 103 if ((i%6) == 0) { 104 newline = SDL_TRUE; 105 } 106 if (newline) { 107 OutputDebugStringA(",\n "); 108 newline = SDL_FALSE; 109 } else { 110 OutputDebugStringA(", "); 111 } 112 } 113 SDL_snprintf(dword, sizeof(dword), "0x%8.8x", shader_data[i]); 114 OutputDebugStringA(dword); 115 } 116 OutputDebugStringA("\n};\n"); 117 } 118} 119 120#endif /* ASSEMBLE_SHADER */ 121 122 123/* Direct3D renderer implementation */ 124 125static SDL_Renderer *D3D_CreateRenderer(SDL_Window * window, Uint32 flags); 126static void D3D_WindowEvent(SDL_Renderer * renderer, 127 const SDL_WindowEvent *event); 128static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); 129static int D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); 130static int D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, 131 const SDL_Rect * rect, const void *pixels, 132 int pitch); 133static int D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture, 134 const SDL_Rect * rect, 135 const Uint8 *Yplane, int Ypitch, 136 const Uint8 *Uplane, int Upitch, 137 const Uint8 *Vplane, int Vpitch); 138static int D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, 139 const SDL_Rect * rect, void **pixels, int *pitch); 140static void D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture); 141static int D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture); 142static int D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture); 143static int D3D_UpdateViewport(SDL_Renderer * renderer); 144static int D3D_UpdateClipRect(SDL_Renderer * renderer); 145static int D3D_RenderClear(SDL_Renderer * renderer); 146static int D3D_RenderDrawPoints(SDL_Renderer * renderer, 147 const SDL_FPoint * points, int count); 148static int D3D_RenderDrawLines(SDL_Renderer * renderer, 149 const SDL_FPoint * points, int count); 150static int D3D_RenderFillRects(SDL_Renderer * renderer, 151 const SDL_FRect * rects, int count); 152static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, 153 const SDL_Rect * srcrect, const SDL_FRect * dstrect); 154static int D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, 155 const SDL_Rect * srcrect, const SDL_FRect * dstrect, 156 const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip); 157static int D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, 158 Uint32 format, void * pixels, int pitch); 159static void D3D_RenderPresent(SDL_Renderer * renderer); 160static void D3D_DestroyTexture(SDL_Renderer * renderer, 161 SDL_Texture * texture); 162static void D3D_DestroyRenderer(SDL_Renderer * renderer); 163 164 165SDL_RenderDriver D3D_RenderDriver = { 166 D3D_CreateRenderer, 167 { 168 "direct3d", 169 (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE), 170 1, 171 {SDL_PIXELFORMAT_ARGB8888}, 172 0, 173 0} 174}; 175 176typedef struct 177{ 178 void* d3dDLL; 179 IDirect3D9 *d3d; 180 IDirect3DDevice9 *device; 181 UINT adapter; 182 D3DPRESENT_PARAMETERS pparams; 183 SDL_bool updateSize; 184 SDL_bool beginScene; 185 SDL_bool enableSeparateAlphaBlend; 186 D3DTEXTUREFILTERTYPE scaleMode[8]; 187 IDirect3DSurface9 *defaultRenderTarget; 188 IDirect3DSurface9 *currentRenderTarget; 189 void* d3dxDLL; 190 LPDIRECT3DPIXELSHADER9 ps_yuv; 191} D3D_RenderData; 192 193typedef struct 194{ 195 SDL_bool dirty; 196 int w, h; 197 DWORD usage; 198 Uint32 format; 199 IDirect3DTexture9 *texture; 200 IDirect3DTexture9 *staging; 201} D3D_TextureRep; 202 203typedef struct 204{ 205 D3D_TextureRep texture; 206 D3DTEXTUREFILTERTYPE scaleMode; 207 208 /* YV12 texture support */ 209 SDL_bool yuv; 210 D3D_TextureRep utexture; 211 D3D_TextureRep vtexture; 212 Uint8 *pixels; 213 int pitch; 214 SDL_Rect locked_rect; 215} D3D_TextureData; 216 217typedef struct 218{ 219 float x, y, z; 220 DWORD color; 221 float u, v; 222} Vertex; 223 224static int 225D3D_SetError(const char *prefix, HRESULT result) 226{ 227 const char *error; 228 229 switch (result) { 230 case D3DERR_WRONGTEXTUREFORMAT: 231 error = "WRONGTEXTUREFORMAT"; 232 break; 233 case D3DERR_UNSUPPORTEDCOLOROPERATION: 234 error = "UNSUPPORTEDCOLOROPERATION"; 235 break; 236 case D3DERR_UNSUPPORTEDCOLORARG: 237 error = "UNSUPPORTEDCOLORARG"; 238 break; 239 case D3DERR_UNSUPPORTEDALPHAOPERATION: 240 error = "UNSUPPORTEDALPHAOPERATION"; 241 break; 242 case D3DERR_UNSUPPORTEDALPHAARG: 243 error = "UNSUPPORTEDALPHAARG"; 244 break; 245 case D3DERR_TOOMANYOPERATIONS: 246 error = "TOOMANYOPERATIONS"; 247 break; 248 case D3DERR_CONFLICTINGTEXTUREFILTER: 249 error = "CONFLICTINGTEXTUREFILTER"; 250 break; 251 case D3DERR_UNSUPPORTEDFACTORVALUE: 252 error = "UNSUPPORTEDFACTORVALUE"; 253 break; 254 case D3DERR_CONFLICTINGRENDERSTATE: 255 error = "CONFLICTINGRENDERSTATE"; 256 break; 257 case D3DERR_UNSUPPORTEDTEXTUREFILTER: 258 error = "UNSUPPORTEDTEXTUREFILTER"; 259 break; 260 case D3DERR_CONFLICTINGTEXTUREPALETTE: 261 error = "CONFLICTINGTEXTUREPALETTE"; 262 break; 263 case D3DERR_DRIVERINTERNALERROR: 264 error = "DRIVERINTERNALERROR"; 265 break; 266 case D3DERR_NOTFOUND: 267 error = "NOTFOUND"; 268 break; 269 case D3DERR_MOREDATA: 270 error = "MOREDATA"; 271 break; 272 case D3DERR_DEVICELOST: 273 error = "DEVICELOST"; 274 break; 275 case D3DERR_DEVICENOTRESET: 276 error = "DEVICENOTRESET"; 277 break; 278 case D3DERR_NOTAVAILABLE: 279 error = "NOTAVAILABLE"; 280 break; 281 case D3DERR_OUTOFVIDEOMEMORY: 282 error = "OUTOFVIDEOMEMORY"; 283 break; 284 case D3DERR_INVALIDDEVICE: 285 error = "INVALIDDEVICE"; 286 break; 287 case D3DERR_INVALIDCALL: 288 error = "INVALIDCALL"; 289 break; 290 case D3DERR_DRIVERINVALIDCALL: 291 error = "DRIVERINVALIDCALL"; 292 break; 293 case D3DERR_WASSTILLDRAWING: 294 error = "WASSTILLDRAWING"; 295 break; 296 default: 297 error = "UNKNOWN"; 298 break; 299 } 300 return SDL_SetError("%s: %s", prefix, error); 301} 302 303static D3DFORMAT 304PixelFormatToD3DFMT(Uint32 format) 305{ 306 switch (format) { 307 case SDL_PIXELFORMAT_RGB565: 308 return D3DFMT_R5G6B5; 309 case SDL_PIXELFORMAT_RGB888: 310 return D3DFMT_X8R8G8B8; 311 case SDL_PIXELFORMAT_ARGB8888: 312 return D3DFMT_A8R8G8B8; 313 case SDL_PIXELFORMAT_YV12: 314 case SDL_PIXELFORMAT_IYUV: 315 return D3DFMT_L8; 316 default: 317 return D3DFMT_UNKNOWN; 318 } 319} 320 321static Uint32 322D3DFMTToPixelFormat(D3DFORMAT format) 323{ 324 switch (format) { 325 case D3DFMT_R5G6B5: 326 return SDL_PIXELFORMAT_RGB565; 327 case D3DFMT_X8R8G8B8: 328 return SDL_PIXELFORMAT_RGB888; 329 case D3DFMT_A8R8G8B8: 330 return SDL_PIXELFORMAT_ARGB8888; 331 default: 332 return SDL_PIXELFORMAT_UNKNOWN; 333 } 334} 335 336static void 337D3D_InitRenderState(D3D_RenderData *data) 338{ 339 D3DMATRIX matrix; 340 341 IDirect3DDevice9 *device = data->device; 342 343 IDirect3DDevice9_SetVertexShader(device, NULL); 344 IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1); 345 IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_FALSE); 346 IDirect3DDevice9_SetRenderState(device, D3DRS_CULLMODE, D3DCULL_NONE); 347 IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE); 348 349 /* Enable color modulation by diffuse color */ 350 IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLOROP, 351 D3DTOP_MODULATE); 352 IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG1, 353 D3DTA_TEXTURE); 354 IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG2, 355 D3DTA_DIFFUSE); 356 357 /* Enable alpha modulation by diffuse alpha */ 358 IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAOP, 359 D3DTOP_MODULATE); 360 IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG1, 361 D3DTA_TEXTURE); 362 IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG2, 363 D3DTA_DIFFUSE); 364 365 /* Enable separate alpha blend function, if possible */ 366 if (data->enableSeparateAlphaBlend) { 367 IDirect3DDevice9_SetRenderState(device, D3DRS_SEPARATEALPHABLENDENABLE, TRUE); 368 } 369 370 /* Disable second texture stage, since we're done */ 371 IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_COLOROP, 372 D3DTOP_DISABLE); 373 IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_ALPHAOP, 374 D3DTOP_DISABLE); 375 376 /* Set an identity world and view matrix */ 377 matrix.m[0][0] = 1.0f; 378 matrix.m[0][1] = 0.0f; 379 matrix.m[0][2] = 0.0f; 380 matrix.m[0][3] = 0.0f; 381 matrix.m[1][0] = 0.0f; 382 matrix.m[1][1] = 1.0f; 383 matrix.m[1][2] = 0.0f; 384 matrix.m[1][3] = 0.0f; 385 matrix.m[2][0] = 0.0f; 386 matrix.m[2][1] = 0.0f; 387 matrix.m[2][2] = 1.0f; 388 matrix.m[2][3] = 0.0f; 389 matrix.m[3][0] = 0.0f; 390 matrix.m[3][1] = 0.0f; 391 matrix.m[3][2] = 0.0f; 392 matrix.m[3][3] = 1.0f; 393 IDirect3DDevice9_SetTransform(device, D3DTS_WORLD, &matrix); 394 IDirect3DDevice9_SetTransform(device, D3DTS_VIEW, &matrix); 395 396 /* Reset our current scale mode */ 397 SDL_memset(data->scaleMode, 0xFF, sizeof(data->scaleMode)); 398 399 /* Start the render with beginScene */ 400 data->beginScene = SDL_TRUE; 401} 402 403static int 404D3D_Reset(SDL_Renderer * renderer) 405{ 406 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; 407 HRESULT result; 408 SDL_Texture *texture; 409 410 /* Release the default render target before reset */ 411 if (data->defaultRenderTarget) { 412 IDirect3DSurface9_Release(data->defaultRenderTarget); 413 data->defaultRenderTarget = NULL; 414 } 415 if (data->currentRenderTarget != NULL) { 416 IDirect3DSurface9_Release(data->currentRenderTarget); 417 data->currentRenderTarget = NULL; 418 } 419 420 /* Release application render targets */ 421 for (texture = renderer->textures; texture; texture = texture->next) { 422 if (texture->access == SDL_TEXTUREACCESS_TARGET) { 423 D3D_DestroyTexture(renderer, texture); 424 } else { 425 D3D_RecreateTexture(renderer, texture); 426 } 427 } 428 429 result = IDirect3DDevice9_Reset(data->device, &data->pparams); 430 if (FAILED(result)) { 431 if (result == D3DERR_DEVICELOST) { 432 /* Don't worry about it, we'll reset later... */ 433 return 0; 434 } else { 435 return D3D_SetError("Reset()", result); 436 } 437 } 438 439 /* Allocate application render targets */ 440 for (texture = renderer->textures; texture; texture = texture->next) { 441 if (texture->access == SDL_TEXTUREACCESS_TARGET) { 442 D3D_CreateTexture(renderer, texture); 443 } 444 } 445 446 IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget); 447 D3D_InitRenderState(data); 448 D3D_SetRenderTargetInternal(renderer, renderer->target); 449 D3D_UpdateViewport(renderer); 450 451 /* Let the application know that render targets were reset */ 452 { 453 SDL_Event event; 454 event.type = SDL_RENDER_TARGETS_RESET; 455 SDL_PushEvent(&event); 456 } 457 458 return 0; 459} 460 461static int 462D3D_ActivateRenderer(SDL_Renderer * renderer) 463{ 464 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; 465 HRESULT result; 466 467 if (data->updateSize) { 468 SDL_Window *window = renderer->window; 469 int w, h; 470 Uint32 window_flags = SDL_GetWindowFlags(window); 471 472 SDL_GetWindowSize(window, &w, &h); 473 data->pparams.BackBufferWidth = w; 474 data->pparams.BackBufferHeight = h; 475 if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) { 476 SDL_DisplayMode fullscreen_mode; 477 SDL_GetWindowDisplayMode(window, &fullscreen_mode); 478 data->pparams.Windowed = FALSE; 479 data->pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format); 480 data->pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate; 481 } else { 482 data->pparams.Windowed = TRUE; 483 data->pparams.BackBufferFormat = D3DFMT_UNKNOWN; 484 data->pparams.FullScreen_RefreshRateInHz = 0; 485 } 486 if (D3D_Reset(renderer) < 0) { 487 return -1; 488 } 489 490 data->updateSize = SDL_FALSE; 491 } 492 if (data->beginScene) { 493 result = IDirect3DDevice9_BeginScene(data->device); 494 if (result == D3DERR_DEVICELOST) { 495 if (D3D_Reset(renderer) < 0) { 496 return -1; 497 } 498 result = IDirect3DDevice9_BeginScene(data->device); 499 } 500 if (FAILED(result)) { 501 return D3D_SetError("BeginScene()", result); 502 } 503 data->beginScene = SDL_FALSE; 504 } 505 return 0; 506} 507 508SDL_Renderer * 509D3D_CreateRenderer(SDL_Window * window, Uint32 flags) 510{ 511 SDL_Renderer *renderer; 512 D3D_RenderData *data; 513 SDL_SysWMinfo windowinfo; 514 HRESULT result; 515 const char *hint; 516 D3DPRESENT_PARAMETERS pparams; 517 IDirect3DSwapChain9 *chain; 518 D3DCAPS9 caps; 519 DWORD device_flags; 520 Uint32 window_flags; 521 int w, h; 522 SDL_DisplayMode fullscreen_mode; 523 int displayIndex; 524 525 renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); 526 if (!renderer) { 527 SDL_OutOfMemory(); 528 return NULL; 529 } 530 531 data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data)); 532 if (!data) { 533 SDL_free(renderer); 534 SDL_OutOfMemory(); 535 return NULL; 536 } 537 538 if (!D3D_LoadDLL(&data->d3dDLL, &data->d3d)) { 539 SDL_free(renderer); 540 SDL_free(data); 541 SDL_SetError("Unable to create Direct3D interface"); 542 return NULL; 543 } 544 545 renderer->WindowEvent = D3D_WindowEvent; 546 renderer->CreateTexture = D3D_CreateTexture; 547 renderer->UpdateTexture = D3D_UpdateTexture; 548 renderer->UpdateTextureYUV = D3D_UpdateTextureYUV; 549 renderer->LockTexture = D3D_LockTexture; 550 renderer->UnlockTexture = D3D_UnlockTexture; 551 renderer->SetRenderTarget = D3D_SetRenderTarget; 552 renderer->UpdateViewport = D3D_UpdateViewport; 553 renderer->UpdateClipRect = D3D_UpdateClipRect; 554 renderer->RenderClear = D3D_RenderClear; 555 renderer->RenderDrawPoints = D3D_RenderDrawPoints; 556 renderer->RenderDrawLines = D3D_RenderDrawLines; 557 renderer->RenderFillRects = D3D_RenderFillRects; 558 renderer->RenderCopy = D3D_RenderCopy; 559 renderer->RenderCopyEx = D3D_RenderCopyEx; 560 renderer->RenderReadPixels = D3D_RenderReadPixels; 561 renderer->RenderPresent = D3D_RenderPresent; 562 renderer->DestroyTexture = D3D_DestroyTexture; 563 renderer->DestroyRenderer = D3D_DestroyRenderer; 564 renderer->info = D3D_RenderDriver.info; 565 renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE); 566 renderer->driverdata = data; 567 568 SDL_VERSION(&windowinfo.version); 569 SDL_GetWindowWMInfo(window, &windowinfo); 570 571 window_flags = SDL_GetWindowFlags(window); 572 SDL_GetWindowSize(window, &w, &h); 573 SDL_GetWindowDisplayMode(window, &fullscreen_mode); 574 575 SDL_zero(pparams); 576 pparams.hDeviceWindow = windowinfo.info.win.window; 577 pparams.BackBufferWidth = w; 578 pparams.BackBufferHeight = h; 579 pparams.BackBufferCount = 1; 580 pparams.SwapEffect = D3DSWAPEFFECT_DISCARD; 581 582 if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) { 583 pparams.Windowed = FALSE; 584 pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format); 585 pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate; 586 } else { 587 pparams.Windowed = TRUE; 588 pparams.BackBufferFormat = D3DFMT_UNKNOWN; 589 pparams.FullScreen_RefreshRateInHz = 0; 590 } 591 if (flags & SDL_RENDERER_PRESENTVSYNC) { 592 pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE; 593 } else { 594 pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; 595 } 596 597 /* Get the adapter for the display that the window is on */ 598 displayIndex = SDL_GetWindowDisplayIndex(window); 599 data->adapter = SDL_Direct3D9GetAdapterIndex(displayIndex); 600 601 IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps); 602 603 device_flags = D3DCREATE_FPU_PRESERVE; 604 if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) { 605 device_flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING; 606 } else { 607 device_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING; 608 } 609 610 hint = SDL_GetHint(SDL_HINT_RENDER_DIRECT3D_THREADSAFE); 611 if (hint && SDL_atoi(hint)) { 612 device_flags |= D3DCREATE_MULTITHREADED; 613 } 614 615 result = IDirect3D9_CreateDevice(data->d3d, data->adapter, 616 D3DDEVTYPE_HAL, 617 pparams.hDeviceWindow, 618 device_flags, 619 &pparams, &data->device); 620 if (FAILED(result)) { 621 D3D_DestroyRenderer(renderer); 622 D3D_SetError("CreateDevice()", result); 623 return NULL; 624 } 625 626 /* Get presentation parameters to fill info */ 627 result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain); 628 if (FAILED(result)) { 629 D3D_DestroyRenderer(renderer); 630 D3D_SetError("GetSwapChain()", result); 631 return NULL; 632 } 633 result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams); 634 if (FAILED(result)) { 635 IDirect3DSwapChain9_Release(chain); 636 D3D_DestroyRenderer(renderer); 637 D3D_SetError("GetPresentParameters()", result); 638 return NULL; 639 } 640 IDirect3DSwapChain9_Release(chain); 641 if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) { 642 renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; 643 } 644 data->pparams = pparams; 645 646 IDirect3DDevice9_GetDeviceCaps(data->device, &caps); 647 renderer->info.max_texture_width = caps.MaxTextureWidth; 648 renderer->info.max_texture_height = caps.MaxTextureHeight; 649 if (caps.NumSimultaneousRTs >= 2) { 650 renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE; 651 } 652 653 if (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) { 654 data->enableSeparateAlphaBlend = SDL_TRUE; 655 } 656 657 /* Store the default render target */ 658 IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget); 659 data->currentRenderTarget = NULL; 660 661 /* Set up parameters for rendering */ 662 D3D_InitRenderState(data); 663 664 if (caps.MaxSimultaneousTextures >= 3) 665 { 666#ifdef ASSEMBLE_SHADER 667 /* This shader was created by running the following HLSL through the fxc compiler 668 and then tuning the generated assembly. 669 670 fxc /T fx_4_0 /O3 /Gfa /Fc yuv.fxc yuv.fx 671 672 --- yuv.fx --- 673 Texture2D g_txY; 674 Texture2D g_txU; 675 Texture2D g_txV; 676 677 SamplerState samLinear 678 { 679 Filter = ANISOTROPIC; 680 AddressU = Clamp; 681 AddressV = Clamp; 682 MaxAnisotropy = 1; 683 }; 684 685 struct VS_OUTPUT 686 { 687 float2 TextureUV : TEXCOORD0; 688 }; 689 690 struct PS_OUTPUT 691 { 692 float4 RGBAColor : SV_Target; 693 }; 694 695 PS_OUTPUT YUV420( VS_OUTPUT In ) 696 { 697 const float3 offset = {-0.0627451017, -0.501960814, -0.501960814}; 698 const float3 Rcoeff = {1.164, 0.000, 1.596}; 699 const float3 Gcoeff = {1.164, -0.391, -0.813}; 700 const float3 Bcoeff = {1.164, 2.018, 0.000}; 701 702 PS_OUTPUT Output; 703 float2 TextureUV = In.TextureUV; 704 705 float3 yuv; 706 yuv.x = g_txY.Sample( samLinear, TextureUV ).r; 707 yuv.y = g_txU.Sample( samLinear, TextureUV ).r; 708 yuv.z = g_txV.Sample( samLinear, TextureUV ).r; 709 710 yuv += offset; 711 Output.RGBAColor.r = dot(yuv, Rcoeff); 712 Output.RGBAColor.g = dot(yuv, Gcoeff); 713 Output.RGBAColor.b = dot(yuv, Bcoeff); 714 Output.RGBAColor.a = 1.0f; 715 716 return Output; 717 } 718 719 technique10 RenderYUV420 720 { 721 pass P0 722 { 723 SetPixelShader( CompileShader( ps_4_0_level_9_0, YUV420() ) ); 724 } 725 } 726 */ 727 const char *shader_text = 728 "ps_2_0\n" 729 "def c0, -0.0627451017, -0.501960814, -0.501960814, 1\n" 730 "def c1, 1.16400003, 0, 1.59599996, 0\n" 731 "def c2, 1.16400003, -0.391000003, -0.813000023, 0\n" 732 "def c3, 1.16400003, 2.01799989, 0, 0\n" 733 "dcl t0.xy\n" 734 "dcl v0.xyzw\n" 735 "dcl_2d s0\n" 736 "dcl_2d s1\n" 737 "dcl_2d s2\n" 738 "texld r0, t0, s0\n" 739 "texld r1, t0, s1\n" 740 "texld r2, t0, s2\n" 741 "mov r0.y, r1.x\n" 742 "mov r0.z, r2.x\n" 743 "add r0.xyz, r0, c0\n" 744 "dp3 r1.x, r0, c1\n" 745 "dp3 r1.y, r0, c2\n" 746 "dp2add r1.z, r0, c3, c3.z\n" /* Logically this is "dp3 r1.z, r0, c3" but the optimizer did its magic */ 747 "mov r1.w, c0.w\n" 748 "mul r0, r1, v0\n" /* Not in the HLSL, multiply by vertex color */ 749 "mov oC0, r0\n" 750 ; 751 LPD3DXBUFFER pCode; 752 LPD3DXBUFFER pErrorMsgs; 753 LPDWORD shader_data = NULL; 754 DWORD shader_size = 0; 755 result = D3DXAssembleShader(shader_text, SDL_strlen(shader_text), NULL, NULL, 0, &pCode, &pErrorMsgs); 756 if (!FAILED(result)) { 757 shader_data = (DWORD*)pCode->lpVtbl->GetBufferPointer(pCode); 758 shader_size = pCode->lpVtbl->GetBufferSize(pCode); 759 PrintShaderData(shader_data, shader_size); 760 } else { 761 const char *error = (const char *)pErrorMsgs->lpVtbl->GetBufferPointer(pErrorMsgs); 762 SDL_SetError("Couldn't assemble shader: %s", error); 763 } 764#else 765 const DWORD shader_data[] = { 766 0xffff0200, 0x05000051, 0xa00f0000, 0xbd808081, 0xbf008081, 0xbf008081, 767 0x3f800000, 0x05000051, 0xa00f0001, 0x3f94fdf4, 0x00000000, 0x3fcc49ba, 768 0x00000000, 0x05000051, 0xa00f0002, 0x3f94fdf4, 0xbec83127, 0xbf5020c5, 769 0x00000000, 0x05000051, 0xa00f0003, 0x3f94fdf4, 0x400126e9, 0x00000000, 770 0x00000000, 0x0200001f, 0x80000000, 0xb0030000, 0x0200001f, 0x80000000, 771 0x900f0000, 0x0200001f, 0x90000000, 0xa00f0800, 0x0200001f, 0x90000000, 772 0xa00f0801, 0x0200001f, 0x90000000, 0xa00f0802, 0x03000042, 0x800f0000, 773 0xb0e40000, 0xa0e40800, 0x03000042, 0x800f0001, 0xb0e40000, 0xa0e40801, 774 0x03000042, 0x800f0002, 0xb0e40000, 0xa0e40802, 0x02000001, 0x80020000, 775 0x80000001, 0x02000001, 0x80040000, 0x80000002, 0x03000002, 0x80070000, 776 0x80e40000, 0xa0e40000, 0x03000008, 0x80010001, 0x80e40000, 0xa0e40001, 777 0x03000008, 0x80020001, 0x80e40000, 0xa0e40002, 0x0400005a, 0x80040001, 778 0x80e40000, 0xa0e40003, 0xa0aa0003, 0x02000001, 0x80080001, 0xa0ff0000, 779 0x03000005, 0x800f0000, 0x80e40001, 0x90e40000, 0x02000001, 0x800f0800, 780 0x80e40000, 0x0000ffff 781 }; 782#endif 783 if (shader_data != NULL) { 784 result = IDirect3DDevice9_CreatePixelShader(data->device, shader_data, &data->ps_yuv); 785 if (!FAILED(result)) { 786 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12; 787 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV; 788 } else { 789 D3D_SetError("CreatePixelShader()", result); 790 } 791 } 792 } 793 794 return renderer; 795} 796 797static void 798D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) 799{ 800 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; 801 802 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) { 803 data->updateSize = SDL_TRUE; 804 } 805} 806 807static D3DTEXTUREFILTERTYPE 808GetScaleQuality(void) 809{ 810 const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY); 811 812 if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) { 813 return D3DTEXF_POINT; 814 } else /* if (*hint == '1' || SDL_strcasecmp(hint, "linear") == 0) */ { 815 return D3DTEXF_LINEAR; 816 } 817} 818 819static int 820D3D_CreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD usage, Uint32 format, int w, int h) 821{ 822 HRESULT result; 823 824 texture->dirty = SDL_FALSE; 825 texture->w = w; 826 texture->h = h; 827 texture->usage = usage; 828 texture->format = format; 829 830 result = IDirect3DDevice9_CreateTexture(device, w, h, 1, usage, 831 PixelFormatToD3DFMT(format), 832 D3DPOOL_DEFAULT, &texture->texture, NULL); 833 if (FAILED(result)) { 834 return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result); 835 } 836 return 0; 837} 838 839 840static int 841D3D_CreateStagingTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture) 842{ 843 HRESULT result; 844 845 if (texture->staging == NULL) { 846 result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage, 847 PixelFormatToD3DFMT(texture->format), 848 D3DPOOL_SYSTEMMEM, &texture->staging, NULL); 849 if (FAILED(result)) { 850 return D3D_SetError("CreateTexture(D3DPOOL_SYSTEMMEM)", result); 851 } 852 } 853 return 0; 854} 855 856static int 857D3D_BindTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD sampler) 858{ 859 HRESULT result; 860 861 if (texture->dirty && texture->staging) { 862 if (!texture->texture) { 863 result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage, 864 PixelFormatToD3DFMT(texture->format), D3DPOOL_DEFAULT, &texture->texture, NULL); 865 if (FAILED(result)) { 866 return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result); 867 } 868 } 869 870 result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texture->staging, (IDirect3DBaseTexture9 *)texture->texture); 871 if (FAILED(result)) { 872 return D3D_SetError("UpdateTexture()", result); 873 } 874 texture->dirty = SDL_FALSE; 875 } 876 result = IDirect3DDevice9_SetTexture(device, sampler, (IDirect3DBaseTexture9 *)texture->texture); 877 if (FAILED(result)) { 878 return D3D_SetError("SetTexture()", result); 879 } 880 return 0; 881} 882 883static int 884D3D_RecreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32 format, int w, int h) 885{ 886 if (texture->texture) { 887 IDirect3DTexture9_Release(texture->texture); 888 texture->texture = NULL; 889 } 890 if (texture->staging) { 891 IDirect3DTexture9_AddDirtyRect(texture->staging, NULL); 892 texture->dirty = SDL_TRUE; 893 } 894 return 0; 895} 896 897static int 898D3D_UpdateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32 format, int x, int y, int w, int h, const void *pixels, int pitch) 899{ 900 RECT d3drect; 901 D3DLOCKED_RECT locked; 902 const Uint8 *src; 903 Uint8 *dst; 904 int row, length; 905 HRESULT result; 906 907 if (D3D_CreateStagingTexture(device, texture) < 0) { 908 return -1; 909 } 910 911 d3drect.left = x; 912 d3drect.right = x + w; 913 d3drect.top = y; 914 d3drect.bottom = y + h; 915 916 result = IDirect3DTexture9_LockRect(texture->staging, 0, &locked, &d3drect, 0); 917 if (FAILED(result)) { 918 return D3D_SetError("LockRect()", result); 919 } 920 921 src = (const Uint8 *)pixels; 922 dst = locked.pBits; 923 length = w * SDL_BYTESPERPIXEL(format); 924 if (length == pitch && length == locked.Pitch) { 925 SDL_memcpy(dst, src, length*h); 926 } else { 927 if (length > pitch) { 928 length = pitch; 929 } 930 if (length > locked.Pitch) { 931 length = locked.Pitch; 932 } 933 for (row = 0; row < h; ++row) { 934 SDL_memcpy(dst, src, length); 935 src += pitch; 936 dst += locked.Pitch; 937 } 938 } 939 result = IDirect3DTexture9_UnlockRect(texture->staging, 0); 940 if (FAILED(result)) { 941 return D3D_SetError("UnlockRect()", result); 942 } 943 texture->dirty = SDL_TRUE; 944 945 return 0; 946} 947 948static void 949D3D_DestroyTextureRep(D3D_TextureRep *texture) 950{ 951 if (texture->texture) { 952 IDirect3DTexture9_Release(texture->texture); 953 texture->texture = NULL; 954 } 955 if (texture->staging) { 956 IDirect3DTexture9_Release(texture->staging); 957 texture->staging = NULL; 958 } 959} 960 961static int 962D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) 963{ 964 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; 965 D3D_TextureData *texturedata; 966 DWORD usage; 967 968 texturedata = (D3D_TextureData *) SDL_calloc(1, sizeof(*texturedata)); 969 if (!texturedata) { 970 return SDL_OutOfMemory(); 971 } 972 texturedata->scaleMode = GetScaleQuality(); 973 974 texture->driverdata = texturedata; 975 976 if (texture->access == SDL_TEXTUREACCESS_TARGET) { 977 usage = D3DUSAGE_RENDERTARGET; 978 } else { 979 usage = 0; 980 } 981 982 if (D3D_CreateTextureRep(data->device, &texturedata->texture, usage, texture->format, texture->w, texture->h) < 0) { 983 return -1; 984 } 985 986 if (texture->format == SDL_PIXELFORMAT_YV12 || 987 texture->format == SDL_PIXELFORMAT_IYUV) { 988 texturedata->yuv = SDL_TRUE; 989 990 if (D3D_CreateTextureRep(data->device, &texturedata->utexture, usage, texture->format, texture->w / 2, texture->h / 2) < 0) { 991 return -1; 992 } 993 994 if (D3D_CreateTextureRep(data->device, &texturedata->vtexture, usage, texture->format, texture->w / 2, texture->h / 2) < 0) { 995 return -1; 996 } 997 } 998 return 0; 999} 1000 1001static int 1002D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) 1003{ 1004 D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata; 1005 D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata; 1006 1007 if (D3D_RecreateTextureRep(data->device, &texturedata->texture, texture->format, texture->w, texture->h) < 0) { 1008 return -1; 1009 } 1010 1011 if (texturedata->yuv) { 1012 if (D3D_RecreateTextureRep(data->device, &texturedata->utexture, texture->format, texture->w / 2, texture->h / 2) < 0) { 1013 return -1; 1014 } 1015 1016 if (D3D_RecreateTextureRep(data->device, &texturedata->vtexture, texture->format, texture->w / 2, texture->h / 2) < 0) { 1017 return -1; 1018 } 1019 } 1020 return 0; 1021} 1022 1023static int 1024D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, 1025 const SDL_Rect * rect, const void *pixels, int pitch) 1026{ 1027 D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata; 1028 D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata; 1029 1030 if (!texturedata) { 1031 SDL_SetError("Texture is not currently available"); 1032 return -1; 1033 } 1034 1035 if (D3D_UpdateTextureRep(data->device, &texturedata->texture, texture->format, rect->x, rect->y, rect->w, rect->h, pixels, pitch) < 0) { 1036 return -1; 1037 } 1038 1039 if (texturedata->yuv) { 1040 /* Skip to the correct offset into the next texture */ 1041 pixels = (const void*)((const Uint8*)pixels + rect->h * pitch); 1042 1043 if (D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->vtexture : &texturedata->utexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, pixels, pitch / 2) < 0) { 1044 return -1; 1045 } 1046 1047 /* Skip to the correct offset into the next texture */ 1048 pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4); 1049 if (D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->utexture : &texturedata->vtexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, pixels, pitch / 2) < 0) { 1050 return -1; 1051 } 1052 } 1053 return 0; 1054} 1055 1056static int 1057D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture, 1058 const SDL_Rect * rect, 1059 const Uint8 *Yplane, int Ypitch, 1060 const Uint8 *Uplane, int Upitch, 1061 const Uint8 *Vplane, int Vpitch) 1062{ 1063 D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata; 1064 D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata; 1065 1066 if (!texturedata) { 1067 SDL_SetError("Texture is not currently available"); 1068 return -1; 1069 } 1070 1071 if (D3D_UpdateTextureRep(data->device, &texturedata->texture, texture->format, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) { 1072 return -1; 1073 } 1074 if (D3D_UpdateTextureRep(data->device, &texturedata->utexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Uplane, Upitch) < 0) { 1075 return -1; 1076 } 1077 if (D3D_UpdateTextureRep(data->device, &texturedata->vtexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Vplane, Vpitch) < 0) { 1078 return -1; 1079 } 1080 return 0; 1081} 1082 1083static int 1084D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, 1085 const SDL_Rect * rect, void **pixels, int *pitch) 1086{ 1087 D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata; 1088 D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata; 1089 IDirect3DDevice9 *device = data->device; 1090 1091 if (!texturedata) { 1092 SDL_SetError("Texture is not currently available"); 1093 return -1; 1094 } 1095 1096 texturedata->locked_rect = *rect; 1097 1098 if (texturedata->yuv) { 1099 /* It's more efficient to upload directly... */ 1100 if (!texturedata->pixels) { 1101 texturedata->pitch = texture->w; 1102 texturedata->pixels = (Uint8 *)SDL_malloc((texture->h * texturedata->pitch * 3) / 2); 1103 if (!texturedata->pixels) { 1104 return SDL_OutOfMemory(); 1105 } 1106 } 1107 *pixels = 1108 (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch + 1109 rect->x * SDL_BYTESPERPIXEL(texture->format)); 1110 *pitch = texturedata->pitch; 1111 } else { 1112 RECT d3drect; 1113 D3DLOCKED_RECT locked; 1114 HRESULT result; 1115 1116 if (D3D_CreateStagingTexture(device, &texturedata->texture) < 0) { 1117 return -1; 1118 } 1119 1120 d3drect.left = rect->x; 1121 d3drect.right = rect->x + rect->w; 1122 d3drect.top = rect->y; 1123 d3drect.bottom = rect->y + rect->h; 1124 1125 result = IDirect3DTexture9_LockRect(texturedata->texture.staging, 0, &locked, &d3drect, 0); 1126 if (FAILED(result)) { 1127 return D3D_SetError("LockRect()", result); 1128 } 1129 *pixels = locked.pBits; 1130 *pitch = locked.Pitch; 1131 } 1132 return 0; 1133} 1134 1135static void 1136D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) 1137{ 1138 /*D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;*/ 1139 D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata; 1140 1141 if (!texturedata) { 1142 return; 1143 } 1144 1145 if (texturedata->yuv) { 1146 const SDL_Rect *rect = &texturedata->locked_rect; 1147 void *pixels = 1148 (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch + 1149 rect->x * SDL_BYTESPERPIXEL(texture->format)); 1150 D3D_UpdateTexture(renderer, texture, rect, pixels, texturedata->pitch); 1151 } else { 1152 IDirect3DTexture9_UnlockRect(texturedata->texture.staging, 0); 1153 texturedata->texture.dirty = SDL_TRUE; 1154 } 1155} 1156 1157static int 1158D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture) 1159{ 1160 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; 1161 D3D_TextureData *texturedata; 1162 D3D_TextureRep *texturerep; 1163 HRESULT result; 1164 IDirect3DDevice9 *device = data->device; 1165 1166 /* Release the previous render target if it wasn't the default one */ 1167 if (data->currentRenderTarget != NULL) { 1168 IDirect3DSurface9_Release(data->currentRenderTarget); 1169 data->currentRenderTarget = NULL; 1170 } 1171 1172 if (texture == NULL) { 1173 IDirect3DDevice9_SetRenderTarget(data->device, 0, data->defaultRenderTarget); 1174 return 0; 1175 } 1176 1177 texturedata = (D3D_TextureData *)texture->driverdata; 1178 if (!texturedata) { 1179 SDL_SetError("Texture is not currently available"); 1180 return -1; 1181 } 1182 1183 /* Make sure the render target is updated if it was locked and written to */ 1184 texturerep = &texturedata->texture; 1185 if (texturerep->dirty && texturerep->staging) { 1186 if (!texturerep->texture) { 1187 result = IDirect3DDevice9_CreateTexture(device, texturerep->w, texturerep->h, 1, texturerep->usage, 1188 PixelFormatToD3DFMT(texturerep->format), D3DPOOL_DEFAULT, &texturerep->texture, NULL); 1189 if (FAILED(result)) { 1190 return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result); 1191 } 1192 } 1193 1194 result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texturerep->staging, (IDirect3DBaseTexture9 *)texturerep->texture); 1195 if (FAILED(result)) { 1196 return D3D_SetError("UpdateTexture()", result); 1197 } 1198 texturerep->dirty = SDL_FALSE; 1199 } 1200 1201 result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture.texture, 0, &data->currentRenderTarget); 1202 if(FAILED(result)) { 1203 return D3D_SetError("GetSurfaceLevel()", result); 1204 } 1205 result = IDirect3DDevice9_SetRenderTarget(data->device, 0, data->currentRenderTarget); 1206 if(FAILED(result)) { 1207 return D3D_SetError("SetRenderTarget()", result); 1208 } 1209 1210 return 0; 1211} 1212 1213static int 1214D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture) 1215{ 1216 D3D_ActivateRenderer(renderer); 1217 1218 return D3D_SetRenderTargetInternal(renderer, texture); 1219} 1220 1221static int 1222D3D_UpdateViewport(SDL_Renderer * renderer) 1223{ 1224 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; 1225 D3DVIEWPORT9 viewport; 1226 D3DMATRIX matrix; 1227 1228 /* Set the viewport */ 1229 viewport.X = renderer->viewport.x; 1230 viewport.Y = renderer->viewport.y; 1231 viewport.Width = renderer->viewport.w; 1232 viewport.Height = renderer->viewport.h; 1233 viewport.MinZ = 0.0f; 1234 viewport.MaxZ = 1.0f; 1235 IDirect3DDevice9_SetViewport(data->device, &viewport); 1236 1237 /* Set an orthographic projection matrix */ 1238 if (renderer->viewport.w && renderer->viewport.h) { 1239 matrix.m[0][0] = 2.0f / renderer->viewport.w; 1240 matrix.m[0][1] = 0.0f; 1241 matrix.m[0][2] = 0.0f; 1242 matrix.m[0][3] = 0.0f; 1243 matrix.m[1][0] = 0.0f; 1244 matrix.m[1][1] = -2.0f / renderer->viewport.h; 1245 matrix.m[1][2] = 0.0f; 1246 matrix.m[1][3] = 0.0f; 1247 matrix.m[2][0] = 0.0f; 1248 matrix.m[2][1] = 0.0f; 1249 matrix.m[2][2] = 1.0f; 1250 matrix.m[2][3] = 0.0f; 1251 matrix.m[3][0] = -1.0f; 1252 matrix.m[3][1] = 1.0f; 1253 matrix.m[3][2] = 0.0f; 1254 matrix.m[3][3] = 1.0f; 1255 IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &matrix); 1256 } 1257 1258 return 0; 1259} 1260 1261static int 1262D3D_UpdateClipRect(SDL_Renderer * renderer) 1263{ 1264 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; 1265 1266 if (renderer->clipping_enabled) { 1267 const SDL_Rect *rect = &renderer->clip_rect; 1268 RECT r; 1269 HRESULT result; 1270 1271 IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, TRUE); 1272 r.left = rect->x; 1273 r.top = rect->y; 1274 r.right = rect->x + rect->w; 1275 r.bottom = rect->y + rect->h; 1276 1277 result = IDirect3DDevice9_SetScissorRect(data->device, &r); 1278 if (result != D3D_OK) { 1279 D3D_SetError("SetScissor()", result); 1280 return -1; 1281 } 1282 } else { 1283 IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE); 1284 } 1285 return 0; 1286} 1287 1288static int 1289D3D_RenderClear(SDL_Renderer * renderer) 1290{ 1291 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; 1292 DWORD color; 1293 HRESULT result; 1294 int BackBufferWidth, BackBufferHeight; 1295 1296 if (D3D_ActivateRenderer(renderer) < 0) { 1297 return -1; 1298 } 1299 1300 color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b); 1301 1302 if (renderer->target) { 1303 BackBufferWidth = renderer->target->w; 1304 BackBufferHeight = renderer->target->h; 1305 } else { 1306 BackBufferWidth = data->pparams.BackBufferWidth; 1307 BackBufferHeight = data->pparams.BackBufferHeight; 1308 } 1309 1310 /* Don't reset the viewport if we don't have to! */ 1311 if (!renderer->viewport.x && !renderer->viewport.y && 1312 renderer->viewport.w == BackBufferWidth && 1313 renderer->viewport.h == BackBufferHeight) { 1314 result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0); 1315 } else { 1316 D3DVIEWPORT9 viewport; 1317 1318 /* Clear is defined to clear the entire render target */ 1319 viewport.X = 0; 1320 viewport.Y = 0; 1321 viewport.Width = BackBufferWidth; 1322 viewport.Height = BackBufferHeight; 1323 viewport.MinZ = 0.0f; 1324 viewport.MaxZ = 1.0f; 1325 IDirect3DDevice9_SetViewport(data->device, &viewport); 1326 1327 result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0); 1328 1329 /* Reset the viewport */ 1330 viewport.X = renderer->viewport.x; 1331 viewport.Y = renderer->viewport.y; 1332 viewport.Width = renderer->viewport.w; 1333 viewport.Height = renderer->viewport.h; 1334 viewport.MinZ = 0.0f; 1335 viewport.MaxZ = 1.0f; 1336 IDirect3DDevice9_SetViewport(data->device, &viewport); 1337 } 1338 1339 if (FAILED(result)) { 1340 return D3D_SetError("Clear()", result); 1341 } 1342 return 0; 1343} 1344 1345static void 1346D3D_SetBlendMode(D3D_RenderData * data, int blendMode) 1347{ 1348 switch (blendMode) { 1349 case SDL_BLENDMODE_NONE: 1350 IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, 1351 FALSE); 1352 break; 1353 case SDL_BLENDMODE_BLEND: 1354 IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, 1355 TRUE); 1356 IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND, 1357 D3DBLEND_SRCALPHA); 1358 IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND, 1359 D3DBLEND_INVSRCALPHA); 1360 if (data->enableSeparateAlphaBlend) { 1361 IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA, 1362 D3DBLEND_ONE); 1363 IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA, 1364 D3DBLEND_INVSRCALPHA); 1365 } 1366 break; 1367 case SDL_BLENDMODE_ADD: 1368 IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, 1369 TRUE); 1370 IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND, 1371 D3DBLEND_SRCALPHA); 1372 IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND, 1373 D3DBLEND_ONE); 1374 if (data->enableSeparateAlphaBlend) { 1375 IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA, 1376 D3DBLEND_ZERO); 1377 IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA, 1378 D3DBLEND_ONE); 1379 } 1380 break; 1381 case SDL_BLENDMODE_MOD: 1382 IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, 1383 TRUE); 1384 IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND, 1385 D3DBLEND_ZERO); 1386 IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND, 1387 D3DBLEND_SRCCOLOR); 1388 if (data->enableSeparateAlphaBlend) { 1389 IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA, 1390 D3DBLEND_ZERO); 1391 IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA, 1392 D3DBLEND_ONE); 1393 } 1394 break; 1395 } 1396} 1397 1398static int 1399D3D_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points, 1400 int count) 1401{ 1402 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; 1403 DWORD color; 1404 Vertex *vertices; 1405 int i; 1406 HRESULT result; 1407 1408 if (D3D_ActivateRenderer(renderer) < 0) { 1409 return -1; 1410 } 1411 1412 D3D_SetBlendMode(data, renderer->blendMode); 1413 1414 result = 1415 IDirect3DDevice9_SetTexture(data->device, 0, 1416 (IDirect3DBaseTexture9 *) 0); 1417 if (FAILED(result)) { 1418 return D3D_SetError("SetTexture()", result); 1419 } 1420 1421 color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b); 1422 1423 vertices = SDL_stack_alloc(Vertex, count); 1424 for (i = 0; i < count; ++i) { 1425 vertices[i].x = points[i].x; 1426 vertices[i].y = points[i].y; 1427 vertices[i].z = 0.0f; 1428 vertices[i].color = color; 1429 vertices[i].u = 0.0f; 1430 vertices[i].v = 0.0f; 1431 } 1432 result = 1433 IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count, 1434 vertices, sizeof(*vertices)); 1435 SDL_stack_free(vertices); 1436 if (FAILED(result)) { 1437 return D3D_SetError("DrawPrimitiveUP()", result); 1438 } 1439 return 0; 1440} 1441 1442static int 1443D3D_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points, 1444 int count) 1445{ 1446 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; 1447 DWORD color; 1448 Vertex *vertices; 1449 int i; 1450 HRESULT result; 1451 1452 if (D3D_ActivateRenderer(renderer) < 0) { 1453 return -1; 1454 } 1455 1456 D3D_SetBlendMode(data, renderer->blendMode); 1457 1458 result = 1459 IDirect3DDevice9_SetTexture(data->device, 0, 1460 (IDirect3DBaseTexture9 *) 0); 1461 if (FAILED(result)) { 1462 return D3D_SetError("SetTexture()", result); 1463 } 1464 1465 color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b); 1466 1467 vertices = SDL_stack_alloc(Vertex, count); 1468 for (i = 0; i < count; ++i) { 1469 vertices[i].x = points[i].x; 1470 vertices[i].y = points[i].y; 1471 vertices[i].z = 0.0f; 1472 vertices[i].color = color; 1473 vertices[i].u = 0.0f; 1474 vertices[i].v = 0.0f; 1475 } 1476 result = 1477 IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count-1, 1478 vertices, sizeof(*vertices)); 1479 1480 /* DirectX 9 has the same line rasterization semantics as GDI, 1481 so we need to close the endpoint of the line */ 1482 if (count == 2 || 1483 points[0].x != points[count-1].x || points[0].y != points[count-1].y) { 1484 vertices[0].x = points[count-1].x; 1485 vertices[0].y = points[count-1].y; 1486 result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, vertices, sizeof(*vertices)); 1487 } 1488 1489 SDL_stack_free(vertices); 1490 if (FAILED(result)) { 1491 return D3D_SetError("DrawPrimitiveUP()", result); 1492 } 1493 return 0; 1494} 1495 1496static int 1497D3D_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, 1498 int count) 1499{ 1500 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; 1501 DWORD color; 1502 int i; 1503 float minx, miny, maxx, maxy; 1504 Vertex vertices[4]; 1505 HRESULT result; 1506 1507 if (D3D_ActivateRenderer(renderer) < 0) { 1508 return -1; 1509 } 1510 1511 D3D_SetBlendMode(data, renderer->blendMode); 1512 1513 result = 1514 IDirect3DDevice9_SetTexture(data->device, 0, 1515 (IDirect3DBaseTexture9 *) 0); 1516 if (FAILED(result)) { 1517 return D3D_SetError("SetTexture()", result); 1518 } 1519 1520 color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b); 1521 1522 for (i = 0; i < count; ++i) { 1523 const SDL_FRect *rect = &rects[i]; 1524 1525 minx = rect->x; 1526 miny = rect->y; 1527 maxx = rect->x + rect->w; 1528 maxy = rect->y + rect->h; 1529 1530 vertices[0].x = minx; 1531 vertices[0].y = miny; 1532 vertices[0].z = 0.0f; 1533 vertices[0].color = color; 1534 vertices[0].u = 0.0f; 1535 vertices[0].v = 0.0f; 1536 1537 vertices[1].x = maxx; 1538 vertices[1].y = miny; 1539 vertices[1].z = 0.0f; 1540 vertices[1].color = color; 1541 vertices[1].u = 0.0f; 1542 vertices[1].v = 0.0f; 1543 1544 vertices[2].x = maxx; 1545 vertices[2].y = maxy; 1546 vertices[2].z = 0.0f; 1547 vertices[2].color = color; 1548 vertices[2].u = 0.0f; 1549 vertices[2].v = 0.0f; 1550 1551 vertices[3].x = minx; 1552 vertices[3].y = maxy; 1553 vertices[3].z = 0.0f; 1554 vertices[3].color = color; 1555 vertices[3].u = 0.0f; 1556 vertices[3].v = 0.0f; 1557 1558 result = 1559 IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 1560 2, vertices, sizeof(*vertices)); 1561 if (FAILED(result)) { 1562 return D3D_SetError("DrawPrimitiveUP()", result); 1563 } 1564 } 1565 return 0; 1566} 1567 1568static void 1569D3D_UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index) 1570{ 1571 if (texturedata->scaleMode != data->scaleMode[index]) { 1572 IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER, 1573 texturedata->scaleMode); 1574 IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER, 1575 texturedata->scaleMode); 1576 data->scaleMode[index] = texturedata->scaleMode; 1577 } 1578} 1579 1580static int 1581D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, 1582 const SDL_Rect * srcrect, const SDL_FRect * dstrect) 1583{ 1584 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; 1585 D3D_TextureData *texturedata; 1586 LPDIRECT3DPIXELSHADER9 shader = NULL; 1587 float minx, miny, maxx, maxy; 1588 float minu, maxu, minv, maxv; 1589 DWORD color; 1590 Vertex vertices[4]; 1591 HRESULT result; 1592 1593 if (D3D_ActivateRenderer(renderer) < 0) { 1594 return -1; 1595 } 1596 1597 texturedata = (D3D_TextureData *)texture->driverdata; 1598 if (!texturedata) { 1599 SDL_SetError("Texture is not currently available"); 1600 return -1; 1601 } 1602 1603 minx = dstrect->x - 0.5f; 1604 miny = dstrect->y - 0.5f; 1605 maxx = dstrect->x + dstrect->w - 0.5f; 1606 maxy = dstrect->y + dstrect->h - 0.5f; 1607 1608 minu = (float) srcrect->x / texture->w; 1609 maxu = (float) (srcrect->x + srcrect->w) / texture->w; 1610 minv = (float) srcrect->y / texture->h; 1611 maxv = (float) (srcrect->y + srcrect->h) / texture->h; 1612 1613 color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b); 1614 1615 vertices[0].x = minx; 1616 vertices[0].y = miny; 1617 vertices[0].z = 0.0f; 1618 vertices[0].color = color; 1619 vertices[0].u = minu; 1620 vertices[0].v = minv; 1621 1622 vertices[1].x = maxx; 1623 vertices[1].y = miny; 1624 vertices[1].z = 0.0f; 1625 vertices[1].color = color; 1626 vertices[1].u = maxu; 1627 vertices[1].v = minv; 1628 1629 vertices[2].x = maxx; 1630 vertices[2].y = maxy; 1631 vertices[2].z = 0.0f; 1632 vertices[2].color = color; 1633 vertices[2].u = maxu; 1634 vertices[2].v = maxv; 1635 1636 vertices[3].x = minx; 1637 vertices[3].y = maxy; 1638 vertices[3].z = 0.0f; 1639 vertices[3].color = color; 1640 vertices[3].u = minu; 1641 vertices[3].v = maxv; 1642 1643 D3D_SetBlendMode(data, texture->blendMode); 1644 1645 D3D_UpdateTextureScaleMode(data, texturedata, 0); 1646 1647 if (D3D_BindTextureRep(data->device, &texturedata->texture, 0) < 0) { 1648 return -1; 1649 } 1650 1651 if (texturedata->yuv) { 1652 shader = data->ps_yuv; 1653 1654 D3D_UpdateTextureScaleMode(data, texturedata, 1); 1655 D3D_UpdateTextureScaleMode(data, texturedata, 2); 1656 1657 if (D3D_BindTextureRep(data->device, &texturedata->utexture, 1) < 0) { 1658 return -1; 1659 } 1660 if (D3D_BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) { 1661 return -1; 1662 } 1663 } 1664 1665 if (shader) { 1666 result = IDirect3DDevice9_SetPixelShader(data->device, shader); 1667 if (FAILED(result)) { 1668 return D3D_SetError("SetShader()", result); 1669 } 1670 } 1671 result = 1672 IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, 1673 vertices, sizeof(*vertices)); 1674 if (FAILED(result)) { 1675 return D3D_SetError("DrawPrimitiveUP()", result); 1676 } 1677 if (shader) { 1678 result = IDirect3DDevice9_SetPixelShader(data->device, NULL); 1679 if (FAILED(result)) { 1680 return D3D_SetError("SetShader()", result); 1681 } 1682 } 1683 return 0; 1684} 1685 1686 1687static int 1688D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, 1689 const SDL_Rect * srcrect, const SDL_FRect * dstrect, 1690 const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip) 1691{ 1692 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; 1693 D3D_TextureData *texturedata; 1694 LPDIRECT3DPIXELSHADER9 shader = NULL; 1695 float minx, miny, maxx, maxy; 1696 float minu, maxu, minv, maxv; 1697 float centerx, centery; 1698 DWORD color; 1699 Vertex vertices[4]; 1700 Float4X4 modelMatrix; 1701 HRESULT result; 1702 1703 if (D3D_ActivateRenderer(renderer) < 0) { 1704 return -1; 1705 } 1706 1707 texturedata = (D3D_TextureData *)texture->driverdata; 1708 if (!texturedata) { 1709 SDL_SetError("Texture is not currently available"); 1710 return -1; 1711 } 1712 1713 centerx = center->x; 1714 centery = center->y; 1715 1716 if (flip & SDL_FLIP_HORIZONTAL) { 1717 minx = dstrect->w - centerx - 0.5f; 1718 maxx = -centerx - 0.5f; 1719 } 1720 else { 1721 minx = -centerx - 0.5f; 1722 maxx = dstrect->w - centerx - 0.5f; 1723 } 1724 1725 if (flip & SDL_FLIP_VERTICAL) { 1726 miny = dstrect->h - centery - 0.5f; 1727 maxy = -centery - 0.5f; 1728 } 1729 else { 1730 miny = -centery - 0.5f; 1731 maxy = dstrect->h - centery - 0.5f; 1732 } 1733 1734 minu = (float) srcrect->x / texture->w; 1735 maxu = (float) (srcrect->x + srcrect->w) / texture->w; 1736 minv = (float) srcrect->y / texture->h; 1737 maxv = (float) (srcrect->y + srcrect->h) / texture->h; 1738 1739 color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b); 1740 1741 vertices[0].x = minx; 1742 vertices[0].y = miny; 1743 vertices[0].z = 0.0f; 1744 vertices[0].color = color; 1745 vertices[0].u = minu; 1746 vertices[0].v = minv; 1747 1748 vertices[1].x = maxx; 1749 vertices[1].y = miny; 1750 vertices[1].z = 0.0f; 1751 vertices[1].color = color; 1752 vertices[1].u = maxu; 1753 vertices[1].v = minv; 1754 1755 vertices[2].x = maxx; 1756 vertices[2].y = maxy; 1757 vertices[2].z = 0.0f; 1758 vertices[2].color = color; 1759 vertices[2].u = maxu; 1760 vertices[2].v = maxv; 1761 1762 vertices[3].x = minx; 1763 vertices[3].y = maxy; 1764 vertices[3].z = 0.0f; 1765 vertices[3].color = color; 1766 vertices[3].u = minu; 1767 vertices[3].v = maxv; 1768 1769 D3D_SetBlendMode(data, texture->blendMode); 1770 1771 /* Rotate and translate */ 1772 modelMatrix = MatrixMultiply( 1773 MatrixRotationZ((float)(M_PI * (float) angle / 180.0f)), 1774 MatrixTranslation(dstrect->x + center->x, dstrect->y + center->y, 0) 1775); 1776 IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix); 1777 1778 D3D_UpdateTextureScaleMode(data, texturedata, 0); 1779 1780 if (D3D_BindTextureRep(data->device, &texturedata->texture, 0) < 0) { 1781 return -1; 1782 } 1783 1784 if (texturedata->yuv) { 1785 shader = data->ps_yuv; 1786 1787 D3D_UpdateTextureScaleMode(data, texturedata, 1); 1788 D3D_UpdateTextureScaleMode(data, texturedata, 2); 1789 1790 if (D3D_BindTextureRep(data->device, &texturedata->utexture, 1) < 0) { 1791 return -1; 1792 } 1793 if (D3D_BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) { 1794 return -1; 1795 } 1796 } 1797 1798 if (shader) { 1799 result = IDirect3DDevice9_SetPixelShader(data->device, shader); 1800 if (FAILED(result)) { 1801 return D3D_SetError("SetShader()", result); 1802 } 1803 } 1804 result = 1805 IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, 1806 vertices, sizeof(*vertices)); 1807 if (FAILED(result)) { 1808 return D3D_SetError("DrawPrimitiveUP()", result); 1809 } 1810 if (shader) { 1811 result = IDirect3DDevice9_SetPixelShader(data->device, NULL); 1812 if (FAILED(result)) { 1813 return D3D_SetError("SetShader()", result); 1814 } 1815 } 1816 1817 modelMatrix = MatrixIdentity(); 1818 IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix); 1819 return 0; 1820} 1821 1822static int 1823D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, 1824 Uint32 format, void * pixels, int pitch) 1825{ 1826 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; 1827 D3DSURFACE_DESC desc; 1828 LPDIRECT3DSURFACE9 backBuffer; 1829 LPDIRECT3DSURFACE9 surface; 1830 RECT d3drect; 1831 D3DLOCKED_RECT locked; 1832 HRESULT result; 1833 1834 if (data->currentRenderTarget) { 1835 backBuffer = data->currentRenderTarget; 1836 } else { 1837 backBuffer = data->defaultRenderTarget; 1838 } 1839 1840 result = IDirect3DSurface9_GetDesc(backBuffer, &desc); 1841 if (FAILED(result)) { 1842 IDirect3DSurface9_Release(backBuffer); 1843 return D3D_SetError("GetDesc()", result); 1844 } 1845 1846 result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL); 1847 if (FAILED(result)) { 1848 IDirect3DSurface9_Release(backBuffer); 1849 return D3D_SetError("CreateOffscreenPlainSurface()", result); 1850 } 1851 1852 result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface); 1853 if (FAILED(result)) { 1854 IDirect3DSurface9_Release(surface); 1855 IDirect3DSurface9_Release(backBuffer); 1856 return D3D_SetError("GetRenderTargetData()", result); 1857 } 1858 1859 d3drect.left = rect->x; 1860 d3drect.right = rect->x + rect->w; 1861 d3drect.top = rect->y; 1862 d3drect.bottom = rect->y + rect->h; 1863 1864 result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY); 1865 if (FAILED(result)) { 1866 IDirect3DSurface9_Release(surface); 1867 IDirect3DSurface9_Release(backBuffer); 1868 return D3D_SetError("LockRect()", result); 1869 } 1870 1871 SDL_ConvertPixels(rect->w, rect->h, 1872 D3DFMTToPixelFormat(desc.Format), locked.pBits, locked.Pitch, 1873 format, pixels, pitch); 1874 1875 IDirect3DSurface9_UnlockRect(surface); 1876 1877 IDirect3DSurface9_Release(surface); 1878 1879 return 0; 1880} 1881 1882static void 1883D3D_RenderPresent(SDL_Renderer * renderer) 1884{ 1885 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; 1886 HRESULT result; 1887 1888 if (!data->beginScene) { 1889 IDirect3DDevice9_EndScene(data->device); 1890 data->beginScene = SDL_TRUE; 1891 } 1892 1893 result = IDirect3DDevice9_TestCooperativeLevel(data->device); 1894 if (result == D3DERR_DEVICELOST) { 1895 /* We'll reset later */ 1896 return; 1897 } 1898 if (result == D3DERR_DEVICENOTRESET) { 1899 D3D_Reset(renderer); 1900 } 1901 result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL); 1902 if (FAILED(result)) { 1903 D3D_SetError("Present()", result); 1904 } 1905} 1906 1907static void 1908D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) 1909{ 1910 D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; 1911 1912 if (!data) { 1913 return; 1914 } 1915 D3D_DestroyTextureRep(&data->texture); 1916 D3D_DestroyTextureRep(&data->utexture); 1917 D3D_DestroyTextureRep(&data->vtexture); 1918 SDL_free(data->pixels); 1919 SDL_free(data); 1920 texture->driverdata = NULL; 1921} 1922 1923static void 1924D3D_DestroyRenderer(SDL_Renderer * renderer) 1925{ 1926 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; 1927 1928 if (data) { 1929 /* Release the render target */ 1930 if (data->defaultRenderTarget) { 1931 IDirect3DSurface9_Release(data->defaultRenderTarget); 1932 data->defaultRenderTarget = NULL; 1933 } 1934 if (data->currentRenderTarget != NULL) { 1935 IDirect3DSurface9_Release(data->currentRenderTarget); 1936 data->currentRenderTarget = NULL; 1937 } 1938 if (data->ps_yuv) { 1939 IDirect3DPixelShader9_Release(data->ps_yuv); 1940 } 1941 if (data->device) { 1942 IDirect3DDevice9_Release(data->device); 1943 } 1944 if (data->d3d) { 1945 IDirect3D9_Release(data->d3d); 1946 SDL_UnloadObject(data->d3dDLL); 1947 } 1948 SDL_free(data); 1949 } 1950 SDL_free(renderer); 1951} 1952#endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */ 1953 1954#ifdef __WIN32__ 1955/* This function needs to always exist on Windows, for the Dynamic API. */ 1956IDirect3DDevice9 * 1957SDL_RenderGetD3D9Device(SDL_Renderer * renderer) 1958{ 1959 IDirect3DDevice9 *device = NULL; 1960 1961#if SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED 1962 D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; 1963 1964 /* Make sure that this is a D3D renderer */ 1965 if (renderer->DestroyRenderer != D3D_DestroyRenderer) { 1966 SDL_SetError("Renderer is not a D3D renderer"); 1967 return NULL; 1968 } 1969 1970 device = data->device; 1971 if (device) { 1972 IDirect3DDevice9_AddRef(device); 1973 } 1974#endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */ 1975 1976 return device; 1977} 1978#endif /* __WIN32__ */ 1979 1980/* vi: set ts=4 sw=4 expandtab: */