view src/win32/Direct3D.cpp @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children
line wrap: on
line source
1 #include "stdafx.h"
3 #define DIRECT3D_VERSION 0x0800
4 #include "d3d8.h"
5 #include "d3dx8.h"
7 #include "resource.h"
8 #include "MainWnd.h"
9 #include "Reg.h"
10 #include "VBA.h"
12 //#include "../common/System.h"
13 #include "../gba/GBAGlobals.h"
14 #include "../gb/gbGlobals.h"
15 #include "../common/Text.h"
16 #include "../version.h"
18 #ifdef MMX
19 extern "C" bool cpu_mmx;
21 extern bool detectMMX();
22 #endif
24 extern int Init_2xSaI(u32);
25 extern void directXMessage(const char *);
26 extern void winlog(const char *, ...);
28 typedef struct _D3DTLVERTEX
29 {
30 float sx; /* Screen coordinates */
31 float sy;
32 float sz;
33 float rhw; /* Reciprocal of homogeneous w */
34 D3DCOLOR color; /* Vertex color */
35 float tu; /* Texture coordinates */
36 float tv;
37 _D3DTLVERTEX() { }
38 _D3DTLVERTEX(const D3DVECTOR& v, float _rhw,
39 D3DCOLOR _color,
40 float _tu, float _tv)
41 {
42 sx = v.x; sy = v.y; sz = v.z; rhw = _rhw;
43 color = _color;
44 tu = _tu; tv = _tv;
45 }
46 } D3DTLVERTEX, *LPD3DTLVERTEX;
48 #define D3DFVF_TLVERTEX D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1
50 class Direct3DDisplay : public IDisplay
51 {
52 public:
53 Direct3DDisplay();
54 virtual ~Direct3DDisplay();
56 virtual bool initialize();
57 virtual void cleanup();
58 virtual void render();
59 virtual void checkFullScreen();
60 virtual void renderMenu();
61 virtual void clear();
62 virtual bool changeRenderSize(int w, int h);
63 virtual void resize(int w, int h);
64 virtual DISPLAY_TYPE getType() { return DIRECT_3D; };
65 virtual void setOption(const char *, int);
66 virtual int selectFullScreenMode(GUID * *);
68 private:
69 HINSTANCE d3dDLL;
70 LPDIRECT3D8 pD3D;
71 LPDIRECT3DDEVICE8 pDevice;
72 LPDIRECT3DTEXTURE8 pTexture;
73 D3DSURFACE_DESC dsdBackBuffer;
74 D3DPRESENT_PARAMETERS dpp;
75 D3DFORMAT screenFormat;
76 int width;
77 int height;
78 bool filterDisabled;
79 ID3DXFont *pFont;
80 bool failed;
81 unsigned int textureSize;
82 D3DTLVERTEX verts[4];
85 void restoreDeviceObjects();
86 void invalidateDeviceObjects();
87 bool initializeOffscreen(int w, int h);
88 void updateFiltering(int);
89 void calculateVertices();
90 };
92 Direct3DDisplay::Direct3DDisplay()
93 {
94 d3dDLL = NULL;
95 pD3D = NULL;
96 pDevice = NULL;
97 pTexture = NULL;
98 pFont = NULL;
99 screenFormat = D3DFMT_R5G6B5;
100 width = 0;
101 height = 0;
102 filterDisabled = false;
103 failed = false;
104 textureSize = 0;
105 }
107 Direct3DDisplay::~Direct3DDisplay()
108 {
109 cleanup();
110 }
112 void Direct3DDisplay::cleanup()
113 {
114 if (pD3D != NULL)
115 {
116 if (pFont)
117 {
118 pFont->Release();
119 pFont = NULL;
120 }
122 if (pTexture)
123 {
124 pTexture->Release();
125 pTexture = NULL;
126 }
128 if (pDevice)
129 {
130 pDevice->Release();
131 pDevice = NULL;
132 }
134 pD3D->Release();
135 pD3D = NULL;
137 if (d3dDLL != NULL)
138 {
139 FreeLibrary(d3dDLL);
140 d3dDLL = NULL;
141 }
142 }
143 }
145 bool Direct3DDisplay::initialize()
146 {
147 CWnd *pWnd = theApp.m_pMainWnd;
149 d3dDLL = LoadLibrary("D3D8.DLL");
150 LPDIRECT3D8 (WINAPI *D3DCreate)(UINT);
151 if (d3dDLL != NULL)
152 {
153 D3DCreate = (LPDIRECT3D8 (WINAPI *)(UINT))
154 GetProcAddress(d3dDLL, "Direct3DCreate8");
156 if (D3DCreate == NULL)
157 {
158 directXMessage("Direct3DCreate8");
159 return FALSE;
160 }
161 }
162 else
163 {
164 directXMessage("D3D8.DLL");
165 return FALSE;
166 }
168 pD3D = D3DCreate(120);
170 if (pD3D == NULL)
171 {
172 winlog("Error creating Direct3D object\n");
173 return FALSE;
174 }
176 theApp.mode320Available = false;
177 theApp.mode640Available = false;
178 theApp.mode800Available = false;
180 D3DDISPLAYMODE mode;
181 pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &mode);
183 switch (mode.Format)
184 {
185 case D3DFMT_R8G8B8:
186 systemColorDepth = 24;
187 systemRedShift = 19;
188 systemGreenShift = 11;
189 systemBlueShift = 3;
190 break;
191 case D3DFMT_X8R8G8B8:
192 systemColorDepth = 32;
193 systemRedShift = 19;
194 systemGreenShift = 11;
195 systemBlueShift = 3;
196 Init_2xSaI(32);
197 break;
198 case D3DFMT_R5G6B5:
199 systemColorDepth = 16;
200 systemRedShift = 11;
201 systemGreenShift = 6;
202 systemBlueShift = 0;
203 Init_2xSaI(565);
204 break;
205 case D3DFMT_X1R5G5B5:
206 systemColorDepth = 16;
207 systemRedShift = 10;
208 systemGreenShift = 5;
209 systemBlueShift = 0;
210 Init_2xSaI(555);
211 break;
212 default:
213 systemMessage(0, "Unsupport D3D format %d", mode.Format);
214 return false;
215 }
216 theApp.fsColorDepth = systemColorDepth;
218 #ifdef MMX
219 if (!theApp.disableMMX)
220 cpu_mmx = theApp.detectMMX();
221 else
222 cpu_mmx = 0;
223 #endif
225 screenFormat = mode.Format;
227 // check for available fullscreen modes
228 ZeroMemory(&dpp, sizeof(dpp));
229 dpp.Windowed = TRUE;
230 dpp.BackBufferFormat = mode.Format;
231 dpp.BackBufferCount = 1;
232 dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
233 dpp.BackBufferWidth = theApp.surfaceSizeX;
234 dpp.BackBufferHeight = theApp.surfaceSizeY;
236 HRESULT hret = pD3D->CreateDevice(D3DADAPTER_DEFAULT,
237 D3DDEVTYPE_HAL,
238 pWnd->GetSafeHwnd(),
239 D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE,
240 &dpp,
241 &pDevice);
242 if (!SUCCEEDED(hret))
243 {
244 winlog("Error creating Direct3DDevice %08x\n", hret);
245 return false;
246 }
248 restoreDeviceObjects();
250 switch (systemColorDepth)
251 {
252 case 16:
253 {
254 for (int i = 0; i < 0x10000; i++)
255 {
256 systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
257 (((i & 0x3e0) >> 5) << systemGreenShift) |
258 (((i & 0x7c00) >> 10) << systemBlueShift);
259 }
260 break;
261 }
262 case 24:
263 case 32:
264 {
265 for (int i = 0; i < 0x10000; i++)
266 {
267 systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
268 (((i & 0x3e0) >> 5) << systemGreenShift) |
269 (((i & 0x7c00) >> 10) << systemBlueShift);
270 }
271 break;
272 }
273 }
275 theApp.updateFilter();
276 theApp.updateIFB();
278 if (failed)
279 return false;
281 pWnd->DragAcceptFiles(TRUE);
283 return TRUE;
284 }
286 bool Direct3DDisplay::initializeOffscreen(int w, int h)
287 {
288 int size = 256;
289 if (w > 512 || h > 512)
290 size = 1024;
291 else if (w > 256 || h > 256)
292 size = 512;
293 textureSize = size;
295 UINT ww = size;
296 UINT hh = size;
297 D3DFORMAT format = screenFormat;
299 if (SUCCEEDED(D3DXCheckTextureRequirements(pDevice,
300 &ww,
301 &hh,
302 NULL,
303 0,
304 &format,
305 D3DPOOL_MANAGED)))
306 {
307 if ((int)ww < w || (int)hh < h)
308 {
309 if (theApp.filterFunction)
310 {
311 filterDisabled = true;
312 theApp.filterFunction = NULL;
313 systemMessage(0, "3D card cannot support needed texture size for filter function. Disabling it");
314 }
315 }
316 else
317 filterDisabled = false;
318 if (SUCCEEDED(D3DXCreateTexture(pDevice,
319 ww,
320 hh,
321 0,
322 0,
323 format,
324 D3DPOOL_MANAGED,
325 &pTexture)))
326 {
327 width = w;
328 height = h;
329 return true;
330 }
331 }
332 return false;
333 }
335 void Direct3DDisplay::updateFiltering(int filter)
336 {
337 switch (filter)
338 {
339 default:
340 case 0:
341 // point filtering
342 pDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_POINT);
343 pDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_POINT);
344 pDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTEXF_POINT);
345 break;
346 case 1:
347 // bilinear
348 pDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
349 pDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
350 pDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTEXF_POINT);
351 break;
352 }
353 }
355 void Direct3DDisplay::restoreDeviceObjects()
356 {
357 // Store render target surface desc
358 LPDIRECT3DSURFACE8 pBackBuffer;
359 HRESULT hr;
360 if (SUCCEEDED(hr = pDevice->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer)))
361 {
362 pBackBuffer->GetDesc(&dsdBackBuffer);
363 pBackBuffer->Release();
364 }
365 else
366 systemMessage(0, "Failed GetBackBuffer %08x", hr);
368 // Set up the texture
369 pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
370 pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
371 pDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
373 int filter = regQueryDwordValue("d3dFilter", 0);
374 if (filter < 0 || filter > 3)
375 filter = 0;
376 updateFiltering(filter);
378 // Set miscellaneous render states
379 pDevice->SetRenderState(D3DRS_DITHERENABLE, TRUE);
380 pDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
382 // Set the projection matrix
383 D3DXMATRIX matProj;
384 FLOAT fAspect = ((FLOAT)dsdBackBuffer.Width) / dsdBackBuffer.Height;
385 D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4, fAspect, 1.0f, 100.0f);
386 pDevice->SetTransform(D3DTS_PROJECTION, &matProj);
388 // turn off lighting
389 pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
391 if (pFont)
392 {
393 pFont->Release();
394 pFont = NULL;
395 }
396 // Create a D3D font using D3DX
397 HFONT hFont = CreateFont(14, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
398 ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
399 ANTIALIASED_QUALITY, FF_DONTCARE, "Arial");
400 D3DXCreateFont(pDevice, hFont, &pFont);
401 }
403 void Direct3DDisplay::clear()
404 {}
406 void Direct3DDisplay::renderMenu()
407 {
408 checkFullScreen();
409 if (theApp.m_pMainWnd)
410 theApp.m_pMainWnd->DrawMenuBar();
411 }
413 void Direct3DDisplay::checkFullScreen()
414 {
415 // if(tripleBuffering)
416 // pDirect3D->FlipToGDISurface();
417 }
419 void Direct3DDisplay::calculateVertices()
420 {
421 // color
422 D3DCOLOR col = 0xFFFFFFFF;
424 // calculate rhw
425 FLOAT z = 1.0f;
426 FLOAT rhw = 1.0f / (z * 990.0f + 10.0f);
428 // -0.5f is necessary in order to match texture alignment to display pixels
429 FLOAT left = -0.5f;
430 FLOAT right = dpp.BackBufferWidth - 0.5f;
431 FLOAT top = -0.5f;
432 FLOAT bottom = dpp.BackBufferHeight - 0.5f;
434 FLOAT textureX = (FLOAT)theApp.rect.right / (FLOAT)textureSize;
435 FLOAT textureY = (FLOAT)theApp.rect.bottom / (FLOAT)textureSize;
437 //#define D3D_DRAW_SINGLE_RECTANGLE
438 #ifdef D3D_DRAW_SINGLE_RECTANGLE
439 // set up a rectangle
440 verts[0] = D3DTLVERTEX(D3DXVECTOR3(left, top, z), rhw, col, 0.0f, 0.0f);
441 verts[1] = D3DTLVERTEX(D3DXVECTOR3(right, top, z), rhw, col, textureX, 0.0f);
442 verts[2] = D3DTLVERTEX(D3DXVECTOR3(right, bottom, z), rhw, col, textureX, textureY);
443 verts[3] = D3DTLVERTEX(D3DXVECTOR3(left, bottom, z), rhw, col, 0.0f, textureY);
444 #else
445 // set up triangles
446 verts[0] = D3DTLVERTEX(D3DXVECTOR3(left, bottom, z), rhw, col, 0.0f, textureY);
447 verts[1] = D3DTLVERTEX(D3DXVECTOR3(left, top, z), rhw, col, 0.0f, 0.0f);
448 verts[2] = D3DTLVERTEX(D3DXVECTOR3(right, bottom, z), rhw, col, textureX, textureY);
449 verts[3] = D3DTLVERTEX(D3DXVECTOR3(right, top, z), rhw, col, textureX, 0.0f);
450 #endif
451 }
453 void Direct3DDisplay::render()
454 {
455 if (!pDevice)
456 return;
458 // Test the cooperative level to see if it's okay to render
459 if (FAILED(pDevice->TestCooperativeLevel()))
460 {
461 return;
462 }
463 pDevice->Clear(0L, NULL, D3DCLEAR_TARGET, 0x000000ff, 1.0f, 0L);
465 if (SUCCEEDED(pDevice->BeginScene()))
466 {
467 D3DLOCKED_RECT locked;
468 if (pTexture && SUCCEEDED(pTexture->LockRect(0, &locked, NULL, 0)))
469 {
470 if (theApp.filterFunction)
471 {
472 if (systemColorDepth == 16)
473 theApp.filterFunction(pix + theApp.filterWidth * 2 + 4,
474 theApp.filterWidth*2 + 4,
475 (u8 *)theApp.delta,
476 (u8 *)locked.pBits,
477 locked.Pitch,
478 theApp.filterWidth,
479 theApp.filterHeight);
480 else
481 theApp.filterFunction(pix + theApp.filterWidth * 4 + 4,
482 theApp.filterWidth * 4 + 4,
483 (u8 *)theApp.delta,
484 (u8 *)locked.pBits,
485 locked.Pitch,
486 theApp.filterWidth,
487 theApp.filterHeight);
488 }
489 else
490 {
491 int copyX = 240;
492 int copyY = 160;
494 if (systemCartridgeType == 1)
495 {
496 if (gbBorderOn)
497 {
498 copyX = 256;
499 copyY = 224;
500 }
501 else
502 {
503 copyX = 160;
504 copyY = 144;
505 }
506 }
507 // MMX doesn't seem to be faster to copy the data
508 __asm {
509 mov eax, copyX;
510 mov ebx, copyY;
512 mov esi, pix;
513 mov edi, locked.pBits;
514 mov edx, locked.Pitch;
515 cmp systemColorDepth, 16;
516 jnz gbaOtherColor;
517 sub edx, eax;
518 sub edx, eax;
519 lea esi, [esi+2*eax+4];
520 shr eax, 1;
521 gbaLoop16bit:
522 mov ecx, eax;
523 repz movsd;
524 inc esi;
525 inc esi;
526 inc esi;
527 inc esi;
528 add edi, edx;
529 dec ebx;
530 jnz gbaLoop16bit;
531 jmp gbaLoopEnd;
532 gbaOtherColor:
533 cmp systemColorDepth, 32;
534 jnz gbaOtherColor2;
536 sub edx, eax;
537 sub edx, eax;
538 sub edx, eax;
539 sub edx, eax;
540 lea esi, [esi+4*eax+4];
541 gbaLoop32bit:
542 mov ecx, eax;
543 repz movsd;
544 add esi, 4;
545 add edi, edx;
546 dec ebx;
547 jnz gbaLoop32bit;
548 jmp gbaLoopEnd;
549 gbaOtherColor2:
550 lea eax, [eax+2*eax];
551 sub edx, eax;
552 gbaLoop24bit:
553 mov ecx, eax;
554 shr ecx, 2;
555 repz movsd;
556 add edi, edx;
557 dec ebx;
558 jnz gbaLoop24bit;
559 gbaLoopEnd:
560 }
561 }
563 if (theApp.videoOption > VIDEO_4X && theApp.showSpeed)
564 {
565 char buffer[30];
566 if (theApp.showSpeed == 1)
567 sprintf(buffer, "%3d%%", systemSpeed);
568 else
569 sprintf(buffer, "%3d%%(%d, %d fps)", systemSpeed,
570 systemFrameSkip,
571 theApp.showRenderedFrames);
572 if (theApp.showSpeedTransparent)
573 drawTextTransp((u8 *)locked.pBits,
574 locked.Pitch,
575 theApp.rect.left+10,
576 theApp.rect.bottom-10,
577 buffer);
578 else
579 drawText((u8 *)locked.pBits,
580 locked.Pitch,
581 theApp.rect.left+10,
582 theApp.rect.bottom-10,
583 buffer);
584 }
586 if (textMethod == 1)
587 {
588 DrawTextMessages((u8 *)locked.pBits, locked.Pitch, theApp.rect.left, theApp.rect.bottom);
589 }
591 pTexture->UnlockRect(0);
593 // set the texture
594 pDevice->SetTexture(0, pTexture);
596 // configure shader for vertex type
597 pDevice->SetVertexShader(D3DFVF_TLVERTEX);
599 #ifdef D3D_DRAW_SINGLE_RECTANGLE
600 // draw the rectangle
601 pDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts, sizeof(D3DTLVERTEX));
602 //#undef D3D_DRAW_RECT
603 #else
604 // draw the triangles
605 pDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, verts, sizeof(D3DTLVERTEX));
606 #endif
607 }
609 if (textMethod == 2)
610 {
611 for (int slot = 0; slot < SCREEN_MESSAGE_SLOTS; slot++)
612 {
613 if (theApp.screenMessage[slot])
614 {
615 if ((theApp.screenMessageDuration[slot] < 0 ||
616 (int)(GetTickCount() - theApp.screenMessageTime[slot]) < theApp.screenMessageDuration[slot]) &&
617 (!theApp.disableStatusMessage || slot == 1 || slot == 2) && pFont)
618 {
619 pFont->Begin();
620 RECT r;
621 D3DCOLOR color;
623 r.left = 10;
624 r.top = dpp.BackBufferHeight - 20*(slot+1);
625 r.right = dpp.BackBufferWidth - 10;
626 r.bottom = r.top + 20;
628 if (outlinedText)
629 {
630 color = textColor != 7 ? D3DCOLOR_ARGB(255, 0, 0, 0) : D3DCOLOR_ARGB(255, 255, 255, 255);
632 // draw outline
633 const static int xd [8] = {-1, 0, 1, 1, 1, 0, -1, -1};
634 const static int yd [8] = {-1, -1, -1, 0, 1, 1, 1, 0};
635 for (int i = 0; i < 8; i++)
636 {
637 RECT r2 = r;
638 r2.left += xd[i]; r2.right += xd[i];
639 r2.top += yd[i]; r2.bottom += yd[i];
641 pFont->DrawText(theApp.screenMessageBuffer[slot], -1, &r2, 0, color);
642 }
643 }
645 // draw center text
646 switch (textColor)
647 {
648 case 0:
649 color = D3DCOLOR_ARGB(255, 255, 255, 255); break;
650 case 1:
651 color = D3DCOLOR_ARGB(255, 255, 0, 0); break;
652 case 2:
653 color = D3DCOLOR_ARGB(255, 255, 255, 0); break;
654 case 3:
655 color = D3DCOLOR_ARGB(255, 0, 255, 0); break;
656 case 4:
657 color = D3DCOLOR_ARGB(255, 0, 255, 255); break;
658 case 5:
659 color = D3DCOLOR_ARGB(255, 0, 0, 255); break;
660 case 6:
661 color = D3DCOLOR_ARGB(255, 255, 0, 255); break;
662 case 7:
663 color = D3DCOLOR_ARGB(255, 0, 0, 0); break;
664 }
665 pFont->DrawText(theApp.screenMessageBuffer[slot], -1, &r, 0, color);
667 pFont->End();
668 }
669 else
670 {
671 theApp.screenMessage[slot] = false;
672 }
673 }
674 }
675 }
677 pDevice->EndScene();
679 pDevice->Present(NULL, NULL, NULL, NULL);
680 }
681 }
683 void Direct3DDisplay::invalidateDeviceObjects()
684 {
685 if (pFont)
686 pFont->Release();
687 pFont = NULL;
688 }
690 void Direct3DDisplay::resize(int w, int h)
691 {
692 if (pDevice && w > 0 && h > 0)
693 {
694 dpp.BackBufferWidth = w;
695 dpp.BackBufferHeight = h;
696 HRESULT hr;
697 invalidateDeviceObjects();
698 if (SUCCEEDED(hr = pDevice->Reset(&dpp)))
699 {
700 restoreDeviceObjects();
701 }
702 else
703 systemMessage(0, "Failed device reset %08x", hr);
704 }
705 calculateVertices();
706 }
708 bool Direct3DDisplay::changeRenderSize(int w, int h)
709 {
710 if (w != width || h != height)
711 {
712 if (pTexture)
713 {
714 pTexture->Release();
715 pTexture = NULL;
716 }
717 if (!initializeOffscreen(w, h))
718 {
719 failed = true;
720 return false;
721 }
722 }
723 calculateVertices();
725 return true;
726 }
728 void Direct3DDisplay::setOption(const char *option, int value)
729 {
730 if (!strcmp(option, "d3dFilter"))
731 updateFiltering(value);
732 }
734 int Direct3DDisplay::selectFullScreenMode(GUID * *)
735 {
736 HWND wnd = GetDesktopWindow();
737 RECT r;
738 GetWindowRect(wnd, &r);
739 int w = (r.right - r.left) & 4095;
740 int h = (r.bottom - r.top) & 4095;
741 HDC dc = GetDC(wnd);
742 int c = GetDeviceCaps(dc, BITSPIXEL);
743 ReleaseDC(wnd, dc);
745 return (c << 24) | (w << 12) | h;
746 }
748 IDisplay *newDirect3DDisplay()
749 {
750 return new Direct3DDisplay();
751 }