| // SwiftShader Software Renderer |
| // |
| // Copyright(c) 2005-2012 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 "FrameBuffer.hpp" |
| |
| #include "Timer.hpp" |
| #include "CPUID.hpp" |
| #include "serialvalid.h" |
| #include "Surface.hpp" |
| #include "Register.hpp" |
| #include "Debug.hpp" |
| #include "Reactor/Reactor.hpp" |
| #include "Common/Configurator.hpp" |
| |
| #include <stdio.h> |
| |
| extern const int logoWidth; |
| extern const int logoHeight; |
| extern const unsigned int logoData[]; |
| |
| #ifndef DISPLAY_LOGO |
| #define DISPLAY_LOGO (NDEBUG & 1) |
| #endif |
| |
| #define ASYNCHRONOUS_BLIT 0 // FIXME: Currently leads to rare race conditions |
| |
| namespace sw |
| { |
| extern bool forceWindowed; |
| |
| Surface *FrameBuffer::logo; |
| unsigned int *FrameBuffer::logoImage; |
| void *FrameBuffer::cursor; |
| int FrameBuffer::cursorWidth = 0; |
| int FrameBuffer::cursorHeight = 0; |
| int FrameBuffer::cursorHotspotX; |
| int FrameBuffer::cursorHotspotY; |
| int FrameBuffer::cursorPositionX; |
| int FrameBuffer::cursorPositionY; |
| int FrameBuffer::cursorX; |
| int FrameBuffer::cursorY; |
| bool FrameBuffer::topLeftOrigin = false; |
| |
| FrameBuffer::FrameBuffer(HWND windowHandle, int width, int height, bool fullscreen, bool topLeftOrigin) |
| { |
| this->topLeftOrigin = topLeftOrigin; |
| |
| locked = 0; |
| |
| this->windowHandle = windowHandle; |
| this->width = width; |
| this->height = height; |
| bitDepth = 32; |
| HDRdisplay = false; |
| stride = 0; |
| |
| if(forceWindowed) |
| { |
| fullscreen = false; |
| } |
| |
| windowed = !fullscreen; |
| |
| if(!windowed) |
| { |
| // Force fullscreen window style (no borders) |
| originalWindowStyle = GetWindowLong(windowHandle, GWL_STYLE); |
| SetWindowLong(windowHandle, GWL_STYLE, WS_POPUP); |
| } |
| |
| HINSTANCE instance = (HINSTANCE)GetWindowLongPtr(windowHandle, GWLP_HINSTANCE); |
| unsigned char one[32 * 32 / sizeof(unsigned char)]; |
| memset(one, 0xFFFFFFFF, sizeof(one)); |
| unsigned char zero[32 * 32 / sizeof(unsigned char)] = {0}; |
| nullCursor = CreateCursor(instance, 0, 0, 32, 32, one, zero); |
| win32Cursor = GetCursor(); |
| |
| blitFunction = 0; |
| blitRoutine = 0; |
| |
| blitState.width = 0; |
| blitState.height = 0; |
| blitState.depth = 0; |
| blitState.cursorWidth = 0; |
| blitState.cursorHeight = 0; |
| |
| logo = 0; |
| |
| if(ASYNCHRONOUS_BLIT) |
| { |
| syncEvent = CreateEvent(0, FALSE, FALSE, 0); |
| blitEvent = CreateEvent(0, FALSE, FALSE, 0); |
| FrameBuffer *parameters = this; |
| |
| terminate = false; |
| blitThread = CreateThread(0, 1024 * 1024, threadFunction, ¶meters, 0, 0); |
| WaitForSingleObject(syncEvent, INFINITE); |
| } |
| } |
| |
| FrameBuffer::~FrameBuffer() |
| { |
| if(ASYNCHRONOUS_BLIT) |
| { |
| terminate = true; |
| SetEvent(blitEvent); |
| WaitForSingleObject(blitThread, INFINITE); |
| CloseHandle(blitThread); |
| CloseHandle(blitEvent); |
| CloseHandle(syncEvent); |
| } |
| |
| delete blitRoutine; |
| |
| DestroyCursor(nullCursor); |
| |
| if(!windowed && GetWindowLong(windowHandle, GWL_STYLE) == WS_POPUP) |
| { |
| SetWindowLong(windowHandle, GWL_STYLE, originalWindowStyle); |
| } |
| } |
| |
| void FrameBuffer::updateBounds(HWND windowOverride) |
| { |
| HWND window = windowOverride ? windowOverride : windowHandle; |
| |
| if(windowed) |
| { |
| GetClientRect(window, &bounds); |
| ClientToScreen(window, (POINT*)&bounds); |
| ClientToScreen(window, (POINT*)&bounds + 1); |
| } |
| else |
| { |
| SetRect(&bounds, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); |
| } |
| } |
| |
| int FrameBuffer::getWidth() const |
| { |
| return width; |
| } |
| |
| int FrameBuffer::getHeight() const |
| { |
| return height; |
| } |
| |
| int FrameBuffer::getStride() const |
| { |
| return stride; |
| } |
| |
| void FrameBuffer::setCursorImage(sw::Surface *cursorImage) |
| { |
| if(cursorImage) |
| { |
| cursor = cursorImage->lockExternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC); |
| cursorImage->unlockExternal(); |
| |
| cursorWidth = cursorImage->getExternalWidth(); |
| cursorHeight = cursorImage->getExternalHeight(); |
| } |
| else |
| { |
| cursorWidth = 0; |
| cursorHeight = 0; |
| } |
| } |
| |
| void FrameBuffer::setCursorOrigin(int x0, int y0) |
| { |
| cursorHotspotX = x0; |
| cursorHotspotY = y0; |
| } |
| |
| void FrameBuffer::setCursorPosition(int x, int y) |
| { |
| cursorPositionX = x; |
| cursorPositionY = y; |
| } |
| |
| void FrameBuffer::copy(HWND windowOverride, void *source, bool HDR) |
| { |
| if(!source) |
| { |
| return; |
| } |
| |
| updateBounds(windowOverride); |
| |
| if(!lock()) |
| { |
| return; |
| } |
| |
| if(topLeftOrigin) |
| { |
| target = source; |
| } |
| else |
| { |
| const int width2 = (width + 1) & ~1; |
| const int sBytes = HDR ? 8 : 4; |
| const int sStride = sBytes * width2; |
| |
| target = (byte*)source + (height - 1) * sStride; |
| } |
| |
| HDRdisplay = HDR; |
| |
| if(cursor) |
| { |
| cursorX = cursorPositionX - cursorHotspotX; |
| cursorY = cursorPositionY - cursorHotspotY; |
| |
| HCURSOR oldCursor = SetCursor(nullCursor); |
| |
| if(oldCursor != nullCursor) |
| { |
| win32Cursor = oldCursor; |
| } |
| } |
| else |
| { |
| if(GetCursor() == nullCursor) |
| { |
| SetCursor(win32Cursor); |
| } |
| } |
| |
| if(ASYNCHRONOUS_BLIT) |
| { |
| SetEvent(blitEvent); |
| WaitForSingleObject(syncEvent, INFINITE); |
| } |
| else |
| { |
| copyLocked(); |
| } |
| |
| unlock(); |
| } |
| |
| void FrameBuffer::copyLocked() |
| { |
| BlitState update; |
| |
| update.width = width; |
| update.height = height; |
| update.depth = bitDepth; |
| update.stride = stride; |
| update.HDR = HDRdisplay; |
| update.cursorWidth = cursorWidth; |
| update.cursorHeight = cursorHeight; |
| |
| if(memcmp(&blitState, &update, sizeof(BlitState)) != 0) |
| { |
| blitState = update; |
| delete blitRoutine; |
| |
| blitRoutine = copyRoutine(blitState); |
| blitFunction = (void(__cdecl*)(void*, void*))blitRoutine->getEntry(); |
| } |
| |
| blitFunction(locked, target); |
| |
| #ifndef _M_AMD64 |
| __asm emms |
| #endif |
| } |
| |
| Routine *FrameBuffer::copyRoutine(const BlitState &state) |
| { |
| initializeLogo(); |
| |
| const int width = state.width; |
| const int height = state.height; |
| const int width2 = (state.width + 1) & ~1; |
| const int dBytes = state.depth / 8; |
| const int dStride = state.stride; |
| const int sBytes = state.HDR ? 8 : 4; |
| const int sStride = topLeftOrigin ? (sBytes * width2) : -(sBytes * width2); |
| |
| // char compareApp[32] = SCRAMBLE31(validationApp, APPNAME_SCRAMBLE); |
| // bool validApp = strcmp(compareApp, registeredApp) == 0; |
| bool validKey = ValidateSerialNumber(validationKey, CHECKSUM_KEY, SERIAL_PREFIX); |
| |
| Function<Void, Pointer<Byte>, Pointer<Byte>> function; |
| { |
| Pointer<Byte> dst(function.arg(0)); |
| Pointer<Byte> src(function.arg(1)); |
| |
| For(Int y = 0, y < height, y++) |
| { |
| Pointer<Byte> d = dst + y * dStride; |
| Pointer<Byte> s = src + y * sStride; |
| |
| Int x0 = 0; |
| |
| #if DISPLAY_LOGO |
| If(!Bool(validKey)/* || !Bool(validApp)*/) |
| { |
| If(y > height - logoHeight) |
| { |
| x0 = logoWidth; |
| s += logoWidth * sBytes; |
| d += logoWidth * dBytes; |
| } |
| } |
| #endif |
| |
| if(state.depth == 32) |
| { |
| if(width2 % 4 == 0 && !state.HDR) |
| { |
| For(Int x = x0, x < width2, x += 4) |
| { |
| *Pointer<Int4>(d, 1) = *Pointer<Int4>(s, 16); |
| |
| s += 4 * sBytes; |
| d += 4 * dBytes; |
| } |
| } |
| else |
| { |
| For(Int x = x0, x < width2, x += 2) |
| { |
| Int2 c01; |
| |
| if(!state.HDR) |
| { |
| c01 = *Pointer<Int2>(s); |
| } |
| else |
| { |
| UShort4 c0 = As<UShort4>(Swizzle(*Pointer<Short4>(s + 0), 0xC6)) >> 8; |
| UShort4 c1 = As<UShort4>(Swizzle(*Pointer<Short4>(s + 8), 0xC6)) >> 8; |
| |
| c01 = As<Int2>(Pack(c0, c1)); |
| } |
| |
| *Pointer<Int2>(d) = c01; |
| |
| s += 2 * sBytes; |
| d += 2 * dBytes; |
| } |
| } |
| } |
| else if(state.depth == 24) |
| { |
| For(Int x = x0, x < width, x++) |
| { |
| if(!state.HDR) |
| { |
| *Pointer<Byte>(d + 0) = *Pointer<Byte>(s + 0); |
| *Pointer<Byte>(d + 1) = *Pointer<Byte>(s + 1); |
| *Pointer<Byte>(d + 2) = *Pointer<Byte>(s + 2); |
| } |
| else |
| { |
| *Pointer<Byte>(d + 0) = *Pointer<Byte>(s + 5); |
| *Pointer<Byte>(d + 1) = *Pointer<Byte>(s + 3); |
| *Pointer<Byte>(d + 2) = *Pointer<Byte>(s + 1); |
| } |
| |
| s += sBytes; |
| d += dBytes; |
| } |
| } |
| else if(state.depth == 16) |
| { |
| For(Int x = x0, x < width, x++) |
| { |
| Int c; |
| |
| if(!state.HDR) |
| { |
| c = *Pointer<Int>(s); |
| } |
| else |
| { |
| UShort4 cc = As<UShort4>(Swizzle(*Pointer<Short4>(s + 0), 0xC6)) >> 8; |
| |
| c = Int(As<Int2>(Pack(cc, cc))); |
| } |
| |
| *Pointer<Short>(d) = Short((c & 0x00F80000) >> 8 | |
| (c & 0x0000FC00) >> 5 | |
| (c & 0x000000F8) >> 3); |
| |
| s += sBytes; |
| d += dBytes; |
| } |
| } |
| else ASSERT(false); |
| } |
| |
| #if DISPLAY_LOGO |
| If(!Bool(validKey)/* || !Bool(validApp)*/) |
| { |
| UInt hash = UInt(0x0B020C04) + UInt(0xC0F090E0); // Initial value |
| UInt imageHash = S3TC_SUPPORT ? UInt(0x01010600) + UInt(0xC0302010) : UInt(0x0D030E0B) + UInt(0xB0D01040); |
| |
| While(hash != imageHash) |
| { |
| For(y = (height - 1), height - 1 - y < logoHeight, y--) |
| { |
| Pointer<Byte> logo = *Pointer<Pointer<Byte>>(&logoImage) + 4 * (logoHeight - height + y) * logoWidth; |
| Pointer<Byte> s = src + y * sStride; |
| Pointer<Byte> d = dst + y * dStride; |
| |
| For(Int x = 0, x < logoWidth, x++) |
| { |
| hash *= 16777619; |
| hash ^= *Pointer<UInt>(logo); |
| |
| If(y >= 0 && x < width) |
| { |
| blend(state, d, s, logo); |
| } |
| |
| logo += 4; |
| s += sBytes; |
| d += dBytes; |
| } |
| } |
| } |
| } |
| #endif |
| |
| Int x0 = *Pointer<Int>(&cursorX); |
| Int y0 = *Pointer<Int>(&cursorY); |
| |
| For(Int y1 = 0, y1 < cursorHeight, y1++) |
| { |
| Int y = y0 + y1; |
| |
| If(y >= 0 && y < height) |
| { |
| Pointer<Byte> d = dst + y * dStride + x0 * dBytes; |
| Pointer<Byte> s = src + y * sStride + x0 * sBytes; |
| Pointer<Byte> c = *Pointer<Pointer<Byte>>(&cursor) + y1 * cursorWidth * 4; |
| |
| For(Int x1 = 0, x1 < cursorWidth, x1++) |
| { |
| Int x = x0 + x1; |
| |
| If(x >= 0 && x < width) |
| { |
| blend(state, d, s, c); |
| } |
| |
| c += 4; |
| s += sBytes; |
| d += dBytes; |
| } |
| } |
| } |
| |
| Return(); |
| } |
| |
| return function(L"FrameBuffer"); |
| } |
| |
| void FrameBuffer::blend(const BlitState &state, const Pointer<Byte> &d, const Pointer<Byte> &s, const Pointer<Byte> &c) |
| { |
| Short4 c1; |
| Short4 c2; |
| |
| c1 = UnpackLow(As<Byte8>(c1), *Pointer<Byte8>(c)); |
| |
| if(!state.HDR) |
| { |
| c2 = UnpackLow(As<Byte8>(c2), *Pointer<Byte8>(s)); |
| } |
| else |
| { |
| c2 = Swizzle(*Pointer<Short4>(s + 0), 0xC6); |
| } |
| |
| c1 = As<Short4>(As<UShort4>(c1) >> 9); |
| c2 = As<Short4>(As<UShort4>(c2) >> 9); |
| |
| Short4 alpha = Swizzle(c1, 0xFF) & Short4(0xFFFFu, 0xFFFFu, 0xFFFFu, 0x0000); |
| |
| c1 = (c1 - c2) * alpha; |
| c1 = c1 >> 7; |
| c1 = c1 + c2; |
| c1 = c1 + c1; |
| |
| c1 = As<Short4>(Pack(As<UShort4>(c1), As<UShort4>(c1))); |
| |
| if(state.depth == 32) |
| { |
| *Pointer<UInt>(d) = UInt(As<Long>(c1)); |
| } |
| else if(state.depth == 24) |
| { |
| Int c = Int(As<Int2>(c1)); |
| |
| *Pointer<Byte>(d + 0) = Byte(c >> 0); |
| *Pointer<Byte>(d + 1) = Byte(c >> 8); |
| *Pointer<Byte>(d + 2) = Byte(c >> 16); |
| } |
| else if(state.depth == 16) |
| { |
| Int c = Int(As<Int2>(c1)); |
| |
| *Pointer<Short>(d) = Short((c & 0x00F80000) >> 8 | |
| (c & 0x0000FC00) >> 5 | |
| (c & 0x000000F8) >> 3); |
| } |
| else ASSERT(false); |
| } |
| |
| unsigned long __stdcall FrameBuffer::threadFunction(void *parameters) |
| { |
| FrameBuffer *frameBuffer = *static_cast<FrameBuffer**>(parameters); |
| |
| SetEvent(frameBuffer->syncEvent); // Received parameters |
| |
| while(!frameBuffer->terminate) |
| { |
| WaitForSingleObject(frameBuffer->blitEvent, INFINITE); |
| |
| if(!frameBuffer->terminate) |
| { |
| frameBuffer->copyLocked(); |
| |
| SetEvent(frameBuffer->syncEvent); |
| } |
| } |
| |
| return 0; |
| } |
| |
| void FrameBuffer::initializeLogo() |
| { |
| #if DISPLAY_LOGO |
| if(!logo) |
| { |
| #if S3TC_SUPPORT |
| logo = new Surface(0, logoWidth, logoHeight, 1, FORMAT_DXT5, true, false); |
| void *data = logo->lockExternal(0, 0, 0, LOCK_WRITEONLY, sw::PUBLIC); |
| memcpy(data, logoData, logoWidth * logoHeight); |
| logo->unlockExternal(); |
| #else |
| logo = new Surface(0, logoWidth, logoHeight, 1, FORMAT_A8R8G8B8, true, false); |
| void *data = logo->lockExternal(0, 0, 0, LOCK_WRITEONLY, sw::PUBLIC); |
| memcpy(data, logoData, logoWidth * logoHeight * 4); |
| logo->unlockExternal(); |
| #endif |
| |
| logoImage = (unsigned int*)logo->lockInternal(0, 0, 0, LOCK_READONLY, sw::PUBLIC); |
| logo->unlockInternal(); |
| } |
| #endif |
| } |
| } |
| |
| #include "FrameBufferDD.hpp" |
| #include "FrameBufferGDI.hpp" |
| |
| extern "C" |
| { |
| sw::FrameBuffer *createFrameBuffer(HWND windowHandle, int width, int height, bool fullscreen, bool topLeftOrigin) |
| { |
| sw::Configurator ini("SwiftShader.ini"); |
| int api = ini.getInteger("Testing", "FrameBufferAPI", 1); |
| |
| if(api == 0) |
| { |
| return new sw::FrameBufferDD(windowHandle, width, height, fullscreen, topLeftOrigin); |
| } |
| else if(api == 1) |
| { |
| return new sw::FrameBufferGDI(windowHandle, width, height, fullscreen, topLeftOrigin); |
| } |
| else ASSERT(false); |
| |
| return 0; |
| } |
| } |