Direct3DSwapChain9.cpp revision 894018228b0e0bdbd7aa7e8f47d4a9458789ca82
1// SwiftShader Software Renderer
2//
3// Copyright(c) 2005-2011 TransGaming Inc.
4//
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 "Direct3DSwapChain9.hpp"
13
14#include "Direct3DDevice9.hpp"
15#include "Renderer.hpp"
16#include "Timer.hpp"
17#include "Resource.hpp"
18#include "Configurator.hpp"
19#include "Debug.hpp"
20
21#include "FrameBufferDD.hpp"
22#include "FrameBufferGDI.hpp"
23
24namespace D3D9
25{
26	Direct3DSwapChain9::Direct3DSwapChain9(Direct3DDevice9 *device, D3DPRESENT_PARAMETERS *presentParameters) : device(device), presentParameters(*presentParameters)
27	{
28		frameBuffer = 0;
29
30		for(int i = 0; i < 3; i++)
31		{
32			backBuffer[i] = 0;
33		}
34
35		reset(presentParameters);
36	}
37
38	Direct3DSwapChain9::~Direct3DSwapChain9()
39	{
40		release();
41	}
42
43	long Direct3DSwapChain9::QueryInterface(const IID &iid, void **object)
44	{
45		CriticalSection cs(device);
46
47		TRACE("");
48
49		if(iid == IID_IDirect3DSwapChain9 ||
50		   iid == IID_IUnknown)
51		{
52			AddRef();
53			*object = this;
54
55			return S_OK;
56		}
57
58		*object = 0;
59
60		return NOINTERFACE(iid);
61	}
62
63	unsigned long Direct3DSwapChain9::AddRef()
64	{
65		TRACE("");
66
67		return Unknown::AddRef();
68	}
69
70	unsigned long Direct3DSwapChain9::Release()
71	{
72		TRACE("");
73
74		return Unknown::Release();
75	}
76
77	long Direct3DSwapChain9::Present(const RECT *sourceRect, const RECT *destRect, HWND destWindowOverride, const RGNDATA *dirtyRegion, unsigned long flags)
78	{
79		CriticalSection cs(device);
80
81		TRACE("");
82
83		#if PERF_PROFILE
84			profiler.nextFrame();
85		#endif
86
87		#if PERF_HUD
88			sw::Renderer *renderer = device->renderer;
89
90			static int64_t frame = sw::Timer::ticks();
91
92			int64_t frameTime = sw::Timer::ticks() - frame;
93			frame = sw::Timer::ticks();
94
95			if(frameTime > 0)
96			{
97				unsigned int *frameBuffer = (unsigned int*)lockBackBuffer(0);   // FIXME: Don't assume A8R8G8B8 mode
98				unsigned int stride = backBuffer[0]->getInternalPitchP();
99
100				int thread;
101				for(thread = 0; thread < renderer->getThreadCount(); thread++)
102				{
103					int64_t drawTime = renderer->getVertexTime(thread) + renderer->getSetupTime(thread) + renderer->getPixelTime(thread);
104
105					int vertexPercentage = sw::clamp((int)(100 * renderer->getVertexTime(thread) / frameTime), 0, 100);
106					int setupPercentage = sw::clamp((int)(100 * renderer->getSetupTime(thread) / frameTime), 0, 100);
107					int pixelPercentage = sw::clamp((int)(100 * renderer->getPixelTime(thread) / frameTime), 0, 100);
108
109					for(int i = 0; i < 100; i++)
110					{
111						frameBuffer[thread * stride + i] = 0x00000000;
112					}
113
114					unsigned int *buffer = frameBuffer;
115
116					for(int i = 0; i < vertexPercentage; i++)
117					{
118						buffer[thread * stride] = 0x000000FF;
119						buffer++;
120					}
121
122					for(int i = 0; i < setupPercentage; i++)
123					{
124						buffer[thread * stride] = 0x0000FF00;
125						buffer++;
126					}
127
128					for(int i = 0; i < pixelPercentage; i++)
129					{
130						buffer[thread * stride] = 0x00FF0000;
131						buffer++;
132					}
133
134					frameBuffer[thread * stride + 100] = 0x00FFFFFF;
135				}
136
137				for(int i = 0; i <= 100; i++)
138				{
139					frameBuffer[thread * stride + i] = 0x00FFFFFF;
140				}
141
142				unlockBackBuffer(0);
143			}
144
145			renderer->resetTimers();
146		#endif
147
148		HWND window = destWindowOverride ? destWindowOverride : presentParameters.hDeviceWindow;
149		void *source = backBuffer[0]->lockInternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);   // FIXME: External
150		bool HDR = backBuffer[0]->getInternalFormat() == sw::FORMAT_A16B16G16R16;
151
152		POINT point;
153		GetCursorPos(&point);
154		ScreenToClient(window, &point);
155
156		frameBuffer->setCursorPosition(point.x, point.y);
157
158		if(!sourceRect && !destRect)   // FIXME: More cases?
159		{
160			frameBuffer->flip(window, source, HDR);
161		}
162		else   // FIXME: Check for SWAPEFFECT_COPY
163		{
164			sw::Rect sRect = {0};
165			sw::Rect dRect = {0};
166
167			if(sourceRect)
168			{
169				sRect.left = sourceRect->left;
170				sRect.top = sourceRect->top;
171				sRect.right = sourceRect->right;
172				sRect.bottom = sourceRect->bottom;
173			}
174
175			if(destRect)
176			{
177				dRect.left = destRect->left;
178				dRect.top = destRect->top;
179				dRect.right = destRect->right;
180				dRect.bottom = destRect->bottom;
181			}
182
183			frameBuffer->blit(window, source, sourceRect ? &sRect : 0, destRect ? &dRect : 0, HDR);
184		}
185
186		backBuffer[0]->unlockInternal();   // FIXME: External
187
188		return D3D_OK;
189	}
190
191	long Direct3DSwapChain9::GetFrontBufferData(IDirect3DSurface9 *destSurface)
192	{
193		CriticalSection cs(device);
194
195		TRACE("");
196
197		if(!destSurface)
198		{
199			return INVALIDCALL();
200		}
201
202		sw::Surface *dest = static_cast<Direct3DSurface9*>(destSurface);
203		void *buffer = dest->lockExternal(0, 0, 0, sw::LOCK_WRITEONLY, sw::PRIVATE);
204
205		frameBuffer->screenshot(buffer);
206
207		dest->unlockExternal();
208
209		return D3D_OK;
210	}
211
212	long Direct3DSwapChain9::GetBackBuffer(unsigned int index, D3DBACKBUFFER_TYPE type, IDirect3DSurface9 **backBuffer)
213	{
214		CriticalSection cs(device);
215
216		TRACE("");
217
218		if(!backBuffer/* || type != D3DBACKBUFFER_TYPE_MONO*/)
219		{
220			return INVALIDCALL();
221		}
222
223		*backBuffer = 0;
224
225		if(index >= 3 || this->backBuffer[index] == 0)
226		{
227			return INVALIDCALL();
228		}
229
230		*backBuffer = this->backBuffer[index];
231		this->backBuffer[index]->AddRef();
232
233		return D3D_OK;
234	}
235
236	long Direct3DSwapChain9::GetRasterStatus(D3DRASTER_STATUS *rasterStatus)
237	{
238		CriticalSection cs(device);
239
240		TRACE("");
241
242		if(!rasterStatus)
243		{
244			return INVALIDCALL();
245		}
246
247		bool inVerticalBlank;
248		unsigned int scanline;
249		bool supported = frameBuffer->getScanline(inVerticalBlank, scanline);
250
251		if(supported)
252		{
253			rasterStatus->InVBlank = inVerticalBlank;
254			rasterStatus->ScanLine = scanline;
255		}
256		else
257		{
258			return INVALIDCALL();
259		}
260
261		return D3D_OK;
262	}
263
264	long Direct3DSwapChain9::GetDisplayMode(D3DDISPLAYMODE *displayMode)
265	{
266		CriticalSection cs(device);
267
268		TRACE("");
269
270		if(!displayMode)
271		{
272			return INVALIDCALL();
273		}
274
275		device->getAdapterDisplayMode(D3DADAPTER_DEFAULT, displayMode);
276
277		return D3D_OK;
278	}
279
280	long Direct3DSwapChain9::GetDevice(IDirect3DDevice9 **device)
281	{
282		CriticalSection cs(this->device);
283
284		TRACE("");
285
286		if(!device)
287		{
288			return INVALIDCALL();
289		}
290
291		this->device->AddRef();
292		*device = this->device;
293
294		return D3D_OK;
295	}
296
297	long Direct3DSwapChain9::GetPresentParameters(D3DPRESENT_PARAMETERS *presentParameters)
298	{
299		CriticalSection cs(device);
300
301		TRACE("");
302
303		if(!presentParameters)
304		{
305			return INVALIDCALL();
306		}
307
308		*presentParameters = this->presentParameters;
309
310		return D3D_OK;
311	}
312
313	void Direct3DSwapChain9::reset(D3DPRESENT_PARAMETERS *presentParameters)
314	{
315		release();
316
317		ASSERT(presentParameters->BackBufferCount <= 3);   // Maximum of three back buffers
318
319		if(presentParameters->BackBufferCount == 0)
320		{
321			presentParameters->BackBufferCount = 1;
322		}
323
324		if(presentParameters->BackBufferFormat == D3DFMT_UNKNOWN)
325		{
326			D3DDISPLAYMODE displayMode;
327			GetDisplayMode(&displayMode);
328
329			presentParameters->BackBufferFormat = displayMode.Format;
330		}
331
332		D3DDEVICE_CREATION_PARAMETERS creationParameters;
333		device->GetCreationParameters(&creationParameters);
334
335		HWND windowHandle = presentParameters->hDeviceWindow ? presentParameters->hDeviceWindow : creationParameters.hFocusWindow;
336
337		if(presentParameters->Windowed && (presentParameters->BackBufferHeight == 0 || presentParameters->BackBufferWidth == 0))
338		{
339			RECT rectangle;
340			GetClientRect(windowHandle, &rectangle);
341
342			presentParameters->BackBufferWidth = rectangle.right - rectangle.left;
343			presentParameters->BackBufferHeight = rectangle.bottom - rectangle.top;
344		}
345
346		lockable = presentParameters->Flags & D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
347
348		sw::Configurator ini("SwiftShader.ini");
349		int api = ini.getInteger("Testing", "FrameBufferAPI", 0);
350
351		if(api == 0)
352		{
353			frameBuffer = new sw::FrameBufferDD(windowHandle, presentParameters->BackBufferWidth, presentParameters->BackBufferHeight, presentParameters->Windowed == FALSE);
354		}
355		else if(api == 1)
356		{
357			frameBuffer = new sw::FrameBufferGDI(windowHandle, presentParameters->BackBufferWidth, presentParameters->BackBufferHeight, presentParameters->Windowed == FALSE);
358		}
359		else ASSERT(false);
360
361		backBuffer[0] = 0;
362		backBuffer[1] = 0;
363		backBuffer[2] = 0;
364
365		for(int i = 0; i < (int)presentParameters->BackBufferCount; i++)
366		{
367			backBuffer[i] = new Direct3DSurface9(device, this, presentParameters->BackBufferWidth, presentParameters->BackBufferHeight, presentParameters->BackBufferFormat, D3DPOOL_DEFAULT, presentParameters->MultiSampleType, presentParameters->MultiSampleQuality, lockable, D3DUSAGE_RENDERTARGET);
368			backBuffer[i]->bind();
369		}
370
371		this->presentParameters = *presentParameters;
372	}
373
374	void Direct3DSwapChain9::release()
375	{
376		delete frameBuffer;
377		frameBuffer = 0;
378
379		for(int i = 0; i < 3; i++)
380		{
381			if(backBuffer[i])
382			{
383				backBuffer[i]->unbind();
384				backBuffer[i] = 0;
385			}
386		}
387	}
388
389	void Direct3DSwapChain9::setGammaRamp(sw::GammaRamp *gammaRamp, bool calibrate)
390	{
391		frameBuffer->setGammaRamp(gammaRamp, calibrate);
392	}
393
394	void Direct3DSwapChain9::getGammaRamp(sw::GammaRamp *gammaRamp)
395	{
396		frameBuffer->getGammaRamp(gammaRamp);
397	}
398
399	void *Direct3DSwapChain9::lockBackBuffer(int index)
400	{
401		return backBuffer[index]->lockInternal(0, 0, 0, sw::LOCK_READWRITE, sw::PUBLIC);   // FIXME: External
402	}
403
404	void Direct3DSwapChain9::unlockBackBuffer(int index)
405	{
406		backBuffer[index]->unlockInternal();   // FIXME: External
407	}
408}
409