comparison src/video/win32/SDL_d3drender.c @ 2973:ab0c00f1b070

Improved Direct3D YUV texture support
author Sam Lantinga <slouken@libsdl.org>
date Sat, 03 Jan 2009 05:42:18 +0000
parents 0a4b70368372
children 502adab079a4
comparison
equal deleted inserted replaced
2972:0a4b70368372 2973:ab0c00f1b070
22 #include "SDL_config.h" 22 #include "SDL_config.h"
23 23
24 #if SDL_VIDEO_RENDER_D3D 24 #if SDL_VIDEO_RENDER_D3D
25 25
26 #include "SDL_win32video.h" 26 #include "SDL_win32video.h"
27 #include "../SDL_yuv_sw_c.h"
27 28
28 /* Direct3D renderer implementation */ 29 /* Direct3D renderer implementation */
29 30
30 #if 1 /* This takes more memory but you won't lose your texture data */ 31 #if 1 /* This takes more memory but you won't lose your texture data */
31 #define D3DPOOL_SDL D3DPOOL_MANAGED 32 #define D3DPOOL_SDL D3DPOOL_MANAGED
36 #endif 37 #endif
37 38
38 static SDL_Renderer *D3D_CreateRenderer(SDL_Window * window, Uint32 flags); 39 static SDL_Renderer *D3D_CreateRenderer(SDL_Window * window, Uint32 flags);
39 static int D3D_DisplayModeChanged(SDL_Renderer * renderer); 40 static int D3D_DisplayModeChanged(SDL_Renderer * renderer);
40 static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); 41 static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
42 static int D3D_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture, void **pixels, int *pitch);
41 static int D3D_SetTexturePalette(SDL_Renderer * renderer, 43 static int D3D_SetTexturePalette(SDL_Renderer * renderer,
42 SDL_Texture * texture, 44 SDL_Texture * texture,
43 const SDL_Color * colors, int firstcolor, 45 const SDL_Color * colors, int firstcolor,
44 int ncolors); 46 int ncolors);
45 static int D3D_GetTexturePalette(SDL_Renderer * renderer, 47 static int D3D_GetTexturePalette(SDL_Renderer * renderer,
94 0} 96 0}
95 }; 97 };
96 98
97 typedef struct 99 typedef struct
98 { 100 {
101 IDirect3D9 *d3d;
99 IDirect3DDevice9 *device; 102 IDirect3DDevice9 *device;
100 D3DPRESENT_PARAMETERS pparams; 103 D3DPRESENT_PARAMETERS pparams;
101 SDL_bool beginScene; 104 SDL_bool beginScene;
102 } D3D_RenderData; 105 } D3D_RenderData;
103 106
104 typedef struct 107 typedef struct
105 { 108 {
109 SDL_SW_YUVTexture *yuv;
110 Uint32 format;
106 IDirect3DTexture9 *texture; 111 IDirect3DTexture9 *texture;
107 } D3D_TextureData; 112 } D3D_TextureData;
108 113
109 typedef struct 114 typedef struct
110 { 115 {
224 default: 229 default:
225 return D3DFMT_UNKNOWN; 230 return D3DFMT_UNKNOWN;
226 } 231 }
227 } 232 }
228 233
234 static SDL_bool
235 D3D_IsTextureFormatAvailable(IDirect3D9 *d3d, Uint32 display_format, Uint32 texture_format)
236 {
237 HRESULT result;
238
239 result = IDirect3D9_CheckDeviceFormat(d3d,
240 D3DADAPTER_DEFAULT, /* FIXME */
241 D3DDEVTYPE_HAL,
242 PixelFormatToD3DFMT(display_format),
243 0,
244 D3DRTYPE_TEXTURE,
245 PixelFormatToD3DFMT(texture_format));
246 return FAILED(result) ? SDL_FALSE : SDL_TRUE;
247 }
248
249 static void
250 UpdateYUVTextureData(SDL_Texture * texture)
251 {
252 D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
253 SDL_Rect rect;
254 RECT d3drect;
255 D3DLOCKED_RECT locked;
256 HRESULT result;
257
258 d3drect.left = 0;
259 d3drect.right = texture->w;
260 d3drect.top = 0;
261 d3drect.bottom = texture->h;
262
263 result = IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect, 0);
264 if (FAILED(result)) {
265 return;
266 }
267
268 rect.x = 0;
269 rect.y = 0;
270 rect.w = texture->w;
271 rect.h = texture->h;
272 SDL_SW_CopyYUVToRGB(data->yuv, &rect, data->format, texture->w,
273 texture->h, locked.pBits, locked.Pitch);
274
275 IDirect3DTexture9_UnlockRect(data->texture, 0);
276 }
277
229 void 278 void
230 D3D_AddRenderDriver(_THIS) 279 D3D_AddRenderDriver(_THIS)
231 { 280 {
232 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 281 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
233 SDL_RendererInfo *info = &D3D_RenderDriver.info; 282 SDL_RendererInfo *info = &D3D_RenderDriver.info;
244 SDL_PIXELFORMAT_ARGB1555, 293 SDL_PIXELFORMAT_ARGB1555,
245 SDL_PIXELFORMAT_RGB565, 294 SDL_PIXELFORMAT_RGB565,
246 SDL_PIXELFORMAT_RGB888, 295 SDL_PIXELFORMAT_RGB888,
247 SDL_PIXELFORMAT_ARGB8888, 296 SDL_PIXELFORMAT_ARGB8888,
248 SDL_PIXELFORMAT_ARGB2101010, 297 SDL_PIXELFORMAT_ARGB2101010,
249 SDL_PIXELFORMAT_YUY2,
250 SDL_PIXELFORMAT_UYVY,
251 }; 298 };
252 HRESULT result;
253 299
254 for (i = 0; i < SDL_arraysize(formats); ++i) { 300 for (i = 0; i < SDL_arraysize(formats); ++i) {
255 result = IDirect3D9_CheckDeviceFormat(data->d3d, 301 if (D3D_IsTextureFormatAvailable(data->d3d, mode->format, formats[i])) {
256 D3DADAPTER_DEFAULT, /* FIXME */
257 D3DDEVTYPE_HAL,
258 PixelFormatToD3DFMT(mode->format),
259 0,
260 D3DRTYPE_TEXTURE,
261 PixelFormatToD3DFMT(formats[i]));
262 if (!FAILED(result)) {
263 info->texture_formats[info->num_texture_formats++] = formats[i]; 302 info->texture_formats[info->num_texture_formats++] = formats[i];
264 } 303 }
265 } 304 }
305 info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_YV12;
306 info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
307 info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_YUY2;
308 info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_UYVY;
309 info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_YVYU;
266 310
267 SDL_AddRenderDriver(0, &D3D_RenderDriver); 311 SDL_AddRenderDriver(0, &D3D_RenderDriver);
268 } 312 }
269 } 313 }
270 314
291 if (!data) { 335 if (!data) {
292 D3D_DestroyRenderer(renderer); 336 D3D_DestroyRenderer(renderer);
293 SDL_OutOfMemory(); 337 SDL_OutOfMemory();
294 return NULL; 338 return NULL;
295 } 339 }
340 data->d3d = videodata->d3d;
296 341
297 renderer->DisplayModeChanged = D3D_DisplayModeChanged; 342 renderer->DisplayModeChanged = D3D_DisplayModeChanged;
298 renderer->CreateTexture = D3D_CreateTexture; 343 renderer->CreateTexture = D3D_CreateTexture;
344 renderer->QueryTexturePixels = D3D_QueryTexturePixels;
299 renderer->SetTexturePalette = D3D_SetTexturePalette; 345 renderer->SetTexturePalette = D3D_SetTexturePalette;
300 renderer->GetTexturePalette = D3D_GetTexturePalette; 346 renderer->GetTexturePalette = D3D_GetTexturePalette;
301 renderer->SetTextureColorMod = D3D_SetTextureColorMod; 347 renderer->SetTextureColorMod = D3D_SetTextureColorMod;
302 renderer->SetTextureAlphaMod = D3D_SetTextureAlphaMod; 348 renderer->SetTextureAlphaMod = D3D_SetTextureAlphaMod;
303 renderer->SetTextureBlendMode = D3D_SetTextureBlendMode; 349 renderer->SetTextureBlendMode = D3D_SetTextureBlendMode;
487 D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) 533 D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
488 { 534 {
489 D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata; 535 D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
490 SDL_Window *window = SDL_GetWindowFromID(renderer->window); 536 SDL_Window *window = SDL_GetWindowFromID(renderer->window);
491 SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); 537 SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
538 Uint32 display_format = display->current_mode.format;
492 D3D_TextureData *data; 539 D3D_TextureData *data;
493 HRESULT result; 540 HRESULT result;
494 541
495 data = (D3D_TextureData *) SDL_calloc(1, sizeof(*data)); 542 data = (D3D_TextureData *) SDL_calloc(1, sizeof(*data));
496 if (!data) { 543 if (!data) {
498 return -1; 545 return -1;
499 } 546 }
500 547
501 texture->driverdata = data; 548 texture->driverdata = data;
502 549
550 if (SDL_ISPIXELFORMAT_FOURCC(texture->format) &&
551 (texture->format != SDL_PIXELFORMAT_YUY2 ||
552 !D3D_IsTextureFormatAvailable(renderdata->d3d, display_format, texture->format)) &&
553 (texture->format != SDL_PIXELFORMAT_YVYU ||
554 !D3D_IsTextureFormatAvailable(renderdata->d3d, display_format, texture->format))) {
555 data->yuv =
556 SDL_SW_CreateYUVTexture(texture->format, texture->w, texture->h);
557 if (!data->yuv) {
558 return -1;
559 }
560 data->format = display->current_mode.format;
561 } else {
562 data->format = texture->format;
563 }
564
503 result = 565 result =
504 IDirect3DDevice9_CreateTexture(renderdata->device, texture->w, 566 IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,
505 texture->h, 1, 0, 567 texture->h, 1, 0,
506 PixelFormatToD3DFMT(texture->format), 568 PixelFormatToD3DFMT(data->format),
507 D3DPOOL_SDL, &data->texture, NULL); 569 D3DPOOL_SDL, &data->texture, NULL);
508 if (FAILED(result)) { 570 if (FAILED(result)) {
509 D3D_SetError("CreateTexture()", result); 571 D3D_SetError("CreateTexture()", result);
510 return -1; 572 return -1;
511 } 573 }
512 574
513 return 0; 575 return 0;
576 }
577
578 static int
579 D3D_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
580 void **pixels, int *pitch)
581 {
582 D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
583
584 if (data->yuv) {
585 return SDL_SW_QueryYUVTexturePixels(data->yuv, pixels, pitch);
586 } else {
587 /* D3D textures don't have their pixels hanging out */
588 return -1;
589 }
514 } 590 }
515 591
516 static int 592 static int
517 D3D_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture, 593 D3D_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
518 const SDL_Color * colors, int firstcolor, int ncolors) 594 const SDL_Color * colors, int firstcolor, int ncolors)
576 return -1; 652 return -1;
577 } 653 }
578 return 0; 654 return 0;
579 } 655 }
580 656
581 #ifdef SDL_MEMORY_POOL_DEFAULT
582 static int 657 static int
583 D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, 658 D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
584 const SDL_Rect * rect, const void *pixels, int pitch) 659 const SDL_Rect * rect, const void *pixels, int pitch)
585 { 660 {
586 D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; 661 D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
587 D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata; 662 D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
588 IDirect3DTexture9 *temp; 663
589 RECT d3drect; 664 if (data->yuv) {
590 D3DLOCKED_RECT locked; 665 if (SDL_SW_UpdateYUVTexture(data->yuv, rect, pixels, pitch) < 0) {
591 const Uint8 *src; 666 return -1;
592 Uint8 *dst; 667 }
593 int row, length; 668 UpdateYUVTextureData(texture);
594 HRESULT result; 669 return 0;
595 670 } else {
596 result = 671 #ifdef SDL_MEMORY_POOL_DEFAULT
597 IDirect3DDevice9_CreateTexture(renderdata->device, texture->w, 672 IDirect3DTexture9 *temp;
598 texture->h, 1, 0, 673 RECT d3drect;
599 PixelFormatToD3DFMT(texture->format), 674 D3DLOCKED_RECT locked;
600 D3DPOOL_SYSTEMMEM, &temp, NULL); 675 const Uint8 *src;
601 if (FAILED(result)) { 676 Uint8 *dst;
602 D3D_SetError("CreateTexture()", result); 677 int row, length;
603 return -1; 678 HRESULT result;
604 } 679
605 680 result =
606 d3drect.left = rect->x; 681 IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,
607 d3drect.right = rect->x + rect->w; 682 texture->h, 1, 0,
608 d3drect.top = rect->y; 683 PixelFormatToD3DFMT(texture->format),
609 d3drect.bottom = rect->y + rect->h; 684 D3DPOOL_SYSTEMMEM, &temp, NULL);
610 685 if (FAILED(result)) {
611 result = IDirect3DTexture9_LockRect(temp, 0, &locked, &d3drect, 0); 686 D3D_SetError("CreateTexture()", result);
612 if (FAILED(result)) { 687 return -1;
688 }
689
690 d3drect.left = rect->x;
691 d3drect.right = rect->x + rect->w;
692 d3drect.top = rect->y;
693 d3drect.bottom = rect->y + rect->h;
694
695 result = IDirect3DTexture9_LockRect(temp, 0, &locked, &d3drect, 0);
696 if (FAILED(result)) {
697 IDirect3DTexture9_Release(temp);
698 D3D_SetError("LockRect()", result);
699 return -1;
700 }
701
702 src = pixels;
703 dst = locked.pBits;
704 length = rect->w * SDL_BYTESPERPIXEL(texture->format);
705 for (row = 0; row < rect->h; ++row) {
706 SDL_memcpy(dst, src, length);
707 src += pitch;
708 dst += locked.Pitch;
709 }
710 IDirect3DTexture9_UnlockRect(temp, 0);
711
712 result =
713 IDirect3DDevice9_UpdateTexture(renderdata->device,
714 (IDirect3DBaseTexture9 *) temp,
715 (IDirect3DBaseTexture9 *)
716 data->texture);
613 IDirect3DTexture9_Release(temp); 717 IDirect3DTexture9_Release(temp);
614 D3D_SetError("LockRect()", result); 718 if (FAILED(result)) {
615 return -1; 719 D3D_SetError("UpdateTexture()", result);
616 } 720 return -1;
617 721 }
618 src = pixels;
619 dst = locked.pBits;
620 length = rect->w * SDL_BYTESPERPIXEL(texture->format);
621 for (row = 0; row < rect->h; ++row) {
622 SDL_memcpy(dst, src, length);
623 src += pitch;
624 dst += locked.Pitch;
625 }
626 IDirect3DTexture9_UnlockRect(temp, 0);
627
628 result =
629 IDirect3DDevice9_UpdateTexture(renderdata->device,
630 (IDirect3DBaseTexture9 *) temp,
631 (IDirect3DBaseTexture9 *)
632 data->texture);
633 IDirect3DTexture9_Release(temp);
634 if (FAILED(result)) {
635 D3D_SetError("UpdateTexture()", result);
636 return -1;
637 }
638 return 0;
639 }
640 #else 722 #else
641 static int 723 RECT d3drect;
642 D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, 724 D3DLOCKED_RECT locked;
643 const SDL_Rect * rect, const void *pixels, int pitch) 725 const Uint8 *src;
644 { 726 Uint8 *dst;
645 D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; 727 int row, length;
646 D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata; 728 HRESULT result;
647 RECT d3drect; 729
648 D3DLOCKED_RECT locked; 730 d3drect.left = rect->x;
649 const Uint8 *src; 731 d3drect.right = rect->x + rect->w;
650 Uint8 *dst; 732 d3drect.top = rect->y;
651 int row, length; 733 d3drect.bottom = rect->y + rect->h;
652 HRESULT result; 734
653 735 result =
654 d3drect.left = rect->x; 736 IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect, 0);
655 d3drect.right = rect->x + rect->w; 737 if (FAILED(result)) {
656 d3drect.top = rect->y; 738 D3D_SetError("LockRect()", result);
657 d3drect.bottom = rect->y + rect->h; 739 return -1;
658 740 }
659 result = 741
660 IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect, 0); 742 src = pixels;
661 if (FAILED(result)) { 743 dst = locked.pBits;
662 D3D_SetError("LockRect()", result); 744 length = rect->w * SDL_BYTESPERPIXEL(texture->format);
663 return -1; 745 for (row = 0; row < rect->h; ++row) {
664 } 746 SDL_memcpy(dst, src, length);
665 747 src += pitch;
666 src = pixels; 748 dst += locked.Pitch;
667 dst = locked.pBits; 749 }
668 length = rect->w * SDL_BYTESPERPIXEL(texture->format); 750 IDirect3DTexture9_UnlockRect(data->texture, 0);
669 for (row = 0; row < rect->h; ++row) {
670 SDL_memcpy(dst, src, length);
671 src += pitch;
672 dst += locked.Pitch;
673 }
674 IDirect3DTexture9_UnlockRect(data->texture, 0);
675 return 0;
676 }
677 #endif // SDL_MEMORY_POOL_DEFAULT 751 #endif // SDL_MEMORY_POOL_DEFAULT
752
753 return 0;
754 }
755 }
678 756
679 static int 757 static int
680 D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, 758 D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
681 const SDL_Rect * rect, int markDirty, void **pixels, 759 const SDL_Rect * rect, int markDirty, void **pixels,
682 int *pitch) 760 int *pitch)
683 { 761 {
684 D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; 762 D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
685 RECT d3drect; 763
686 D3DLOCKED_RECT locked; 764 if (data->yuv) {
687 HRESULT result; 765 return SDL_SW_LockYUVTexture(data->yuv, rect, markDirty, pixels,
688 766 pitch);
689 d3drect.left = rect->x; 767 } else {
690 d3drect.right = rect->x + rect->w; 768 RECT d3drect;
691 d3drect.top = rect->y; 769 D3DLOCKED_RECT locked;
692 d3drect.bottom = rect->y + rect->h; 770 HRESULT result;
693 771
694 result = 772 d3drect.left = rect->x;
695 IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect, 773 d3drect.right = rect->x + rect->w;
696 markDirty ? 0 : D3DLOCK_NO_DIRTY_UPDATE); 774 d3drect.top = rect->y;
697 if (FAILED(result)) { 775 d3drect.bottom = rect->y + rect->h;
698 D3D_SetError("LockRect()", result); 776
699 return -1; 777 result =
700 } 778 IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect,
701 *pixels = locked.pBits; 779 markDirty ? 0 : D3DLOCK_NO_DIRTY_UPDATE);
702 *pitch = locked.Pitch; 780 if (FAILED(result)) {
703 return 0; 781 D3D_SetError("LockRect()", result);
782 return -1;
783 }
784 *pixels = locked.pBits;
785 *pitch = locked.Pitch;
786 return 0;
787 }
704 } 788 }
705 789
706 static void 790 static void
707 D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) 791 D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
708 { 792 {
709 D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; 793 D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
710 794
711 IDirect3DTexture9_UnlockRect(data->texture, 0); 795 if (data->yuv) {
796 SDL_SW_UnlockYUVTexture(data->yuv);
797 UpdateYUVTextureData(texture);
798 } else {
799 IDirect3DTexture9_UnlockRect(data->texture, 0);
800 }
712 } 801 }
713 802
714 static void 803 static void
715 D3D_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects, 804 D3D_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects,
716 const SDL_Rect * rects) 805 const SDL_Rect * rects)
1064 D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; 1153 D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
1065 1154
1066 if (!data) { 1155 if (!data) {
1067 return; 1156 return;
1068 } 1157 }
1158 if (data->yuv) {
1159 SDL_SW_DestroyYUVTexture(data->yuv);
1160 }
1069 if (data->texture) { 1161 if (data->texture) {
1070 IDirect3DTexture9_Release(data->texture); 1162 IDirect3DTexture9_Release(data->texture);
1071 } 1163 }
1072 SDL_free(data); 1164 SDL_free(data);
1073 texture->driverdata = NULL; 1165 texture->driverdata = NULL;