blob: 50932ca3a9736ae76f31db586993baf8483f6e76 [file] [log] [blame]
John Bauman89401822014-05-06 15:04:28 -04001// SwiftShader Software Renderer
2//
John Bauman19bac1e2014-05-06 15:23:49 -04003// Copyright(c) 2005-2012 TransGaming Inc.
John Bauman89401822014-05-06 15:04:28 -04004//
5// All rights reserved. No part of this software may be copied, distributed, transmitted,
6// transcribed, stored in a retrieval system, translated into any human or computer
7// language by any means, or disclosed to third parties without the explicit written
8// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
9// or implied, including but not limited to any patent rights, are granted to you.
10//
11
12#include "FrameBufferDD.hpp"
13
14#include "Debug.hpp"
15
16namespace sw
17{
18 extern bool forceWindowed;
19
20 GUID secondaryDisplay = {0};
21
22 int __stdcall enumDisplayCallback(GUID* guid, char *driverDescription, char *driverName, void *context, HMONITOR monitor)
23 {
24 if(strcmp(driverName, "\\\\.\\DISPLAY2") == 0)
25 {
26 secondaryDisplay = *guid;
27 }
28
29 return 1;
30 }
31
John Bauman66b8ab22014-05-06 15:57:45 -040032 FrameBufferDD::FrameBufferDD(HWND windowHandle, int width, int height, bool fullscreen, bool topLeftOrigin) : FrameBufferWin(windowHandle, width, height, fullscreen, topLeftOrigin)
John Bauman89401822014-05-06 15:04:28 -040033 {
34 directDraw = 0;
35 frontBuffer = 0;
36 backBuffer = 0;
37
38 locked = 0;
39
40 ddraw = LoadLibrary("ddraw.dll");
41 DirectDrawCreate = (DIRECTDRAWCREATE)GetProcAddress(ddraw, "DirectDrawCreate");
42 DirectDrawEnumerateExA = (DIRECTDRAWENUMERATEEXA)GetProcAddress(ddraw, "DirectDrawEnumerateExA");
43
44 if(!windowed)
45 {
46 initFullscreen();
47 }
48 else
49 {
50 initWindowed();
51 }
52 }
53
54 FrameBufferDD::~FrameBufferDD()
55 {
56 releaseAll();
57
58 FreeLibrary(ddraw);
59 }
60
61 void FrameBufferDD::createSurfaces()
62 {
63 if(backBuffer)
64 {
65 backBuffer->Release();
66 backBuffer = 0;
67 }
68
69 if(frontBuffer)
70 {
71 frontBuffer->Release();
72 frontBuffer = 0;
73 }
74
75 if(!windowed)
76 {
77 DDSURFACEDESC surfaceDescription = {0};
78 surfaceDescription.dwSize = sizeof(surfaceDescription);
79 surfaceDescription.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
80 surfaceDescription.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
81 surfaceDescription.dwBackBufferCount = 1;
82 long result = directDraw->CreateSurface(&surfaceDescription, &frontBuffer, 0);
83
84 if(frontBuffer)
85 {
86 DDSCAPS surfaceCapabilties = {0};
87 surfaceCapabilties.dwCaps = DDSCAPS_BACKBUFFER;
88 frontBuffer->GetAttachedSurface(&surfaceCapabilties, &backBuffer);
89 backBuffer->AddRef();
90 }
91 }
92 else
93 {
94 IDirectDrawClipper *clipper;
95
96 DDSURFACEDESC ddsd = {0};
97 ddsd.dwSize = sizeof(ddsd);
98 ddsd.dwFlags = DDSD_CAPS;
99 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
100
101 long result = directDraw->CreateSurface(&ddsd, &frontBuffer, 0);
102 directDraw->GetDisplayMode(&ddsd);
103 bitDepth = ddsd.ddpfPixelFormat.dwRGBBitCount;
104
105 if((result != DD_OK && result != DDERR_PRIMARYSURFACEALREADYEXISTS) || (bitDepth != 32 && bitDepth != 24 && bitDepth != 16))
106 {
John Bauman19bac1e2014-05-06 15:23:49 -0400107 assert(!"Failed to initialize graphics: Incompatible display mode.");
John Bauman89401822014-05-06 15:04:28 -0400108 }
John Bauman19bac1e2014-05-06 15:23:49 -0400109 else
110 {
111 ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
112 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
113 ddsd.dwWidth = width;
114 ddsd.dwHeight = height;
John Bauman89401822014-05-06 15:04:28 -0400115
John Bauman19bac1e2014-05-06 15:23:49 -0400116 directDraw->CreateSurface(&ddsd, &backBuffer, 0);
John Bauman89401822014-05-06 15:04:28 -0400117
John Bauman19bac1e2014-05-06 15:23:49 -0400118 directDraw->CreateClipper(0, &clipper, 0);
119 clipper->SetHWnd(0, windowHandle);
120 frontBuffer->SetClipper(clipper);
121 clipper->Release();
122 }
John Bauman89401822014-05-06 15:04:28 -0400123 }
124 }
125
126 bool FrameBufferDD::readySurfaces()
127 {
128 if(!frontBuffer || !backBuffer)
129 {
130 createSurfaces();
131 }
132
133 if(frontBuffer && backBuffer)
134 {
135 if(frontBuffer->IsLost() || backBuffer->IsLost())
136 {
137 restoreSurfaces();
138 }
139
140 if(frontBuffer && backBuffer)
141 {
142 if(!frontBuffer->IsLost() && !backBuffer->IsLost())
143 {
144 return true;
145 }
146 }
147 }
148
149 return false;
150 }
151
152 void FrameBufferDD::updateClipper(HWND windowOverride)
153 {
154 if(windowed)
155 {
156 if(frontBuffer)
157 {
158 HWND window = windowOverride ? windowOverride : windowHandle;
159
160 IDirectDrawClipper *clipper;
161 frontBuffer->GetClipper(&clipper);
162 clipper->SetHWnd(0, window);
163 clipper->Release();
164 }
165 }
166 }
167
168 void FrameBufferDD::restoreSurfaces()
169 {
170 long result1 = frontBuffer->Restore();
171 long result2 = backBuffer->Restore();
172
173 if(result1 != DD_OK || result2 != DD_OK) // Surfaces could not be restored; recreate them
174 {
175 createSurfaces();
176 }
177 }
178
179 void FrameBufferDD::initFullscreen()
180 {
181 releaseAll();
182
183 if(true) // Render to primary display
184 {
185 DirectDrawCreate(0, &directDraw, 0);
186 }
187 else // Render to secondary display
188 {
189 DirectDrawEnumerateEx(&enumDisplayCallback, 0, DDENUM_ATTACHEDSECONDARYDEVICES);
190 DirectDrawCreate(&secondaryDisplay, &directDraw, 0);
191 }
192
193 directDraw->SetCooperativeLevel(windowHandle, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
194
195 long result;
196
197 do
198 {
199 bitDepth = 32;
200 result = directDraw->SetDisplayMode(width, height, bitDepth);
201
202 if(result == DDERR_INVALIDMODE)
203 {
204 bitDepth = 16;
205 result = directDraw->SetDisplayMode(width, height, bitDepth);
206
207 if(result == DDERR_INVALIDMODE)
208 {
209 bitDepth = 24;
210 result = directDraw->SetDisplayMode(width, height, bitDepth);
211
212 if(result == DDERR_INVALIDMODE)
213 {
John Bauman19bac1e2014-05-06 15:23:49 -0400214 assert(!"Failed to initialize graphics: Display mode not supported.");
John Bauman89401822014-05-06 15:04:28 -0400215 }
216 }
217 }
218
219 if(result != DD_OK)
220 {
221 Sleep(1);
222 }
223 }
224 while(result != DD_OK);
225
226 createSurfaces();
227
228 updateBounds(windowHandle);
229 }
230
231 void FrameBufferDD::initWindowed()
232 {
233 releaseAll();
234
235 DirectDrawCreate(0, &directDraw, 0);
236 directDraw->SetCooperativeLevel(windowHandle, DDSCL_NORMAL);
237
238 createSurfaces();
239
240 updateBounds(windowHandle);
241 }
242
John Bauman66b8ab22014-05-06 15:57:45 -0400243 void FrameBufferDD::flip(void *source, bool HDR)
John Bauman89401822014-05-06 15:04:28 -0400244 {
John Bauman66b8ab22014-05-06 15:57:45 -0400245 copy(source, HDR);
John Bauman89401822014-05-06 15:04:28 -0400246
247 if(!readySurfaces())
248 {
249 return;
250 }
251
252 while(true)
253 {
254 long result;
255
256 if(windowed)
257 {
258 result = frontBuffer->Blt(&bounds, backBuffer, 0, DDBLT_WAIT, 0);
259 }
260 else
261 {
262 result = frontBuffer->Flip(0, DDFLIP_NOVSYNC);
263 }
264
265 if(result != DDERR_WASSTILLDRAWING)
266 {
267 break;
268 }
269
270 Sleep(0);
271 }
272 }
273
John Bauman66b8ab22014-05-06 15:57:45 -0400274 void FrameBufferDD::blit(void *source, const Rect *sourceRect, const Rect *destRect, bool HDR)
John Bauman89401822014-05-06 15:04:28 -0400275 {
John Bauman66b8ab22014-05-06 15:57:45 -0400276 copy(source, HDR);
John Bauman89401822014-05-06 15:04:28 -0400277
278 if(!readySurfaces())
279 {
280 return;
281 }
282
283 RECT dRect;
284
285 if(destRect)
286 {
John Bauman19bac1e2014-05-06 15:23:49 -0400287 dRect.bottom = bounds.top + destRect->y1;
288 dRect.left = bounds.left + destRect->x0;
289 dRect.right = bounds.left + destRect->x1;
290 dRect.top = bounds.top + destRect->y0;
John Bauman89401822014-05-06 15:04:28 -0400291 }
292 else
293 {
294 dRect.bottom = bounds.top + height;
295 dRect.left = bounds.left + 0;
296 dRect.right = bounds.left + width;
297 dRect.top = bounds.top + 0;
298 }
299
300 while(true)
301 {
302 long result = frontBuffer->Blt(&dRect, backBuffer, (LPRECT)sourceRect, DDBLT_WAIT, 0);
303
304 if(result != DDERR_WASSTILLDRAWING)
305 {
306 break;
307 }
308
309 Sleep(0);
310 }
311 }
312
John Bauman66b8ab22014-05-06 15:57:45 -0400313 void FrameBufferDD::flip(HWND windowOverride, void *source, bool HDR)
314 {
315 updateClipper(windowOverride);
316 updateBounds(windowOverride);
317
318 flip(source, HDR);
319 }
320
321 void FrameBufferDD::blit(HWND windowOverride, void *source, const Rect *sourceRect, const Rect *destRect, bool HDR)
322 {
323 updateClipper(windowOverride);
324 updateBounds(windowOverride);
325
326 blit(source, sourceRect, destRect, HDR);
327 }
328
John Bauman89401822014-05-06 15:04:28 -0400329 void FrameBufferDD::screenshot(void *destBuffer)
330 {
331 if(!readySurfaces())
332 {
333 return;
334 }
335
336 DDSURFACEDESC DDSD;
337 DDSD.dwSize = sizeof(DDSD);
338
339 long result = frontBuffer->Lock(0, &DDSD, DDLOCK_WAIT, 0);
340
341 if(result == DD_OK)
342 {
343 int width = DDSD.dwWidth;
344 int height = DDSD.dwHeight;
345 int bitDepth = DDSD.ddpfPixelFormat.dwRGBBitCount;
346 int stride = DDSD.lPitch;
347
348 void *sourceBuffer = DDSD.lpSurface;
349
350 for(int y = 0; y < height; y++)
351 {
352 memcpy(destBuffer, sourceBuffer, width * 4); // FIXME: Assumes 32-bit buffer
353
354 (char*&)sourceBuffer += stride;
355 (char*&)destBuffer += 4 * width;
356 }
357
358 frontBuffer->Unlock(0);
359 }
360 }
361
362 void FrameBufferDD::setGammaRamp(GammaRamp *gammaRamp, bool calibrate)
363 {
364 IDirectDrawGammaControl *gammaControl = 0;
365
366 if(frontBuffer)
367 {
368 frontBuffer->QueryInterface(IID_IDirectDrawGammaControl, (void**)&gammaControl);
369
370 if(gammaControl)
371 {
372 gammaControl->SetGammaRamp(calibrate ? DDSGR_CALIBRATE : 0, (DDGAMMARAMP*)gammaRamp);
373
374 gammaControl->Release();
375 }
376 }
377 }
378
379 void FrameBufferDD::getGammaRamp(GammaRamp *gammaRamp)
380 {
381 IDirectDrawGammaControl *gammaControl = 0;
382
383 if(frontBuffer)
384 {
385 frontBuffer->QueryInterface(IID_IDirectDrawGammaControl, (void**)&gammaControl);
386
387 if(gammaControl)
388 {
389 gammaControl->GetGammaRamp(0, (DDGAMMARAMP*)gammaRamp);
390
391 gammaControl->Release();
392 }
393 }
394 }
395
396 void *FrameBufferDD::lock()
397 {
398 if(locked)
399 {
400 return locked;
401 }
402
403 if(!readySurfaces())
404 {
405 return 0;
406 }
407
408 DDSURFACEDESC DDSD;
409 DDSD.dwSize = sizeof(DDSD);
410
411 long result = backBuffer->Lock(0, &DDSD, DDLOCK_WAIT, 0);
412
413 if(result == DD_OK)
414 {
415 width = DDSD.dwWidth;
416 height = DDSD.dwHeight;
417 int bitDepth = DDSD.ddpfPixelFormat.dwRGBBitCount;
418 stride = DDSD.lPitch;
419
420 locked = DDSD.lpSurface;
421
422 return locked;
423 }
424
425 return 0;
426 }
427
428 void FrameBufferDD::unlock()
429 {
430 if(!locked || !backBuffer) return;
431
432 backBuffer->Unlock(0);
433
434 locked = 0;
435 }
436
437 void FrameBufferDD::drawText(int x, int y, const char *string, ...)
438 {
439 char buffer[256];
440 va_list arglist;
441
442 va_start(arglist, string);
443 vsprintf(buffer, string, arglist);
444 va_end(arglist);
445
446 HDC hdc;
447
448 backBuffer->GetDC(&hdc);
449
450 SetBkColor(hdc, RGB(0, 0, 255));
451 SetTextColor(hdc, RGB(255, 255, 255));
452
453 TextOut(hdc, x, y, buffer, lstrlen(buffer));
454
455 backBuffer->ReleaseDC(hdc);
456 }
457
458 bool FrameBufferDD::getScanline(bool &inVerticalBlank, unsigned int &scanline)
459 {
460 HRESULT result = directDraw->GetScanLine((unsigned long*)&scanline);
461
462 if(result == DD_OK)
463 {
464 inVerticalBlank = false;
465 }
466 else if(result == DDERR_VERTICALBLANKINPROGRESS)
467 {
468 inVerticalBlank = true;
469 }
470 else if(result == DDERR_UNSUPPORTED)
471 {
472 return false;
473 }
474 else ASSERT(false);
475
476 return true;
477 }
478
479 void FrameBufferDD::releaseAll()
480 {
481 unlock();
482
483 if(backBuffer)
484 {
485 backBuffer->Release();
486 backBuffer = 0;
487 }
488
489 if(frontBuffer)
490 {
491 frontBuffer->Release();
492 frontBuffer = 0;
493 }
494
495 if(directDraw)
496 {
497 directDraw->SetCooperativeLevel(0, DDSCL_NORMAL);
498 directDraw->Release();
499 directDraw = 0;
500 }
501 }
502}