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 "Direct3DVertexBuffer9.hpp"
16
17#include "Direct3DDevice9.hpp"
18#include "Resource.hpp"
19#include "Debug.hpp"
20
21#include <assert.h>
22
23namespace D3D9
24{
25	Direct3DVertexBuffer9::Direct3DVertexBuffer9(Direct3DDevice9 *device, unsigned int length, unsigned long usage, long FVF, D3DPOOL pool) : Direct3DResource9(device, D3DRTYPE_VERTEXBUFFER, pool, length), length(length), usage(usage), FVF(FVF)
26	{
27		if(FVF)
28		{
29			unsigned int stride = 0;
30
31			switch(FVF & D3DFVF_POSITION_MASK)
32			{
33			case D3DFVF_XYZ:	stride += 12;	break;
34			case D3DFVF_XYZRHW:	stride += 16;	break;
35			case D3DFVF_XYZB1:	stride += 16;	break;
36			case D3DFVF_XYZB2:	stride += 20;	break;
37			case D3DFVF_XYZB3:	stride += 24;	break;
38			case D3DFVF_XYZB4:	stride += 28;	break;
39			case D3DFVF_XYZB5:	stride += 32;	break;
40			case D3DFVF_XYZW:   stride += 16;   break;
41			}
42
43			if(FVF & D3DFVF_NORMAL)   stride += 12;
44			if(FVF & D3DFVF_PSIZE)    stride += 4;
45			if(FVF & D3DFVF_DIFFUSE)  stride += 4;
46			if(FVF & D3DFVF_SPECULAR) stride += 4;
47
48			switch((FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT)
49			{
50			case 8: stride += 4 + 4 * ((1 + (FVF >> 30)) % 4);
51			case 7: stride += 4 + 4 * ((1 + (FVF >> 28)) % 4);
52			case 6: stride += 4 + 4 * ((1 + (FVF >> 26)) % 4);
53			case 5: stride += 4 + 4 * ((1 + (FVF >> 24)) % 4);
54			case 4: stride += 4 + 4 * ((1 + (FVF >> 22)) % 4);
55			case 3: stride += 4 + 4 * ((1 + (FVF >> 20)) % 4);
56			case 2: stride += 4 + 4 * ((1 + (FVF >> 18)) % 4);
57			case 1: stride += 4 + 4 * ((1 + (FVF >> 16)) % 4);
58			case 0: break;
59			default:
60				ASSERT(false);
61			}
62
63			ASSERT(length >= stride);       // FIXME
64		}
65
66		vertexBuffer = new sw::Resource(length + 192 + 1024);   // NOTE: Applications can 'overshoot' while writing vertices
67		lockCount = 0;
68	}
69
70	Direct3DVertexBuffer9::~Direct3DVertexBuffer9()
71	{
72		vertexBuffer->destruct();
73	}
74
75	long Direct3DVertexBuffer9::QueryInterface(const IID &iid, void **object)
76	{
77		CriticalSection cs(device);
78
79		TRACE("");
80
81		if(iid == IID_IDirect3DVertexBuffer9 ||
82		   iid == IID_IDirect3DResource9 ||
83		   iid == IID_IUnknown)
84		{
85			AddRef();
86			*object = this;
87
88			return S_OK;
89		}
90
91		*object = 0;
92
93		return NOINTERFACE(iid);
94	}
95
96	unsigned long Direct3DVertexBuffer9::AddRef()
97	{
98		TRACE("");
99
100		return Direct3DResource9::AddRef();
101	}
102
103	unsigned long Direct3DVertexBuffer9::Release()
104	{
105		TRACE("");
106
107		return Direct3DResource9::Release();
108	}
109
110	long Direct3DVertexBuffer9::FreePrivateData(const GUID &guid)
111	{
112		CriticalSection cs(device);
113
114		TRACE("");
115
116		return Direct3DResource9::FreePrivateData(guid);
117	}
118
119	long Direct3DVertexBuffer9::GetPrivateData(const GUID &guid, void *data, unsigned long *size)
120	{
121		CriticalSection cs(device);
122
123		TRACE("");
124
125		return Direct3DResource9::GetPrivateData(guid, data, size);
126	}
127
128	void Direct3DVertexBuffer9::PreLoad()
129	{
130		CriticalSection cs(device);
131
132		TRACE("");
133
134		Direct3DResource9::PreLoad();
135	}
136
137	long Direct3DVertexBuffer9::SetPrivateData(const GUID &guid, const void *data, unsigned long size, unsigned long flags)
138	{
139		CriticalSection cs(device);
140
141		TRACE("");
142
143		return Direct3DResource9::SetPrivateData(guid, data, size, flags);
144	}
145
146	long Direct3DVertexBuffer9::GetDevice(IDirect3DDevice9 **device)
147	{
148		CriticalSection cs(this->device);
149
150		TRACE("");
151
152		return Direct3DResource9::GetDevice(device);
153	}
154
155	unsigned long Direct3DVertexBuffer9::SetPriority(unsigned long newPriority)
156	{
157		CriticalSection cs(device);
158
159		TRACE("");
160
161		return Direct3DResource9::SetPriority(newPriority);
162	}
163
164	unsigned long Direct3DVertexBuffer9::GetPriority()
165	{
166		CriticalSection cs(device);
167
168		TRACE("");
169
170		return Direct3DResource9::GetPriority();
171	}
172
173	D3DRESOURCETYPE Direct3DVertexBuffer9::GetType()
174	{
175		CriticalSection cs(device);
176
177		TRACE("");
178
179		return Direct3DResource9::GetType();
180	}
181
182	long Direct3DVertexBuffer9::Lock(unsigned int offset, unsigned int size, void **data, unsigned long flags)
183	{
184		CriticalSection cs(device);
185
186		TRACE("");
187
188		if(offset == 0 && size == 0)   // Lock whole buffer
189		{
190			size = length;
191		}
192
193		if(!data || offset + size > length)
194		{
195			return INVALIDCALL();
196		}
197
198		void *buffer;
199
200		if(flags & D3DLOCK_DISCARD/* && usage & D3DUSAGE_DYNAMIC*/)
201		{
202			vertexBuffer->destruct();
203			vertexBuffer = new sw::Resource(length + 192 + 1024);   // NOTE: Applications can 'overshoot' while writing vertices
204
205			buffer = (void*)vertexBuffer->data();
206		}
207		else if(flags & D3DLOCK_NOOVERWRITE/* && usage & D3DUSAGE_DYNAMIC*/)
208		{
209			buffer = (void*)vertexBuffer->data();
210		}
211		else
212		{
213			buffer = vertexBuffer->lock(sw::PUBLIC);
214			lockCount++;
215		}
216
217		*data = (unsigned char*)buffer + offset;
218
219		return D3D_OK;
220	}
221
222	long Direct3DVertexBuffer9::Unlock()
223	{
224		CriticalSection cs(device);
225
226		TRACE("");
227
228		if(lockCount > 0)
229		{
230			vertexBuffer->unlock();
231			lockCount--;
232		}
233
234		return D3D_OK;
235	}
236
237	long Direct3DVertexBuffer9::GetDesc(D3DVERTEXBUFFER_DESC *description)
238	{
239		CriticalSection cs(device);
240
241		TRACE("");
242
243		if(!description)
244		{
245			return INVALIDCALL();
246		}
247
248		description->FVF = FVF;
249		description->Format = D3DFMT_VERTEXDATA;
250		description->Pool = pool;
251		description->Size = length;
252		description->Type = D3DRTYPE_VERTEXBUFFER;
253		description->Usage = usage;
254
255		return D3D_OK;
256	}
257
258	int Direct3DVertexBuffer9::getLength() const
259	{
260		return length;
261	}
262
263	sw::Resource *Direct3DVertexBuffer9::getResource() const
264	{
265		return vertexBuffer;
266	}
267}
268