// Copyright 2016 The SwiftShader Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "Direct3DSwapChain9.hpp" #include "Direct3DDevice9.hpp" #include "Renderer.hpp" #include "Timer.hpp" #include "Resource.hpp" #include "Configurator.hpp" #include "Debug.hpp" #include "FrameBufferDD.hpp" #include "FrameBufferGDI.hpp" namespace D3D9 { Direct3DSwapChain9::Direct3DSwapChain9(Direct3DDevice9 *device, D3DPRESENT_PARAMETERS *presentParameters) : device(device), presentParameters(*presentParameters) { frameBuffer = 0; for(int i = 0; i < 3; i++) { backBuffer[i] = 0; } reset(presentParameters); } Direct3DSwapChain9::~Direct3DSwapChain9() { release(); } long Direct3DSwapChain9::QueryInterface(const IID &iid, void **object) { CriticalSection cs(device); TRACE(""); if(iid == IID_IDirect3DSwapChain9 || iid == IID_IUnknown) { AddRef(); *object = this; return S_OK; } *object = 0; return NOINTERFACE(iid); } unsigned long Direct3DSwapChain9::AddRef() { TRACE(""); return Unknown::AddRef(); } unsigned long Direct3DSwapChain9::Release() { TRACE(""); return Unknown::Release(); } long Direct3DSwapChain9::Present(const RECT *sourceRect, const RECT *destRect, HWND destWindowOverride, const RGNDATA *dirtyRegion, unsigned long flags) { CriticalSection cs(device); TRACE(""); #if PERF_PROFILE profiler.nextFrame(); #endif #if PERF_HUD sw::Renderer *renderer = device->renderer; static int64_t frame = sw::Timer::ticks(); int64_t frameTime = sw::Timer::ticks() - frame; frame = sw::Timer::ticks(); if(frameTime > 0) { unsigned int *frameBuffer = (unsigned int*)lockBackBuffer(0); // FIXME: Don't assume A8R8G8B8 mode unsigned int stride = backBuffer[0]->getInternalPitchP(); int thread; for(thread = 0; thread < renderer->getThreadCount(); thread++) { int64_t drawTime = renderer->getVertexTime(thread) + renderer->getSetupTime(thread) + renderer->getPixelTime(thread); int vertexPercentage = sw::clamp((int)(100 * renderer->getVertexTime(thread) / frameTime), 0, 100); int setupPercentage = sw::clamp((int)(100 * renderer->getSetupTime(thread) / frameTime), 0, 100); int pixelPercentage = sw::clamp((int)(100 * renderer->getPixelTime(thread) / frameTime), 0, 100); for(int i = 0; i < 100; i++) { frameBuffer[thread * stride + i] = 0x00000000; } unsigned int *buffer = frameBuffer; for(int i = 0; i < vertexPercentage; i++) { buffer[thread * stride] = 0x000000FF; buffer++; } for(int i = 0; i < setupPercentage; i++) { buffer[thread * stride] = 0x0000FF00; buffer++; } for(int i = 0; i < pixelPercentage; i++) { buffer[thread * stride] = 0x00FF0000; buffer++; } frameBuffer[thread * stride + 100] = 0x00FFFFFF; } for(int i = 0; i <= 100; i++) { frameBuffer[thread * stride + i] = 0x00FFFFFF; } unlockBackBuffer(0); } renderer->resetTimers(); #endif HWND window = destWindowOverride ? destWindowOverride : presentParameters.hDeviceWindow; POINT point; GetCursorPos(&point); ScreenToClient(window, &point); frameBuffer->setCursorPosition(point.x, point.y); if(!sourceRect && !destRect) // FIXME: More cases? { frameBuffer->flip(window, backBuffer[0]); } else // FIXME: Check for SWAPEFFECT_COPY { sw::Rect sRect(0, 0, 0, 0); sw::Rect dRect(0, 0, 0, 0); if(sourceRect) { sRect.x0 = sourceRect->left; sRect.y0 = sourceRect->top; sRect.x1 = sourceRect->right; sRect.y1 = sourceRect->bottom; } if(destRect) { dRect.x0 = destRect->left; dRect.y0 = destRect->top; dRect.x1 = destRect->right; dRect.y1 = destRect->bottom; } frameBuffer->blit(window, backBuffer[0], sourceRect ? &sRect : nullptr, destRect ? &dRect : nullptr); } return D3D_OK; } long Direct3DSwapChain9::GetFrontBufferData(IDirect3DSurface9 *destSurface) { CriticalSection cs(device); TRACE(""); if(!destSurface) { return INVALIDCALL(); } sw::Surface *dest = static_cast<Direct3DSurface9*>(destSurface); void *buffer = dest->lockExternal(0, 0, 0, sw::LOCK_WRITEONLY, sw::PRIVATE); frameBuffer->screenshot(buffer); dest->unlockExternal(); return D3D_OK; } long Direct3DSwapChain9::GetBackBuffer(unsigned int index, D3DBACKBUFFER_TYPE type, IDirect3DSurface9 **backBuffer) { CriticalSection cs(device); TRACE(""); if(!backBuffer/* || type != D3DBACKBUFFER_TYPE_MONO*/) { return INVALIDCALL(); } *backBuffer = 0; if(index >= 3 || this->backBuffer[index] == 0) { return INVALIDCALL(); } *backBuffer = this->backBuffer[index]; this->backBuffer[index]->AddRef(); return D3D_OK; } long Direct3DSwapChain9::GetRasterStatus(D3DRASTER_STATUS *rasterStatus) { CriticalSection cs(device); TRACE(""); if(!rasterStatus) { return INVALIDCALL(); } bool inVerticalBlank; unsigned int scanline; bool supported = frameBuffer->getScanline(inVerticalBlank, scanline); if(supported) { rasterStatus->InVBlank = inVerticalBlank; rasterStatus->ScanLine = scanline; } else { return INVALIDCALL(); } return D3D_OK; } long Direct3DSwapChain9::GetDisplayMode(D3DDISPLAYMODE *displayMode) { CriticalSection cs(device); TRACE(""); if(!displayMode) { return INVALIDCALL(); } device->getAdapterDisplayMode(D3DADAPTER_DEFAULT, displayMode); return D3D_OK; } long Direct3DSwapChain9::GetDevice(IDirect3DDevice9 **device) { CriticalSection cs(this->device); TRACE(""); if(!device) { return INVALIDCALL(); } this->device->AddRef(); *device = this->device; return D3D_OK; } long Direct3DSwapChain9::GetPresentParameters(D3DPRESENT_PARAMETERS *presentParameters) { CriticalSection cs(device); TRACE(""); if(!presentParameters) { return INVALIDCALL(); } *presentParameters = this->presentParameters; return D3D_OK; } void Direct3DSwapChain9::reset(D3DPRESENT_PARAMETERS *presentParameters) { release(); ASSERT(presentParameters->BackBufferCount <= 3); // Maximum of three back buffers if(presentParameters->BackBufferCount == 0) { presentParameters->BackBufferCount = 1; } if(presentParameters->BackBufferFormat == D3DFMT_UNKNOWN) { D3DDISPLAYMODE displayMode; GetDisplayMode(&displayMode); presentParameters->BackBufferFormat = displayMode.Format; } D3DDEVICE_CREATION_PARAMETERS creationParameters; device->GetCreationParameters(&creationParameters); HWND windowHandle = presentParameters->hDeviceWindow ? presentParameters->hDeviceWindow : creationParameters.hFocusWindow; if(presentParameters->Windowed && (presentParameters->BackBufferHeight == 0 || presentParameters->BackBufferWidth == 0)) { RECT rectangle; GetClientRect(windowHandle, &rectangle); presentParameters->BackBufferWidth = rectangle.right - rectangle.left; presentParameters->BackBufferHeight = rectangle.bottom - rectangle.top; } frameBuffer = createFrameBufferWin(windowHandle, presentParameters->BackBufferWidth, presentParameters->BackBufferHeight, presentParameters->Windowed == FALSE, true); lockable = presentParameters->Flags & D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; backBuffer[0] = 0; backBuffer[1] = 0; backBuffer[2] = 0; for(int i = 0; i < (int)presentParameters->BackBufferCount; i++) { backBuffer[i] = new Direct3DSurface9(device, this, presentParameters->BackBufferWidth, presentParameters->BackBufferHeight, presentParameters->BackBufferFormat, D3DPOOL_DEFAULT, presentParameters->MultiSampleType, presentParameters->MultiSampleQuality, lockable, D3DUSAGE_RENDERTARGET); backBuffer[i]->bind(); } this->presentParameters = *presentParameters; } void Direct3DSwapChain9::release() { delete frameBuffer; frameBuffer = 0; for(int i = 0; i < 3; i++) { if(backBuffer[i]) { backBuffer[i]->unbind(); backBuffer[i] = 0; } } } void Direct3DSwapChain9::setGammaRamp(sw::GammaRamp *gammaRamp, bool calibrate) { frameBuffer->setGammaRamp(gammaRamp, calibrate); } void Direct3DSwapChain9::getGammaRamp(sw::GammaRamp *gammaRamp) { frameBuffer->getGammaRamp(gammaRamp); } void *Direct3DSwapChain9::lockBackBuffer(int index) { return backBuffer[index]->lockInternal(0, 0, 0, sw::LOCK_READWRITE, sw::PUBLIC); // FIXME: External } void Direct3DSwapChain9::unlockBackBuffer(int index) { backBuffer[index]->unlockInternal(); // FIXME: External } }