1// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "Direct3DSurface9.hpp"
16
17#include "Direct3DDevice9.hpp"
18#include "Direct3DBaseTexture9.hpp"
19#include "Capabilities.hpp"
20#include "Resource.hpp"
21#include "Debug.hpp"
22
23#include <malloc.h>
24#include <assert.h>
25
26extern bool quadLayoutEnabled;
27
28namespace D3D9
29{
30	sw::Resource *getParentResource(Unknown *container)
31	{
32		Direct3DBaseTexture9 *baseTexture = dynamic_cast<Direct3DBaseTexture9*>(container);
33
34		if(baseTexture)
35		{
36			return baseTexture->getResource();
37		}
38
39		return 0;
40	}
41
42	int sampleCount(D3DMULTISAMPLE_TYPE multiSample, unsigned int quality)
43	{
44		if(multiSample == D3DMULTISAMPLE_NONMASKABLE)
45		{
46			switch(quality)
47			{
48			case 0: return 2;
49			case 1: return 4;
50			case 2: return 8;
51			case 3: return 16;
52			}
53		}
54		else if(multiSample == D3DMULTISAMPLE_2_SAMPLES)
55		{
56			return 2;
57		}
58		else if(multiSample == D3DMULTISAMPLE_4_SAMPLES)
59		{
60			return 4;
61		}
62		else if(multiSample == D3DMULTISAMPLE_8_SAMPLES)
63		{
64			return 8;
65		}
66		else if(multiSample == D3DMULTISAMPLE_16_SAMPLES)
67		{
68			return 16;
69		}
70
71		return 1;
72	}
73
74	bool isLockable(D3DPOOL pool, unsigned long usage, bool lockableOverride)
75	{
76		return (pool != D3DPOOL_DEFAULT) || (usage & D3DUSAGE_DYNAMIC) || lockableOverride;
77	}
78
79	Direct3DSurface9::Direct3DSurface9(Direct3DDevice9 *device, Unknown *container, int width, int height, D3DFORMAT format, D3DPOOL pool, D3DMULTISAMPLE_TYPE multiSample, unsigned int quality, bool lockableOverride, unsigned long usage)
80		: Direct3DResource9(device, D3DRTYPE_SURFACE, pool, memoryUsage(width, height, multiSample, quality, format)), Surface(getParentResource(container), width, height, 1, 0, sampleCount(multiSample, quality), translateFormat(format), isLockable(pool, usage, lockableOverride), (usage & D3DUSAGE_RENDERTARGET) || (usage & D3DUSAGE_DEPTHSTENCIL)), container(container), width(width), height(height), format(format), pool(pool), multiSample(multiSample), quality(quality), lockable(isLockable(pool, usage, lockableOverride)), usage(usage)
81	{
82		parentTexture = dynamic_cast<Direct3DBaseTexture9*>(container);
83	}
84
85	Direct3DSurface9::~Direct3DSurface9()
86	{
87	}
88
89	void *Direct3DSurface9::lockInternal(int x, int y, int z, sw::Lock lock, sw::Accessor client)
90	{
91		return Surface::lockInternal(x, y, z, lock, client);
92	}
93
94	void Direct3DSurface9::unlockInternal()
95	{
96		Surface::unlockInternal();
97	}
98
99	long Direct3DSurface9::QueryInterface(const IID &iid, void **object)
100	{
101		CriticalSection cs(device);
102
103		TRACE("");
104
105		if(iid == IID_IDirect3DSurface9 ||
106		   iid == IID_IDirect3DResource9 ||
107		   iid == IID_IUnknown)
108		{
109			AddRef();
110			*object = this;
111
112			return S_OK;
113		}
114
115		*object = 0;
116
117		return NOINTERFACE(iid);
118	}
119
120	unsigned long Direct3DSurface9::AddRef()
121	{
122		TRACE("");
123
124		if(parentTexture)
125		{
126			return parentTexture->AddRef();
127		}
128
129		return Direct3DResource9::AddRef();
130	}
131
132	unsigned long Direct3DSurface9::Release()
133	{
134		TRACE("");
135
136		if(parentTexture)
137		{
138			return parentTexture->Release();
139		}
140
141		return Direct3DResource9::Release();
142	}
143
144	long Direct3DSurface9::FreePrivateData(const GUID &guid)
145	{
146		CriticalSection cs(device);
147
148		TRACE("");
149
150		return Direct3DResource9::FreePrivateData(guid);
151	}
152
153	long Direct3DSurface9::GetPrivateData(const GUID &guid, void *data, unsigned long *size)
154	{
155		CriticalSection cs(device);
156
157		TRACE("");
158
159		return Direct3DResource9::GetPrivateData(guid, data, size);
160	}
161
162	void Direct3DSurface9::PreLoad()
163	{
164		CriticalSection cs(device);
165
166		TRACE("");
167
168		Direct3DResource9::PreLoad();
169	}
170
171	long Direct3DSurface9::SetPrivateData(const GUID &guid, const void *data, unsigned long size, unsigned long flags)
172	{
173		CriticalSection cs(device);
174
175		TRACE("");
176
177		return Direct3DResource9::SetPrivateData(guid, data, size, flags);
178	}
179
180	long Direct3DSurface9::GetDevice(IDirect3DDevice9 **device)
181	{
182		CriticalSection cs(this->device);
183
184		TRACE("");
185
186		return Direct3DResource9::GetDevice(device);
187	}
188
189	unsigned long Direct3DSurface9::SetPriority(unsigned long newPriority)
190	{
191		CriticalSection cs(device);
192
193		TRACE("");
194
195		return Direct3DResource9::SetPriority(newPriority);
196	}
197
198	unsigned long Direct3DSurface9::GetPriority()
199	{
200		CriticalSection cs(device);
201
202		TRACE("");
203
204		return Direct3DResource9::GetPriority();
205	}
206
207	D3DRESOURCETYPE Direct3DSurface9::GetType()
208	{
209		CriticalSection cs(device);
210
211		TRACE("");
212
213		return Direct3DResource9::GetType();
214	}
215
216	long Direct3DSurface9::GetDC(HDC *deviceContext)
217	{
218		CriticalSection cs(device);
219
220		TRACE("");
221
222		if(!deviceContext)
223		{
224			return INVALIDCALL();
225		}
226
227		UNIMPLEMENTED();
228
229		return D3D_OK;
230	}
231
232	long Direct3DSurface9::ReleaseDC(HDC deviceContext)
233	{
234		CriticalSection cs(device);
235
236		TRACE("");
237
238		UNIMPLEMENTED();
239
240		return D3D_OK;
241	}
242
243	long Direct3DSurface9::LockRect(D3DLOCKED_RECT *lockedRect, const RECT *rect, unsigned long flags)
244	{
245		CriticalSection cs(device);
246
247		TRACE("D3DLOCKED_RECT *lockedRect = 0x%0.8p, const RECT *rect = 0x%0.8p, unsigned long flags = %d", lockedRect, rect, flags);
248
249		if(!lockedRect)
250		{
251			return INVALIDCALL();
252		}
253
254		lockedRect->Pitch = 0;
255		lockedRect->pBits = 0;
256
257		if(!lockable)
258		{
259			return INVALIDCALL();
260		}
261
262		lockedRect->Pitch = getExternalPitchB();
263
264		sw::Lock lock = sw::LOCK_READWRITE;
265
266		if(flags & D3DLOCK_DISCARD)
267		{
268			lock = sw::LOCK_DISCARD;
269		}
270
271		if(flags & D3DLOCK_READONLY)
272		{
273			lock = sw::LOCK_READONLY;
274		}
275
276		if(rect)
277		{
278			lockedRect->pBits = lockExternal(rect->left, rect->top, 0, lock, sw::PUBLIC);
279		}
280		else
281		{
282			lockedRect->pBits = lockExternal(0, 0, 0, lock, sw::PUBLIC);
283		}
284
285		return D3D_OK;
286	}
287
288	long Direct3DSurface9::UnlockRect()
289	{
290		CriticalSection cs(device);
291
292		TRACE("");
293
294		unlockExternal();
295
296		return D3D_OK;
297	}
298
299	long Direct3DSurface9::GetContainer(const IID &iid, void **container)
300	{
301		CriticalSection cs(device);
302
303		TRACE("");
304
305		if(!container)
306		{
307			return INVALIDCALL();
308		}
309
310		long result = this->container->QueryInterface(iid, container);
311
312		if(result == S_OK)
313		{
314			return D3D_OK;
315		}
316
317		return INVALIDCALL();
318	}
319
320	long Direct3DSurface9::GetDesc(D3DSURFACE_DESC *description)
321	{
322		CriticalSection cs(device);
323
324		TRACE("");
325
326		if(!description)
327		{
328			return INVALIDCALL();
329		}
330
331		description->Format = format;
332		description->Pool = pool;
333		description->Type = D3DRTYPE_SURFACE;
334		description->Height = height;
335		description->Width = width;
336		description->MultiSampleType = multiSample;
337		description->MultiSampleQuality = quality;
338		description->Usage = usage;
339
340		return D3D_OK;
341	}
342
343	sw::Format Direct3DSurface9::translateFormat(D3DFORMAT format)
344	{
345		switch(format)
346		{
347		case D3DFMT_NULL:			return sw::FORMAT_NULL;
348		case D3DFMT_DXT1:			return sw::FORMAT_DXT1;
349		case D3DFMT_DXT2:			return sw::FORMAT_DXT3;
350		case D3DFMT_DXT3:			return sw::FORMAT_DXT3;
351		case D3DFMT_DXT4:			return sw::FORMAT_DXT5;
352		case D3DFMT_DXT5:			return sw::FORMAT_DXT5;
353		case D3DFMT_ATI1:			return sw::FORMAT_ATI1;
354		case D3DFMT_ATI2:			return sw::FORMAT_ATI2;
355		case D3DFMT_R3G3B2:			return sw::FORMAT_R3G3B2;
356		case D3DFMT_A8R3G3B2:		return sw::FORMAT_A8R3G3B2;
357		case D3DFMT_X4R4G4B4:		return sw::FORMAT_X4R4G4B4;
358		case D3DFMT_A4R4G4B4:		return sw::FORMAT_A4R4G4B4;
359		case D3DFMT_A8R8G8B8:		return sw::FORMAT_A8R8G8B8;
360		case D3DFMT_A8B8G8R8:		return sw::FORMAT_A8B8G8R8;
361		case D3DFMT_G16R16:			return sw::FORMAT_G16R16;
362		case D3DFMT_A2R10G10B10:	return sw::FORMAT_A2R10G10B10;
363		case D3DFMT_A2B10G10R10:	return sw::FORMAT_A2B10G10R10;
364		case D3DFMT_A16B16G16R16:	return sw::FORMAT_A16B16G16R16;
365		case D3DFMT_P8:				return sw::FORMAT_P8;
366		case D3DFMT_A8P8:			return sw::FORMAT_A8P8;
367		case D3DFMT_A8:				return sw::FORMAT_A8;
368		case D3DFMT_R5G6B5:			return sw::FORMAT_R5G6B5;
369		case D3DFMT_X1R5G5B5:		return sw::FORMAT_X1R5G5B5;
370		case D3DFMT_A1R5G5B5:		return sw::FORMAT_A1R5G5B5;
371		case D3DFMT_R8G8B8:			return sw::FORMAT_R8G8B8;
372		case D3DFMT_X8R8G8B8:		return sw::FORMAT_X8R8G8B8;
373		case D3DFMT_X8B8G8R8:		return sw::FORMAT_X8B8G8R8;
374		case D3DFMT_V8U8:			return sw::FORMAT_V8U8;
375		case D3DFMT_L6V5U5:			return sw::FORMAT_L6V5U5;
376		case D3DFMT_Q8W8V8U8:		return sw::FORMAT_Q8W8V8U8;
377		case D3DFMT_X8L8V8U8:		return sw::FORMAT_X8L8V8U8;
378		case D3DFMT_A2W10V10U10:	return sw::FORMAT_A2W10V10U10;
379		case D3DFMT_V16U16:			return sw::FORMAT_V16U16;
380		case D3DFMT_Q16W16V16U16:	return sw::FORMAT_Q16W16V16U16;
381		case D3DFMT_L8:				return sw::FORMAT_L8;
382		case D3DFMT_A4L4:			return sw::FORMAT_A4L4;
383		case D3DFMT_L16:			return sw::FORMAT_L16;
384		case D3DFMT_A8L8:			return sw::FORMAT_A8L8;
385		case D3DFMT_R16F:			return sw::FORMAT_R16F;
386		case D3DFMT_G16R16F:		return sw::FORMAT_G16R16F;
387		case D3DFMT_A16B16G16R16F:	return sw::FORMAT_A16B16G16R16F;
388		case D3DFMT_R32F:			return sw::FORMAT_R32F;
389		case D3DFMT_G32R32F:		return sw::FORMAT_G32R32F;
390		case D3DFMT_A32B32G32R32F:	return sw::FORMAT_A32B32G32R32F;
391		case D3DFMT_D16:			return sw::FORMAT_D16;
392		case D3DFMT_D32:			return sw::FORMAT_D32;
393		case D3DFMT_D24X8:			return sw::FORMAT_D24X8;
394		case D3DFMT_D24S8:			return sw::FORMAT_D24S8;
395		case D3DFMT_D24FS8:			return sw::FORMAT_D24FS8;
396		case D3DFMT_D32F_LOCKABLE:	return sw::FORMAT_D32F_LOCKABLE;
397		case D3DFMT_DF24:			return sw::FORMAT_DF24S8;
398		case D3DFMT_DF16:			return sw::FORMAT_DF16S8;
399		case D3DFMT_INTZ:			return sw::FORMAT_INTZ;
400		default:
401			ASSERT(false);
402		}
403
404		return sw::FORMAT_NULL;
405	}
406
407	int Direct3DSurface9::bytes(D3DFORMAT format)
408	{
409		return Surface::bytes(translateFormat(format));
410	}
411
412	unsigned int Direct3DSurface9::memoryUsage(int width, int height, D3DMULTISAMPLE_TYPE multiSample, unsigned int quality, D3DFORMAT format)
413	{
414		return Surface::size(width, height, 1, 0, sampleCount(multiSample, quality), translateFormat(format));
415	}
416}
417