Add SwiftShader source to repo
Oct 6 code drop from Transgaming
Review URL: https://chromereviews.googleplex.com/3846015
diff --git a/src/Main/FrameBufferDD.cpp b/src/Main/FrameBufferDD.cpp
new file mode 100644
index 0000000..0ec2d79
--- /dev/null
+++ b/src/Main/FrameBufferDD.cpp
@@ -0,0 +1,488 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2011 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+#include "FrameBufferDD.hpp"
+
+#include "Debug.hpp"
+
+namespace sw
+{
+ extern bool forceWindowed;
+
+ GUID secondaryDisplay = {0};
+
+ int __stdcall enumDisplayCallback(GUID* guid, char *driverDescription, char *driverName, void *context, HMONITOR monitor)
+ {
+ if(strcmp(driverName, "\\\\.\\DISPLAY2") == 0)
+ {
+ secondaryDisplay = *guid;
+ }
+
+ return 1;
+ }
+
+ FrameBufferDD::FrameBufferDD(HWND windowHandle, int width, int height, bool fullscreen) : FrameBuffer(windowHandle, width, height, fullscreen)
+ {
+ directDraw = 0;
+ frontBuffer = 0;
+ backBuffer = 0;
+
+ locked = 0;
+
+ ddraw = LoadLibrary("ddraw.dll");
+ DirectDrawCreate = (DIRECTDRAWCREATE)GetProcAddress(ddraw, "DirectDrawCreate");
+ DirectDrawEnumerateExA = (DIRECTDRAWENUMERATEEXA)GetProcAddress(ddraw, "DirectDrawEnumerateExA");
+
+ if(!windowed)
+ {
+ initFullscreen();
+ }
+ else
+ {
+ initWindowed();
+ }
+ }
+
+ FrameBufferDD::~FrameBufferDD()
+ {
+ releaseAll();
+
+ FreeLibrary(ddraw);
+ }
+
+ void FrameBufferDD::createSurfaces()
+ {
+ if(backBuffer)
+ {
+ backBuffer->Release();
+ backBuffer = 0;
+ }
+
+ if(frontBuffer)
+ {
+ frontBuffer->Release();
+ frontBuffer = 0;
+ }
+
+ if(!windowed)
+ {
+ DDSURFACEDESC surfaceDescription = {0};
+ surfaceDescription.dwSize = sizeof(surfaceDescription);
+ surfaceDescription.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
+ surfaceDescription.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
+ surfaceDescription.dwBackBufferCount = 1;
+ long result = directDraw->CreateSurface(&surfaceDescription, &frontBuffer, 0);
+
+ if(frontBuffer)
+ {
+ DDSCAPS surfaceCapabilties = {0};
+ surfaceCapabilties.dwCaps = DDSCAPS_BACKBUFFER;
+ frontBuffer->GetAttachedSurface(&surfaceCapabilties, &backBuffer);
+ backBuffer->AddRef();
+ }
+ }
+ else
+ {
+ IDirectDrawClipper *clipper;
+
+ DDSURFACEDESC ddsd = {0};
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+
+ long result = directDraw->CreateSurface(&ddsd, &frontBuffer, 0);
+ directDraw->GetDisplayMode(&ddsd);
+ bitDepth = ddsd.ddpfPixelFormat.dwRGBBitCount;
+
+ if((result != DD_OK && result != DDERR_PRIMARYSURFACEALREADYEXISTS) || (bitDepth != 32 && bitDepth != 24 && bitDepth != 16))
+ {
+ gracefulExit("Failed to initialize graphics: incompatible display mode. Aborting application.", result);
+ }
+
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = width;
+ ddsd.dwHeight = height;
+
+ directDraw->CreateSurface(&ddsd, &backBuffer, 0);
+
+ directDraw->CreateClipper(0, &clipper, 0);
+ clipper->SetHWnd(0, windowHandle);
+ frontBuffer->SetClipper(clipper);
+ clipper->Release();
+ }
+ }
+
+ bool FrameBufferDD::readySurfaces()
+ {
+ if(!frontBuffer || !backBuffer)
+ {
+ createSurfaces();
+ }
+
+ if(frontBuffer && backBuffer)
+ {
+ if(frontBuffer->IsLost() || backBuffer->IsLost())
+ {
+ restoreSurfaces();
+ }
+
+ if(frontBuffer && backBuffer)
+ {
+ if(!frontBuffer->IsLost() && !backBuffer->IsLost())
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ void FrameBufferDD::updateClipper(HWND windowOverride)
+ {
+ if(windowed)
+ {
+ if(frontBuffer)
+ {
+ HWND window = windowOverride ? windowOverride : windowHandle;
+
+ IDirectDrawClipper *clipper;
+ frontBuffer->GetClipper(&clipper);
+ clipper->SetHWnd(0, window);
+ clipper->Release();
+ }
+ }
+ }
+
+ void FrameBufferDD::restoreSurfaces()
+ {
+ long result1 = frontBuffer->Restore();
+ long result2 = backBuffer->Restore();
+
+ if(result1 != DD_OK || result2 != DD_OK) // Surfaces could not be restored; recreate them
+ {
+ createSurfaces();
+ }
+ }
+
+ void FrameBufferDD::initFullscreen()
+ {
+ releaseAll();
+
+ if(true) // Render to primary display
+ {
+ DirectDrawCreate(0, &directDraw, 0);
+ }
+ else // Render to secondary display
+ {
+ DirectDrawEnumerateEx(&enumDisplayCallback, 0, DDENUM_ATTACHEDSECONDARYDEVICES);
+ DirectDrawCreate(&secondaryDisplay, &directDraw, 0);
+ }
+
+ directDraw->SetCooperativeLevel(windowHandle, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
+
+ long result;
+
+ do
+ {
+ bitDepth = 32;
+ result = directDraw->SetDisplayMode(width, height, bitDepth);
+
+ if(result == DDERR_INVALIDMODE)
+ {
+ bitDepth = 16;
+ result = directDraw->SetDisplayMode(width, height, bitDepth);
+
+ if(result == DDERR_INVALIDMODE)
+ {
+ bitDepth = 24;
+ result = directDraw->SetDisplayMode(width, height, bitDepth);
+
+ if(result == DDERR_INVALIDMODE)
+ {
+ gracefulExit("Failed to initialize graphics: display mode unsupported. Aborting application.", result);
+ }
+ }
+ }
+
+ if(result != DD_OK)
+ {
+ Sleep(1);
+ }
+ }
+ while(result != DD_OK);
+
+ createSurfaces();
+
+ updateBounds(windowHandle);
+ }
+
+ void FrameBufferDD::initWindowed()
+ {
+ releaseAll();
+
+ DirectDrawCreate(0, &directDraw, 0);
+ directDraw->SetCooperativeLevel(windowHandle, DDSCL_NORMAL);
+
+ createSurfaces();
+
+ updateBounds(windowHandle);
+ }
+
+ void FrameBufferDD::flip(HWND windowOverride, void *source, bool HDR)
+ {
+ updateClipper(windowOverride);
+
+ copy(windowOverride, source, HDR);
+
+ if(!readySurfaces())
+ {
+ return;
+ }
+
+ while(true)
+ {
+ long result;
+
+ if(windowed)
+ {
+ result = frontBuffer->Blt(&bounds, backBuffer, 0, DDBLT_WAIT, 0);
+ }
+ else
+ {
+ result = frontBuffer->Flip(0, DDFLIP_NOVSYNC);
+ }
+
+ if(result != DDERR_WASSTILLDRAWING)
+ {
+ break;
+ }
+
+ Sleep(0);
+ }
+ }
+
+ void FrameBufferDD::blit(HWND windowOverride, void *source, const Rect *sourceRect, const Rect *destRect, bool HDR)
+ {
+ updateClipper(windowOverride);
+
+ copy(windowOverride, source, HDR);
+
+ if(!readySurfaces())
+ {
+ return;
+ }
+
+ RECT dRect;
+
+ if(destRect)
+ {
+ dRect.bottom = bounds.top + destRect->bottom;
+ dRect.left = bounds.left + destRect->left;
+ dRect.right = bounds.left + destRect->right;
+ dRect.top = bounds.top + destRect->top;
+ }
+ else
+ {
+ dRect.bottom = bounds.top + height;
+ dRect.left = bounds.left + 0;
+ dRect.right = bounds.left + width;
+ dRect.top = bounds.top + 0;
+ }
+
+ while(true)
+ {
+ long result = frontBuffer->Blt(&dRect, backBuffer, (LPRECT)sourceRect, DDBLT_WAIT, 0);
+
+ if(result != DDERR_WASSTILLDRAWING)
+ {
+ break;
+ }
+
+ Sleep(0);
+ }
+ }
+
+ void FrameBufferDD::screenshot(void *destBuffer)
+ {
+ if(!readySurfaces())
+ {
+ return;
+ }
+
+ DDSURFACEDESC DDSD;
+ DDSD.dwSize = sizeof(DDSD);
+
+ long result = frontBuffer->Lock(0, &DDSD, DDLOCK_WAIT, 0);
+
+ if(result == DD_OK)
+ {
+ int width = DDSD.dwWidth;
+ int height = DDSD.dwHeight;
+ int bitDepth = DDSD.ddpfPixelFormat.dwRGBBitCount;
+ int stride = DDSD.lPitch;
+
+ void *sourceBuffer = DDSD.lpSurface;
+
+ for(int y = 0; y < height; y++)
+ {
+ memcpy(destBuffer, sourceBuffer, width * 4); // FIXME: Assumes 32-bit buffer
+
+ (char*&)sourceBuffer += stride;
+ (char*&)destBuffer += 4 * width;
+ }
+
+ frontBuffer->Unlock(0);
+ }
+ }
+
+ void FrameBufferDD::setGammaRamp(GammaRamp *gammaRamp, bool calibrate)
+ {
+ IDirectDrawGammaControl *gammaControl = 0;
+
+ if(frontBuffer)
+ {
+ frontBuffer->QueryInterface(IID_IDirectDrawGammaControl, (void**)&gammaControl);
+
+ if(gammaControl)
+ {
+ gammaControl->SetGammaRamp(calibrate ? DDSGR_CALIBRATE : 0, (DDGAMMARAMP*)gammaRamp);
+
+ gammaControl->Release();
+ }
+ }
+ }
+
+ void FrameBufferDD::getGammaRamp(GammaRamp *gammaRamp)
+ {
+ IDirectDrawGammaControl *gammaControl = 0;
+
+ if(frontBuffer)
+ {
+ frontBuffer->QueryInterface(IID_IDirectDrawGammaControl, (void**)&gammaControl);
+
+ if(gammaControl)
+ {
+ gammaControl->GetGammaRamp(0, (DDGAMMARAMP*)gammaRamp);
+
+ gammaControl->Release();
+ }
+ }
+ }
+
+ void *FrameBufferDD::lock()
+ {
+ if(locked)
+ {
+ return locked;
+ }
+
+ if(!readySurfaces())
+ {
+ return 0;
+ }
+
+ DDSURFACEDESC DDSD;
+ DDSD.dwSize = sizeof(DDSD);
+
+ long result = backBuffer->Lock(0, &DDSD, DDLOCK_WAIT, 0);
+
+ if(result == DD_OK)
+ {
+ width = DDSD.dwWidth;
+ height = DDSD.dwHeight;
+ int bitDepth = DDSD.ddpfPixelFormat.dwRGBBitCount;
+ stride = DDSD.lPitch;
+
+ locked = DDSD.lpSurface;
+
+ return locked;
+ }
+
+ return 0;
+ }
+
+ void FrameBufferDD::unlock()
+ {
+ if(!locked || !backBuffer) return;
+
+ backBuffer->Unlock(0);
+
+ locked = 0;
+ }
+
+ void FrameBufferDD::drawText(int x, int y, const char *string, ...)
+ {
+ char buffer[256];
+ va_list arglist;
+
+ va_start(arglist, string);
+ vsprintf(buffer, string, arglist);
+ va_end(arglist);
+
+ HDC hdc;
+
+ backBuffer->GetDC(&hdc);
+
+ SetBkColor(hdc, RGB(0, 0, 255));
+ SetTextColor(hdc, RGB(255, 255, 255));
+
+ TextOut(hdc, x, y, buffer, lstrlen(buffer));
+
+ backBuffer->ReleaseDC(hdc);
+ }
+
+ bool FrameBufferDD::getScanline(bool &inVerticalBlank, unsigned int &scanline)
+ {
+ HRESULT result = directDraw->GetScanLine((unsigned long*)&scanline);
+
+ if(result == DD_OK)
+ {
+ inVerticalBlank = false;
+ }
+ else if(result == DDERR_VERTICALBLANKINPROGRESS)
+ {
+ inVerticalBlank = true;
+ }
+ else if(result == DDERR_UNSUPPORTED)
+ {
+ return false;
+ }
+ else ASSERT(false);
+
+ return true;
+ }
+
+ void FrameBufferDD::releaseAll()
+ {
+ unlock();
+
+ if(backBuffer)
+ {
+ backBuffer->Release();
+ backBuffer = 0;
+ }
+
+ if(frontBuffer)
+ {
+ frontBuffer->Release();
+ frontBuffer = 0;
+ }
+
+ if(directDraw)
+ {
+ directDraw->SetCooperativeLevel(0, DDSCL_NORMAL);
+ directDraw->Release();
+ directDraw = 0;
+ }
+ }
+}