blob: 81b2ef2d6d7bee2d495a5c049522514b4adf3701 [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);
Nicolas Capens10219e72014-05-07 00:17:20 -0400103
104 switch(ddsd.ddpfPixelFormat.dwRGBBitCount)
105 {
106 case 32: destFormat = FORMAT_X8R8G8B8; break;
107 case 24: destFormat = FORMAT_R8G8B8; break;
108 case 16: destFormat = FORMAT_R5G6B5; break;
109 default: destFormat = FORMAT_NULL; break;
110 }
John Bauman89401822014-05-06 15:04:28 -0400111
Nicolas Capens10219e72014-05-07 00:17:20 -0400112 if((result != DD_OK && result != DDERR_PRIMARYSURFACEALREADYEXISTS) || (destFormat == FORMAT_NULL))
John Bauman89401822014-05-06 15:04:28 -0400113 {
John Bauman19bac1e2014-05-06 15:23:49 -0400114 assert(!"Failed to initialize graphics: Incompatible display mode.");
John Bauman89401822014-05-06 15:04:28 -0400115 }
John Bauman19bac1e2014-05-06 15:23:49 -0400116 else
117 {
118 ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
119 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
120 ddsd.dwWidth = width;
121 ddsd.dwHeight = height;
John Bauman89401822014-05-06 15:04:28 -0400122
John Bauman19bac1e2014-05-06 15:23:49 -0400123 directDraw->CreateSurface(&ddsd, &backBuffer, 0);
John Bauman89401822014-05-06 15:04:28 -0400124
John Bauman19bac1e2014-05-06 15:23:49 -0400125 directDraw->CreateClipper(0, &clipper, 0);
126 clipper->SetHWnd(0, windowHandle);
127 frontBuffer->SetClipper(clipper);
128 clipper->Release();
129 }
John Bauman89401822014-05-06 15:04:28 -0400130 }
131 }
132
133 bool FrameBufferDD::readySurfaces()
134 {
135 if(!frontBuffer || !backBuffer)
136 {
137 createSurfaces();
138 }
139
140 if(frontBuffer && backBuffer)
141 {
142 if(frontBuffer->IsLost() || backBuffer->IsLost())
143 {
144 restoreSurfaces();
145 }
146
147 if(frontBuffer && backBuffer)
148 {
149 if(!frontBuffer->IsLost() && !backBuffer->IsLost())
150 {
151 return true;
152 }
153 }
154 }
155
156 return false;
157 }
158
159 void FrameBufferDD::updateClipper(HWND windowOverride)
160 {
161 if(windowed)
162 {
163 if(frontBuffer)
164 {
165 HWND window = windowOverride ? windowOverride : windowHandle;
166
167 IDirectDrawClipper *clipper;
168 frontBuffer->GetClipper(&clipper);
169 clipper->SetHWnd(0, window);
170 clipper->Release();
171 }
172 }
173 }
174
175 void FrameBufferDD::restoreSurfaces()
176 {
177 long result1 = frontBuffer->Restore();
178 long result2 = backBuffer->Restore();
179
180 if(result1 != DD_OK || result2 != DD_OK) // Surfaces could not be restored; recreate them
181 {
182 createSurfaces();
183 }
184 }
185
186 void FrameBufferDD::initFullscreen()
187 {
188 releaseAll();
189
190 if(true) // Render to primary display
191 {
192 DirectDrawCreate(0, &directDraw, 0);
193 }
194 else // Render to secondary display
195 {
196 DirectDrawEnumerateEx(&enumDisplayCallback, 0, DDENUM_ATTACHEDSECONDARYDEVICES);
197 DirectDrawCreate(&secondaryDisplay, &directDraw, 0);
198 }
199
200 directDraw->SetCooperativeLevel(windowHandle, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
201
202 long result;
203
204 do
205 {
Nicolas Capens10219e72014-05-07 00:17:20 -0400206 destFormat = FORMAT_X8R8G8B8;
207 result = directDraw->SetDisplayMode(width, height, 32);
John Bauman89401822014-05-06 15:04:28 -0400208
209 if(result == DDERR_INVALIDMODE)
210 {
Nicolas Capens10219e72014-05-07 00:17:20 -0400211 destFormat = FORMAT_R8G8B8;
212 result = directDraw->SetDisplayMode(width, height, 24);
John Bauman89401822014-05-06 15:04:28 -0400213
214 if(result == DDERR_INVALIDMODE)
215 {
Nicolas Capens10219e72014-05-07 00:17:20 -0400216 destFormat = FORMAT_R5G6B5;
217 result = directDraw->SetDisplayMode(width, height, 16);
John Bauman89401822014-05-06 15:04:28 -0400218
219 if(result == DDERR_INVALIDMODE)
220 {
John Bauman19bac1e2014-05-06 15:23:49 -0400221 assert(!"Failed to initialize graphics: Display mode not supported.");
John Bauman89401822014-05-06 15:04:28 -0400222 }
223 }
224 }
225
226 if(result != DD_OK)
227 {
228 Sleep(1);
229 }
230 }
231 while(result != DD_OK);
232
233 createSurfaces();
234
235 updateBounds(windowHandle);
236 }
237
238 void FrameBufferDD::initWindowed()
239 {
240 releaseAll();
241
242 DirectDrawCreate(0, &directDraw, 0);
243 directDraw->SetCooperativeLevel(windowHandle, DDSCL_NORMAL);
244
245 createSurfaces();
246
247 updateBounds(windowHandle);
248 }
249
Nicolas Capens22bc79c2015-11-30 13:24:24 -0500250 void FrameBufferDD::flip(void *source, Format sourceFormat, size_t sourceStride)
John Bauman89401822014-05-06 15:04:28 -0400251 {
Nicolas Capens22bc79c2015-11-30 13:24:24 -0500252 copy(source, sourceFormat, sourceStride);
John Bauman89401822014-05-06 15:04:28 -0400253
254 if(!readySurfaces())
255 {
256 return;
257 }
258
259 while(true)
260 {
261 long result;
262
263 if(windowed)
264 {
265 result = frontBuffer->Blt(&bounds, backBuffer, 0, DDBLT_WAIT, 0);
266 }
267 else
268 {
269 result = frontBuffer->Flip(0, DDFLIP_NOVSYNC);
270 }
271
272 if(result != DDERR_WASSTILLDRAWING)
273 {
274 break;
275 }
276
277 Sleep(0);
278 }
279 }
280
Nicolas Capens22bc79c2015-11-30 13:24:24 -0500281 void FrameBufferDD::blit(void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride)
John Bauman89401822014-05-06 15:04:28 -0400282 {
Nicolas Capens22bc79c2015-11-30 13:24:24 -0500283 copy(source, sourceFormat, sourceStride);
John Bauman89401822014-05-06 15:04:28 -0400284
285 if(!readySurfaces())
286 {
287 return;
288 }
289
290 RECT dRect;
291
292 if(destRect)
293 {
John Bauman19bac1e2014-05-06 15:23:49 -0400294 dRect.bottom = bounds.top + destRect->y1;
295 dRect.left = bounds.left + destRect->x0;
296 dRect.right = bounds.left + destRect->x1;
297 dRect.top = bounds.top + destRect->y0;
John Bauman89401822014-05-06 15:04:28 -0400298 }
299 else
300 {
301 dRect.bottom = bounds.top + height;
302 dRect.left = bounds.left + 0;
303 dRect.right = bounds.left + width;
304 dRect.top = bounds.top + 0;
305 }
306
307 while(true)
308 {
309 long result = frontBuffer->Blt(&dRect, backBuffer, (LPRECT)sourceRect, DDBLT_WAIT, 0);
310
311 if(result != DDERR_WASSTILLDRAWING)
312 {
313 break;
314 }
315
316 Sleep(0);
317 }
318 }
319
Nicolas Capens22bc79c2015-11-30 13:24:24 -0500320 void FrameBufferDD::flip(HWND windowOverride, void *source, Format sourceFormat, size_t sourceStride)
John Bauman66b8ab22014-05-06 15:57:45 -0400321 {
322 updateClipper(windowOverride);
323 updateBounds(windowOverride);
324
Nicolas Capens22bc79c2015-11-30 13:24:24 -0500325 flip(source, sourceFormat, sourceStride);
John Bauman66b8ab22014-05-06 15:57:45 -0400326 }
327
Nicolas Capens22bc79c2015-11-30 13:24:24 -0500328 void FrameBufferDD::blit(HWND windowOverride, void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride)
John Bauman66b8ab22014-05-06 15:57:45 -0400329 {
330 updateClipper(windowOverride);
331 updateBounds(windowOverride);
332
Nicolas Capens22bc79c2015-11-30 13:24:24 -0500333 blit(source, sourceRect, destRect, sourceFormat, sourceStride);
John Bauman66b8ab22014-05-06 15:57:45 -0400334 }
335
John Bauman89401822014-05-06 15:04:28 -0400336 void FrameBufferDD::screenshot(void *destBuffer)
337 {
338 if(!readySurfaces())
339 {
340 return;
341 }
342
343 DDSURFACEDESC DDSD;
344 DDSD.dwSize = sizeof(DDSD);
345
346 long result = frontBuffer->Lock(0, &DDSD, DDLOCK_WAIT, 0);
347
348 if(result == DD_OK)
349 {
350 int width = DDSD.dwWidth;
351 int height = DDSD.dwHeight;
352 int bitDepth = DDSD.ddpfPixelFormat.dwRGBBitCount;
353 int stride = DDSD.lPitch;
354
355 void *sourceBuffer = DDSD.lpSurface;
356
357 for(int y = 0; y < height; y++)
358 {
359 memcpy(destBuffer, sourceBuffer, width * 4); // FIXME: Assumes 32-bit buffer
360
361 (char*&)sourceBuffer += stride;
362 (char*&)destBuffer += 4 * width;
363 }
364
365 frontBuffer->Unlock(0);
366 }
367 }
368
369 void FrameBufferDD::setGammaRamp(GammaRamp *gammaRamp, bool calibrate)
370 {
371 IDirectDrawGammaControl *gammaControl = 0;
372
373 if(frontBuffer)
374 {
375 frontBuffer->QueryInterface(IID_IDirectDrawGammaControl, (void**)&gammaControl);
376
377 if(gammaControl)
378 {
379 gammaControl->SetGammaRamp(calibrate ? DDSGR_CALIBRATE : 0, (DDGAMMARAMP*)gammaRamp);
380
381 gammaControl->Release();
382 }
383 }
384 }
385
386 void FrameBufferDD::getGammaRamp(GammaRamp *gammaRamp)
387 {
388 IDirectDrawGammaControl *gammaControl = 0;
389
390 if(frontBuffer)
391 {
392 frontBuffer->QueryInterface(IID_IDirectDrawGammaControl, (void**)&gammaControl);
393
394 if(gammaControl)
395 {
396 gammaControl->GetGammaRamp(0, (DDGAMMARAMP*)gammaRamp);
397
398 gammaControl->Release();
399 }
400 }
401 }
402
403 void *FrameBufferDD::lock()
404 {
405 if(locked)
406 {
407 return locked;
408 }
409
410 if(!readySurfaces())
411 {
412 return 0;
413 }
414
415 DDSURFACEDESC DDSD;
416 DDSD.dwSize = sizeof(DDSD);
417
418 long result = backBuffer->Lock(0, &DDSD, DDLOCK_WAIT, 0);
419
420 if(result == DD_OK)
421 {
422 width = DDSD.dwWidth;
423 height = DDSD.dwHeight;
424 int bitDepth = DDSD.ddpfPixelFormat.dwRGBBitCount;
425 stride = DDSD.lPitch;
426
427 locked = DDSD.lpSurface;
428
429 return locked;
430 }
431
432 return 0;
433 }
434
435 void FrameBufferDD::unlock()
436 {
437 if(!locked || !backBuffer) return;
438
439 backBuffer->Unlock(0);
440
441 locked = 0;
442 }
443
444 void FrameBufferDD::drawText(int x, int y, const char *string, ...)
445 {
446 char buffer[256];
447 va_list arglist;
448
449 va_start(arglist, string);
450 vsprintf(buffer, string, arglist);
451 va_end(arglist);
452
453 HDC hdc;
454
455 backBuffer->GetDC(&hdc);
456
457 SetBkColor(hdc, RGB(0, 0, 255));
458 SetTextColor(hdc, RGB(255, 255, 255));
459
460 TextOut(hdc, x, y, buffer, lstrlen(buffer));
461
462 backBuffer->ReleaseDC(hdc);
463 }
464
465 bool FrameBufferDD::getScanline(bool &inVerticalBlank, unsigned int &scanline)
466 {
467 HRESULT result = directDraw->GetScanLine((unsigned long*)&scanline);
468
469 if(result == DD_OK)
470 {
471 inVerticalBlank = false;
472 }
473 else if(result == DDERR_VERTICALBLANKINPROGRESS)
474 {
475 inVerticalBlank = true;
476 }
477 else if(result == DDERR_UNSUPPORTED)
478 {
479 return false;
480 }
481 else ASSERT(false);
482
483 return true;
484 }
485
486 void FrameBufferDD::releaseAll()
487 {
488 unlock();
489
490 if(backBuffer)
491 {
492 backBuffer->Release();
493 backBuffer = 0;
494 }
495
496 if(frontBuffer)
497 {
498 frontBuffer->Release();
499 frontBuffer = 0;
500 }
501
502 if(directDraw)
503 {
504 directDraw->SetCooperativeLevel(0, DDSCL_NORMAL);
505 directDraw->Release();
506 directDraw = 0;
507 }
508 }
509}