VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Wine/wined3d/device.c@ 16477

Last change on this file since 16477 was 16477, checked in by vboxsync, 16 years ago

LGPL disclaimer by filemuncher

  • Property svn:eol-style set to native
File size: 320.8 KB
Line 
1/*
2 * IWineD3DDevice implementation
3 *
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 */
27
28/*
29 * Sun LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
30 * other than GPL or LGPL is available it will apply instead, Sun elects to use only
31 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
32 * a choice of LGPL license versions is made available with the language indicating
33 * that LGPLv2 or any later version may be used, or where a choice of which version
34 * of the LGPL is applied is otherwise unspecified.
35 */
36
37#include "config.h"
38#include <stdio.h>
39#ifdef HAVE_FLOAT_H
40# include <float.h>
41#endif
42#include "wined3d_private.h"
43
44WINE_DEFAULT_DEBUG_CHANNEL(d3d);
45#define GLINFO_LOCATION This->adapter->gl_info
46
47/* Define the default light parameters as specified by MSDN */
48const WINED3DLIGHT WINED3D_default_light = {
49
50 WINED3DLIGHT_DIRECTIONAL, /* Type */
51 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
52 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
53 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
54 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
55 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
56 0.0, /* Range */
57 0.0, /* Falloff */
58 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
59 0.0, /* Theta */
60 0.0 /* Phi */
61};
62
63/* static function declarations */
64static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
65
66/* helper macros */
67#define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
68
69#define D3DCREATEOBJECTINSTANCE(object, type) { \
70 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
71 D3DMEMCHECK(object, pp##type); \
72 object->lpVtbl = &IWineD3D##type##_Vtbl; \
73 object->wineD3DDevice = This; \
74 object->parent = parent; \
75 object->ref = 1; \
76 *pp##type = (IWineD3D##type *) object; \
77}
78
79#define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
80 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
81 D3DMEMCHECK(object, pp##type); \
82 object->lpVtbl = &IWineD3D##type##_Vtbl; \
83 object->parent = parent; \
84 object->baseShader.ref = 1; \
85 object->baseShader.device = (IWineD3DDevice*) This; \
86 list_init(&object->baseShader.linked_programs); \
87 *pp##type = (IWineD3D##type *) object; \
88}
89
90#define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
91 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
92 D3DMEMCHECK(object, pp##type); \
93 object->lpVtbl = &IWineD3D##type##_Vtbl; \
94 object->resource.wineD3DDevice = This; \
95 object->resource.parent = parent; \
96 object->resource.resourceType = d3dtype; \
97 object->resource.ref = 1; \
98 object->resource.pool = Pool; \
99 object->resource.format = Format; \
100 object->resource.usage = Usage; \
101 object->resource.size = _size; \
102 object->resource.priority = 0; \
103 list_init(&object->resource.privateData); \
104 /* Check that we have enough video ram left */ \
105 if (Pool == WINED3DPOOL_DEFAULT) { \
106 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
107 WARN("Out of 'bogus' video memory\n"); \
108 HeapFree(GetProcessHeap(), 0, object); \
109 *pp##type = NULL; \
110 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 } \
112 WineD3DAdapterChangeGLRam(This, _size); \
113 } \
114 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
115 if (object->resource.heapMemory == NULL && _size != 0) { \
116 FIXME("Out of memory!\n"); \
117 HeapFree(GetProcessHeap(), 0, object); \
118 *pp##type = NULL; \
119 return WINED3DERR_OUTOFVIDEOMEMORY; \
120 } \
121 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
122 *pp##type = (IWineD3D##type *) object; \
123 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
124 TRACE("(%p) : Created resource %p\n", This, object); \
125}
126
127#define D3DINITIALIZEBASETEXTURE(_basetexture) { \
128 _basetexture.levels = Levels; \
129 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
130 _basetexture.LOD = 0; \
131 _basetexture.dirty = TRUE; \
132 _basetexture.is_srgb = FALSE; \
133 _basetexture.srgb_mode_change_count = 0; \
134}
135
136/**********************************************************
137 * Global variable / Constants follow
138 **********************************************************/
139const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
140
141/**********************************************************
142 * IUnknown parts follows
143 **********************************************************/
144
145static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
146{
147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
148
149 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
150 if (IsEqualGUID(riid, &IID_IUnknown)
151 || IsEqualGUID(riid, &IID_IWineD3DBase)
152 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
153 IUnknown_AddRef(iface);
154 *ppobj = This;
155 return S_OK;
156 }
157 *ppobj = NULL;
158 return E_NOINTERFACE;
159}
160
161static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
163 ULONG refCount = InterlockedIncrement(&This->ref);
164
165 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
166 return refCount;
167}
168
169static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
171 ULONG refCount = InterlockedDecrement(&This->ref);
172
173 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
174
175 if (!refCount) {
176 /* TODO: Clean up all the surfaces and textures! */
177 /* NOTE: You must release the parent if the object was created via a callback
178 ** ***************************/
179
180 if (!list_empty(&This->resources)) {
181 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
182 dumpResources(&This->resources);
183 }
184
185 if(This->contexts) ERR("Context array not freed!\n");
186 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
187 This->haveHardwareCursor = FALSE;
188
189 IWineD3D_Release(This->wineD3D);
190 This->wineD3D = NULL;
191 HeapFree(GetProcessHeap(), 0, This);
192 TRACE("Freed device %p\n", This);
193 This = NULL;
194 }
195 return refCount;
196}
197
198/**********************************************************
199 * IWineD3DDevice implementation follows
200 **********************************************************/
201static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
203 *pParent = This->parent;
204 IUnknown_AddRef(This->parent);
205 return WINED3D_OK;
206}
207
208static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
209 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
210 IUnknown *parent) {
211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
212 IWineD3DVertexBufferImpl *object;
213 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
214 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
215 BOOL conv;
216
217 if(Size == 0) {
218 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
219 *ppVertexBuffer = NULL;
220 return WINED3DERR_INVALIDCALL;
221 } else if(Pool == WINED3DPOOL_SCRATCH) {
222 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
223 * anyway, SCRATCH vertex buffers aren't usable anywhere
224 */
225 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
226 *ppVertexBuffer = NULL;
227 return WINED3DERR_INVALIDCALL;
228 }
229
230 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
231
232 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
233 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
234
235 object->fvf = FVF;
236
237 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
238 * drawStridedFast (half-life 2).
239 *
240 * Basically converting the vertices in the buffer is quite expensive, and observations
241 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
242 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
243 *
244 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
245 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
246 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
247 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
248 * dx7 apps.
249 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
250 * more. In this call we can convert dx7 buffers too.
251 */
252 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
253 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
254 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
255 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
256 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
257 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
258 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
259 } else if(dxVersion <= 7 && conv) {
260 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
261 } else {
262 object->Flags |= VBFLAG_CREATEVBO;
263 }
264 return WINED3D_OK;
265}
266
267static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
268 GLenum error, glUsage;
269 TRACE("Creating VBO for Index Buffer %p\n", object);
270
271 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
272 * restored on the next draw
273 */
274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
275
276 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
277 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
278 ENTER_GL();
279
280 while(glGetError());
281
282 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
283 error = glGetError();
284 if(error != GL_NO_ERROR || object->vbo == 0) {
285 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
286 goto out;
287 }
288
289 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
290 error = glGetError();
291 if(error != GL_NO_ERROR) {
292 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
293 goto out;
294 }
295
296 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
297 * copy no readback will be needed
298 */
299 glUsage = GL_STATIC_DRAW_ARB;
300 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
301 error = glGetError();
302 if(error != GL_NO_ERROR) {
303 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
304 goto out;
305 }
306 LEAVE_GL();
307 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
308 return;
309
310out:
311 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
312 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
313 LEAVE_GL();
314 object->vbo = 0;
315}
316
317static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
318 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
319 HANDLE *sharedHandle, IUnknown *parent) {
320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
321 IWineD3DIndexBufferImpl *object;
322 TRACE("(%p) Creating index buffer\n", This);
323
324 /* Allocate the storage for the device */
325 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
326
327 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
328 CreateIndexBufferVBO(This, object);
329 }
330
331 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
332 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
333 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
334
335 return WINED3D_OK;
336}
337
338static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
339
340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
341 IWineD3DStateBlockImpl *object;
342 int i, j;
343 HRESULT temp_result;
344
345 D3DCREATEOBJECTINSTANCE(object, StateBlock)
346 object->blockType = Type;
347
348 for(i = 0; i < LIGHTMAP_SIZE; i++) {
349 list_init(&object->lightMap[i]);
350 }
351
352 /* Special case - Used during initialization to produce a placeholder stateblock
353 so other functions called can update a state block */
354 if (Type == WINED3DSBT_INIT) {
355 /* Don't bother increasing the reference count otherwise a device will never
356 be freed due to circular dependencies */
357 return WINED3D_OK;
358 }
359
360 temp_result = allocate_shader_constants(object);
361 if (WINED3D_OK != temp_result)
362 return temp_result;
363
364 /* Otherwise, might as well set the whole state block to the appropriate values */
365 if (This->stateBlock != NULL)
366 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
367 else
368 memset(object->streamFreq, 1, sizeof(object->streamFreq));
369
370 /* Reset the ref and type after kludging it */
371 object->wineD3DDevice = This;
372 object->ref = 1;
373 object->blockType = Type;
374
375 TRACE("Updating changed flags appropriate for type %d\n", Type);
376
377 if (Type == WINED3DSBT_ALL) {
378
379 TRACE("ALL => Pretend everything has changed\n");
380 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
381
382 /* Lights are not part of the changed / set structure */
383 for(j = 0; j < LIGHTMAP_SIZE; j++) {
384 struct list *e;
385 LIST_FOR_EACH(e, &object->lightMap[j]) {
386 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
387 light->changed = TRUE;
388 light->enabledChanged = TRUE;
389 }
390 }
391 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
392 object->contained_render_states[j - 1] = j;
393 }
394 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
395 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
396 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
397 object->contained_transform_states[j - 1] = j;
398 }
399 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
400 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
401 object->contained_vs_consts_f[j] = j;
402 }
403 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
404 for(j = 0; j < MAX_CONST_I; j++) {
405 object->contained_vs_consts_i[j] = j;
406 }
407 object->num_contained_vs_consts_i = MAX_CONST_I;
408 for(j = 0; j < MAX_CONST_B; j++) {
409 object->contained_vs_consts_b[j] = j;
410 }
411 object->num_contained_vs_consts_b = MAX_CONST_B;
412 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
413 object->contained_ps_consts_f[j] = j;
414 }
415 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
416 for(j = 0; j < MAX_CONST_I; j++) {
417 object->contained_ps_consts_i[j] = j;
418 }
419 object->num_contained_ps_consts_i = MAX_CONST_I;
420 for(j = 0; j < MAX_CONST_B; j++) {
421 object->contained_ps_consts_b[j] = j;
422 }
423 object->num_contained_ps_consts_b = MAX_CONST_B;
424 for(i = 0; i < MAX_TEXTURES; i++) {
425 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
426 object->contained_tss_states[object->num_contained_tss_states].stage = i;
427 object->contained_tss_states[object->num_contained_tss_states].state = j;
428 object->num_contained_tss_states++;
429 }
430 }
431 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
432 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
433 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
434 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
435 object->num_contained_sampler_states++;
436 }
437 }
438
439 for(i = 0; i < MAX_STREAMS; i++) {
440 if(object->streamSource[i]) {
441 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
442 }
443 }
444 if(object->pIndexData) {
445 IWineD3DIndexBuffer_AddRef(object->pIndexData);
446 }
447 if(object->vertexShader) {
448 IWineD3DVertexShader_AddRef(object->vertexShader);
449 }
450 if(object->pixelShader) {
451 IWineD3DPixelShader_AddRef(object->pixelShader);
452 }
453
454 } else if (Type == WINED3DSBT_PIXELSTATE) {
455
456 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
457 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
458
459 object->changed.pixelShader = TRUE;
460
461 /* Pixel Shader Constants */
462 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
463 object->contained_ps_consts_f[i] = i;
464 object->changed.pixelShaderConstantsF[i] = TRUE;
465 }
466 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
467 for (i = 0; i < MAX_CONST_B; ++i) {
468 object->contained_ps_consts_b[i] = i;
469 object->changed.pixelShaderConstantsB |= (1 << i);
470 }
471 object->num_contained_ps_consts_b = MAX_CONST_B;
472 for (i = 0; i < MAX_CONST_I; ++i) {
473 object->contained_ps_consts_i[i] = i;
474 object->changed.pixelShaderConstantsI |= (1 << i);
475 }
476 object->num_contained_ps_consts_i = MAX_CONST_I;
477
478 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
479 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
480 object->contained_render_states[i] = SavedPixelStates_R[i];
481 }
482 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
483 for (j = 0; j < MAX_TEXTURES; j++) {
484 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
485 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
486 object->contained_tss_states[object->num_contained_tss_states].stage = j;
487 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
488 object->num_contained_tss_states++;
489 }
490 }
491 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
492 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
493 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
494 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
495 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
496 object->num_contained_sampler_states++;
497 }
498 }
499 if(object->pixelShader) {
500 IWineD3DPixelShader_AddRef(object->pixelShader);
501 }
502
503 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
504 * on them. This makes releasing the buffer easier
505 */
506 for(i = 0; i < MAX_STREAMS; i++) {
507 object->streamSource[i] = NULL;
508 }
509 object->pIndexData = NULL;
510 object->vertexShader = NULL;
511
512 } else if (Type == WINED3DSBT_VERTEXSTATE) {
513
514 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
515 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
516
517 object->changed.vertexShader = TRUE;
518
519 /* Vertex Shader Constants */
520 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
521 object->changed.vertexShaderConstantsF[i] = TRUE;
522 object->contained_vs_consts_f[i] = i;
523 }
524 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
525 for (i = 0; i < MAX_CONST_B; ++i) {
526 object->contained_vs_consts_b[i] = i;
527 object->changed.vertexShaderConstantsB |= (1 << i);
528 }
529 object->num_contained_vs_consts_b = MAX_CONST_B;
530 for (i = 0; i < MAX_CONST_I; ++i) {
531 object->contained_vs_consts_i[i] = i;
532 object->changed.vertexShaderConstantsI |= (1 << i);
533 }
534 object->num_contained_vs_consts_i = MAX_CONST_I;
535 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
536 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
537 object->contained_render_states[i] = SavedVertexStates_R[i];
538 }
539 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
540 for (j = 0; j < MAX_TEXTURES; j++) {
541 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
542 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
543 object->contained_tss_states[object->num_contained_tss_states].stage = j;
544 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
545 object->num_contained_tss_states++;
546 }
547 }
548 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
549 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
550 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
551 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
552 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
553 object->num_contained_sampler_states++;
554 }
555 }
556
557 for(j = 0; j < LIGHTMAP_SIZE; j++) {
558 struct list *e;
559 LIST_FOR_EACH(e, &object->lightMap[j]) {
560 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
561 light->changed = TRUE;
562 light->enabledChanged = TRUE;
563 }
564 }
565
566 for(i = 0; i < MAX_STREAMS; i++) {
567 if(object->streamSource[i]) {
568 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
569 }
570 }
571 if(object->vertexShader) {
572 IWineD3DVertexShader_AddRef(object->vertexShader);
573 }
574 object->pIndexData = NULL;
575 object->pixelShader = NULL;
576 } else {
577 FIXME("Unrecognized state block type %d\n", Type);
578 }
579
580 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
581 return WINED3D_OK;
582}
583
584/* ************************************
585MSDN:
586[in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
587
588Discard
589 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
590
591If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
592
593******************************** */
594
595static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
597 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
598 unsigned int Size = 1;
599 const struct GlPixelFormatDesc *glDesc;
600 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
601 UINT mul_4w, mul_4h;
602 TRACE("(%p) Create surface\n",This);
603
604 /** FIXME: Check ranges on the inputs are valid
605 * MSDN
606 * MultisampleQuality
607 * [in] Quality level. The valid range is between zero and one less than the level
608 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
609 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
610 * values of paired render targets, depth stencil surfaces, and the MultiSample type
611 * must all match.
612 *******************************/
613
614
615 /**
616 * TODO: Discard MSDN
617 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
618 *
619 * If this flag is set, the contents of the depth stencil buffer will be
620 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
621 * with a different depth surface.
622 *
623 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
624 ***************************/
625
626 if(MultisampleQuality > 0) {
627 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
628 MultisampleQuality=0;
629 }
630
631 /** FIXME: Check that the format is supported
632 * by the device.
633 *******************************/
634
635 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
636 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
637 * space!
638 *********************************/
639 mul_4w = (Width + 3) & ~3;
640 mul_4h = (Height + 3) & ~3;
641 if (WINED3DFMT_UNKNOWN == Format) {
642 Size = 0;
643 } else if (Format == WINED3DFMT_DXT1) {
644 /* DXT1 is half byte per pixel */
645 Size = (mul_4w * tableEntry->bpp * mul_4h) >> 1;
646
647 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
648 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
649 Format == WINED3DFMT_ATI2N) {
650 Size = (mul_4w * tableEntry->bpp * mul_4h);
651 } else {
652 /* The pitch is a multiple of 4 bytes */
653 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
654 Size *= Height;
655 }
656
657 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
658
659 /** Create and initialise the surface resource **/
660 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
661 /* "Standalone" surface */
662 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
663
664 object->currentDesc.Width = Width;
665 object->currentDesc.Height = Height;
666 object->currentDesc.MultiSampleType = MultiSample;
667 object->currentDesc.MultiSampleQuality = MultisampleQuality;
668 object->glDescription.level = Level;
669 object->heightscale = glDesc->heightscale != 0.0 ? glDesc->heightscale : 1.0;
670 list_init(&object->overlays);
671
672 /* Flags */
673 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
674 object->Flags |= Discard ? SFLAG_DISCARD : 0;
675 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
676 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
677
678
679 if (WINED3DFMT_UNKNOWN != Format) {
680 object->bytesPerPixel = tableEntry->bpp;
681 } else {
682 object->bytesPerPixel = 0;
683 }
684
685 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
686
687 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
688
689 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
690 * this function is too deep to need to care about things like this.
691 * Levels need to be checked too, and possibly Type since they all affect what can be done.
692 * ****************************************/
693 switch(Pool) {
694 case WINED3DPOOL_SCRATCH:
695 if(!Lockable)
696 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
697 "which are mutually exclusive, setting lockable to TRUE\n");
698 Lockable = TRUE;
699 break;
700 case WINED3DPOOL_SYSTEMMEM:
701 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
702 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
703 case WINED3DPOOL_MANAGED:
704 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
705 "Usage of DYNAMIC which are mutually exclusive, not doing "
706 "anything just telling you.\n");
707 break;
708 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
709 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
710 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
711 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
712 break;
713 default:
714 FIXME("(%p) Unknown pool %d\n", This, Pool);
715 break;
716 };
717
718 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
719 FIXME("Trying to create a render target that isn't in the default pool\n");
720 }
721
722 /* mark the texture as dirty so that it gets loaded first time around*/
723 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
724 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
725 This, Width, Height, Format, debug_d3dformat(Format),
726 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
727
728 /* Look at the implementation and set the correct Vtable */
729 switch(Impl) {
730 case SURFACE_OPENGL:
731 /* Check if a 3D adapter is available when creating gl surfaces */
732 if(!This->adapter) {
733 ERR("OpenGL surfaces are not available without opengl\n");
734 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
735 HeapFree(GetProcessHeap(), 0, object);
736 return WINED3DERR_NOTAVAILABLE;
737 }
738 break;
739
740 case SURFACE_GDI:
741 object->lpVtbl = &IWineGDISurface_Vtbl;
742 break;
743
744 default:
745 /* To be sure to catch this */
746 ERR("Unknown requested surface implementation %d!\n", Impl);
747 IWineD3DSurface_Release((IWineD3DSurface *) object);
748 return WINED3DERR_INVALIDCALL;
749 }
750
751 list_init(&object->renderbuffers);
752
753 /* Call the private setup routine */
754 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
755
756}
757
758static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
759 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
760 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
761 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
762
763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
764 IWineD3DTextureImpl *object;
765 unsigned int i;
766 UINT tmpW;
767 UINT tmpH;
768 HRESULT hr;
769 unsigned int pow2Width;
770 unsigned int pow2Height;
771 const struct GlPixelFormatDesc *glDesc;
772 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
773
774 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
775 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
776 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
777
778 /* TODO: It should only be possible to create textures for formats
779 that are reported as supported */
780 if (WINED3DFMT_UNKNOWN >= Format) {
781 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
782 return WINED3DERR_INVALIDCALL;
783 }
784
785 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
786 D3DINITIALIZEBASETEXTURE(object->baseTexture);
787 object->width = Width;
788 object->height = Height;
789
790 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
791 object->baseTexture.minMipLookup = minMipLookup;
792 object->baseTexture.magLookup = magLookup;
793 } else {
794 object->baseTexture.minMipLookup = minMipLookup_noFilter;
795 object->baseTexture.magLookup = magLookup_noFilter;
796 }
797
798 /** Non-power2 support **/
799 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
800 pow2Width = Width;
801 pow2Height = Height;
802 } else {
803 /* Find the nearest pow2 match */
804 pow2Width = pow2Height = 1;
805 while (pow2Width < Width) pow2Width <<= 1;
806 while (pow2Height < Height) pow2Height <<= 1;
807
808 if(pow2Width != Width || pow2Height != Height) {
809 if(Levels > 1) {
810 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
811 HeapFree(GetProcessHeap(), 0, object);
812 *ppTexture = NULL;
813 return WINED3DERR_INVALIDCALL;
814 } else {
815 Levels = 1;
816 }
817 }
818 }
819
820 /** FIXME: add support for real non-power-two if it's provided by the video card **/
821 /* Precalculated scaling for 'faked' non power of two texture coords.
822 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
823 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
824 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
825 */
826 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
827 object->baseTexture.pow2Matrix[0] = 1.0;
828 object->baseTexture.pow2Matrix[5] = 1.0;
829 object->baseTexture.pow2Matrix[10] = 1.0;
830 object->baseTexture.pow2Matrix[15] = 1.0;
831 object->target = GL_TEXTURE_2D;
832 object->cond_np2 = TRUE;
833 object->baseTexture.minMipLookup = minMipLookup_noFilter;
834 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
835 (Width != pow2Width || Height != pow2Height) &&
836 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
837 {
838 object->baseTexture.pow2Matrix[0] = (float)Width;
839 object->baseTexture.pow2Matrix[5] = (float)Height;
840 object->baseTexture.pow2Matrix[10] = 1.0;
841 object->baseTexture.pow2Matrix[15] = 1.0;
842 object->target = GL_TEXTURE_RECTANGLE_ARB;
843 object->cond_np2 = TRUE;
844 object->baseTexture.minMipLookup = minMipLookup_noFilter;
845 } else {
846 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
847 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
848 object->baseTexture.pow2Matrix[10] = 1.0;
849 object->baseTexture.pow2Matrix[15] = 1.0;
850 object->target = GL_TEXTURE_2D;
851 object->cond_np2 = FALSE;
852 }
853 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
854
855 /* Calculate levels for mip mapping */
856 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
857 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
858 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
859 return WINED3DERR_INVALIDCALL;
860 }
861 if(Levels > 1) {
862 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
863 return WINED3DERR_INVALIDCALL;
864 }
865 object->baseTexture.levels = 1;
866 } else if (Levels == 0) {
867 TRACE("calculating levels %d\n", object->baseTexture.levels);
868 object->baseTexture.levels++;
869 tmpW = Width;
870 tmpH = Height;
871 while (tmpW > 1 || tmpH > 1) {
872 tmpW = max(1, tmpW >> 1);
873 tmpH = max(1, tmpH >> 1);
874 object->baseTexture.levels++;
875 }
876 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
877 }
878
879 /* Generate all the surfaces */
880 tmpW = Width;
881 tmpH = Height;
882 for (i = 0; i < object->baseTexture.levels; i++)
883 {
884 /* use the callback to create the texture surface */
885 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
886 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
887 FIXME("Failed to create surface %p\n", object);
888 /* clean up */
889 object->surfaces[i] = NULL;
890 IWineD3DTexture_Release((IWineD3DTexture *)object);
891
892 *ppTexture = NULL;
893 return hr;
894 }
895
896 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
897 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
898 surface_set_texture_target(object->surfaces[i], object->target);
899 /* calculate the next mipmap level */
900 tmpW = max(1, tmpW >> 1);
901 tmpH = max(1, tmpH >> 1);
902 }
903 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
904
905 TRACE("(%p) : Created texture %p\n", This, object);
906 return WINED3D_OK;
907}
908
909static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
910 UINT Width, UINT Height, UINT Depth,
911 UINT Levels, DWORD Usage,
912 WINED3DFORMAT Format, WINED3DPOOL Pool,
913 IWineD3DVolumeTexture **ppVolumeTexture,
914 HANDLE *pSharedHandle, IUnknown *parent,
915 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
916
917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
918 IWineD3DVolumeTextureImpl *object;
919 unsigned int i;
920 UINT tmpW;
921 UINT tmpH;
922 UINT tmpD;
923 const struct GlPixelFormatDesc *glDesc;
924
925 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
926
927 /* TODO: It should only be possible to create textures for formats
928 that are reported as supported */
929 if (WINED3DFMT_UNKNOWN >= Format) {
930 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
931 return WINED3DERR_INVALIDCALL;
932 }
933 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
934 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
935 return WINED3DERR_INVALIDCALL;
936 }
937
938 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
939 D3DINITIALIZEBASETEXTURE(object->baseTexture);
940
941 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
942 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
943
944 /* Is NP2 support for volumes needed? */
945 object->baseTexture.pow2Matrix[ 0] = 1.0;
946 object->baseTexture.pow2Matrix[ 5] = 1.0;
947 object->baseTexture.pow2Matrix[10] = 1.0;
948 object->baseTexture.pow2Matrix[15] = 1.0;
949
950 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
951 object->baseTexture.minMipLookup = minMipLookup;
952 object->baseTexture.magLookup = magLookup;
953 } else {
954 object->baseTexture.minMipLookup = minMipLookup_noFilter;
955 object->baseTexture.magLookup = magLookup_noFilter;
956 }
957
958 /* Calculate levels for mip mapping */
959 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
960 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
961 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
962 return WINED3DERR_INVALIDCALL;
963 }
964 if(Levels > 1) {
965 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
966 return WINED3DERR_INVALIDCALL;
967 }
968 object->baseTexture.levels = 1;
969 } else if (Levels == 0) {
970 object->baseTexture.levels++;
971 tmpW = Width;
972 tmpH = Height;
973 tmpD = Depth;
974 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
975 tmpW = max(1, tmpW >> 1);
976 tmpH = max(1, tmpH >> 1);
977 tmpD = max(1, tmpD >> 1);
978 object->baseTexture.levels++;
979 }
980 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
981 }
982
983 /* Generate all the surfaces */
984 tmpW = Width;
985 tmpH = Height;
986 tmpD = Depth;
987
988 for (i = 0; i < object->baseTexture.levels; i++)
989 {
990 HRESULT hr;
991 /* Create the volume */
992 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
993 &object->volumes[i], pSharedHandle);
994
995 if(FAILED(hr)) {
996 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
997 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
998 *ppVolumeTexture = NULL;
999 return hr;
1000 }
1001
1002 /* Set its container to this object */
1003 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1004
1005 /* calculate the next mipmap level */
1006 tmpW = max(1, tmpW >> 1);
1007 tmpH = max(1, tmpH >> 1);
1008 tmpD = max(1, tmpD >> 1);
1009 }
1010 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
1011
1012 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1013 TRACE("(%p) : Created volume texture %p\n", This, object);
1014 return WINED3D_OK;
1015}
1016
1017static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1018 UINT Width, UINT Height, UINT Depth,
1019 DWORD Usage,
1020 WINED3DFORMAT Format, WINED3DPOOL Pool,
1021 IWineD3DVolume** ppVolume,
1022 HANDLE* pSharedHandle, IUnknown *parent) {
1023
1024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1025 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1026 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1027
1028 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1029 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1030 return WINED3DERR_INVALIDCALL;
1031 }
1032
1033 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1034
1035 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1036 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1037
1038 object->currentDesc.Width = Width;
1039 object->currentDesc.Height = Height;
1040 object->currentDesc.Depth = Depth;
1041 object->bytesPerPixel = formatDesc->bpp;
1042
1043 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1044 object->lockable = TRUE;
1045 object->locked = FALSE;
1046 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1047 object->dirty = TRUE;
1048
1049 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1050}
1051
1052static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1053 UINT Levels, DWORD Usage,
1054 WINED3DFORMAT Format, WINED3DPOOL Pool,
1055 IWineD3DCubeTexture **ppCubeTexture,
1056 HANDLE *pSharedHandle, IUnknown *parent,
1057 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1058
1059 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1060 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1061 unsigned int i, j;
1062 UINT tmpW;
1063 HRESULT hr;
1064 unsigned int pow2EdgeLength;
1065 const struct GlPixelFormatDesc *glDesc;
1066 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1067
1068 /* TODO: It should only be possible to create textures for formats
1069 that are reported as supported */
1070 if (WINED3DFMT_UNKNOWN >= Format) {
1071 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1072 return WINED3DERR_INVALIDCALL;
1073 }
1074
1075 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1076 WARN("(%p) : Tried to create not supported cube texture\n", This);
1077 return WINED3DERR_INVALIDCALL;
1078 }
1079
1080 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1081 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1082
1083 TRACE("(%p) Create Cube Texture\n", This);
1084
1085 /* Find the nearest pow2 match */
1086 pow2EdgeLength = 1;
1087 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1088
1089 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
1090 /* Precalculated scaling for 'faked' non power of two texture coords */
1091 object->baseTexture.pow2Matrix[ 0] = 1.0;
1092 object->baseTexture.pow2Matrix[ 5] = 1.0;
1093 object->baseTexture.pow2Matrix[10] = 1.0;
1094 object->baseTexture.pow2Matrix[15] = 1.0;
1095 } else {
1096 /* Precalculated scaling for 'faked' non power of two texture coords */
1097 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1098 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1099 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1100 object->baseTexture.pow2Matrix[15] = 1.0;
1101 }
1102
1103 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1104 object->baseTexture.minMipLookup = minMipLookup;
1105 object->baseTexture.magLookup = magLookup;
1106 } else {
1107 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1108 object->baseTexture.magLookup = magLookup_noFilter;
1109 }
1110
1111 /* Calculate levels for mip mapping */
1112 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1113 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1114 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1115 HeapFree(GetProcessHeap(), 0, object);
1116 *ppCubeTexture = NULL;
1117
1118 return WINED3DERR_INVALIDCALL;
1119 }
1120 if(Levels > 1) {
1121 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1122 HeapFree(GetProcessHeap(), 0, object);
1123 *ppCubeTexture = NULL;
1124
1125 return WINED3DERR_INVALIDCALL;
1126 }
1127 object->baseTexture.levels = 1;
1128 } else if (Levels == 0) {
1129 object->baseTexture.levels++;
1130 tmpW = EdgeLength;
1131 while (tmpW > 1) {
1132 tmpW = max(1, tmpW >> 1);
1133 object->baseTexture.levels++;
1134 }
1135 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1136 }
1137
1138 /* Generate all the surfaces */
1139 tmpW = EdgeLength;
1140 for (i = 0; i < object->baseTexture.levels; i++) {
1141
1142 /* Create the 6 faces */
1143 for (j = 0; j < 6; j++) {
1144 static const GLenum cube_targets[6] = {
1145 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1146 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1147 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1148 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1149 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1150 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1151 };
1152
1153 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1154 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1155
1156 if(hr!= WINED3D_OK) {
1157 /* clean up */
1158 unsigned int k;
1159 unsigned int l;
1160 for (l = 0; l < j; l++) {
1161 IWineD3DSurface_Release(object->surfaces[l][i]);
1162 }
1163 for (k = 0; k < i; k++) {
1164 for (l = 0; l < 6; l++) {
1165 IWineD3DSurface_Release(object->surfaces[l][k]);
1166 }
1167 }
1168
1169 FIXME("(%p) Failed to create surface\n",object);
1170 HeapFree(GetProcessHeap(),0,object);
1171 *ppCubeTexture = NULL;
1172 return hr;
1173 }
1174 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1175 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1176 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1177 }
1178 tmpW = max(1, tmpW >> 1);
1179 }
1180 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
1181
1182 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1183 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1184 return WINED3D_OK;
1185}
1186
1187static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1189 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1190 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1191 const IWineD3DQueryVtbl *vtable;
1192
1193 /* Just a check to see if we support this type of query */
1194 switch(Type) {
1195 case WINED3DQUERYTYPE_OCCLUSION:
1196 TRACE("(%p) occlusion query\n", This);
1197 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1198 hr = WINED3D_OK;
1199 else
1200 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1201
1202 vtable = &IWineD3DOcclusionQuery_Vtbl;
1203 break;
1204
1205 case WINED3DQUERYTYPE_EVENT:
1206 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1207 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1208 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1209 */
1210 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1211 }
1212 vtable = &IWineD3DEventQuery_Vtbl;
1213 hr = WINED3D_OK;
1214 break;
1215
1216 case WINED3DQUERYTYPE_VCACHE:
1217 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1218 case WINED3DQUERYTYPE_VERTEXSTATS:
1219 case WINED3DQUERYTYPE_TIMESTAMP:
1220 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1221 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1222 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1223 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1224 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1225 case WINED3DQUERYTYPE_PIXELTIMINGS:
1226 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1227 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1228 default:
1229 /* Use the base Query vtable until we have a special one for each query */
1230 vtable = &IWineD3DQuery_Vtbl;
1231 FIXME("(%p) Unhandled query type %d\n", This, Type);
1232 }
1233 if(NULL == ppQuery || hr != WINED3D_OK) {
1234 return hr;
1235 }
1236
1237 D3DCREATEOBJECTINSTANCE(object, Query)
1238 object->lpVtbl = vtable;
1239 object->type = Type;
1240 object->state = QUERY_CREATED;
1241 /* allocated the 'extended' data based on the type of query requested */
1242 switch(Type){
1243 case WINED3DQUERYTYPE_OCCLUSION:
1244 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1245 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1246
1247 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1248 TRACE("(%p) Allocating data for an occlusion query\n", This);
1249
1250 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1251 ENTER_GL();
1252 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1253 LEAVE_GL();
1254 break;
1255 }
1256 case WINED3DQUERYTYPE_EVENT:
1257 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1258 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1259
1260 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1261 ENTER_GL();
1262 if(GL_SUPPORT(APPLE_FENCE)) {
1263 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1264 checkGLcall("glGenFencesAPPLE");
1265 } else if(GL_SUPPORT(NV_FENCE)) {
1266 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1267 checkGLcall("glGenFencesNV");
1268 }
1269 LEAVE_GL();
1270 break;
1271
1272 case WINED3DQUERYTYPE_VCACHE:
1273 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1274 case WINED3DQUERYTYPE_VERTEXSTATS:
1275 case WINED3DQUERYTYPE_TIMESTAMP:
1276 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1277 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1278 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1279 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1280 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1281 case WINED3DQUERYTYPE_PIXELTIMINGS:
1282 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1283 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1284 default:
1285 object->extendedData = 0;
1286 FIXME("(%p) Unhandled query type %d\n",This , Type);
1287 }
1288 TRACE("(%p) : Created Query %p\n", This, object);
1289 return WINED3D_OK;
1290}
1291
1292/*****************************************************************************
1293 * IWineD3DDeviceImpl_SetupFullscreenWindow
1294 *
1295 * Helper function that modifies a HWND's Style and ExStyle for proper
1296 * fullscreen use.
1297 *
1298 * Params:
1299 * iface: Pointer to the IWineD3DDevice interface
1300 * window: Window to setup
1301 *
1302 *****************************************************************************/
1303static LONG fullscreen_style(LONG orig_style) {
1304 LONG style = orig_style;
1305 style &= ~WS_CAPTION;
1306 style &= ~WS_THICKFRAME;
1307
1308 /* Make sure the window is managed, otherwise we won't get keyboard input */
1309 style |= WS_POPUP | WS_SYSMENU;
1310
1311 return style;
1312}
1313
1314static LONG fullscreen_exStyle(LONG orig_exStyle) {
1315 LONG exStyle = orig_exStyle;
1316
1317 /* Filter out window decorations */
1318 exStyle &= ~WS_EX_WINDOWEDGE;
1319 exStyle &= ~WS_EX_CLIENTEDGE;
1320
1321 return exStyle;
1322}
1323
1324static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1326
1327 LONG style, exStyle;
1328 /* Don't do anything if an original style is stored.
1329 * That shouldn't happen
1330 */
1331 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1332 if (This->style || This->exStyle) {
1333 ERR("(%p): Want to change the window parameters of HWND %p, but "
1334 "another style is stored for restoration afterwards\n", This, window);
1335 }
1336
1337 /* Get the parameters and save them */
1338 style = GetWindowLongW(window, GWL_STYLE);
1339 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1340 This->style = style;
1341 This->exStyle = exStyle;
1342
1343 style = fullscreen_style(style);
1344 exStyle = fullscreen_exStyle(exStyle);
1345
1346 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1347 This->style, This->exStyle, style, exStyle);
1348
1349 SetWindowLongW(window, GWL_STYLE, style);
1350 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1351
1352 /* Inform the window about the update. */
1353 SetWindowPos(window, HWND_TOP, 0, 0,
1354 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1355}
1356
1357/*****************************************************************************
1358 * IWineD3DDeviceImpl_RestoreWindow
1359 *
1360 * Helper function that restores a windows' properties when taking it out
1361 * of fullscreen mode
1362 *
1363 * Params:
1364 * iface: Pointer to the IWineD3DDevice interface
1365 * window: Window to setup
1366 *
1367 *****************************************************************************/
1368static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1370 LONG style, exStyle;
1371
1372 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1373 * switch, do nothing
1374 */
1375 if (!This->style && !This->exStyle) return;
1376
1377 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1378 This, window, This->style, This->exStyle);
1379
1380 style = GetWindowLongW(window, GWL_STYLE);
1381 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1382
1383 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1384 * Some applications change it before calling Reset() when switching between windowed and
1385 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1386 */
1387 if(style == fullscreen_style(This->style) &&
1388 exStyle == fullscreen_style(This->exStyle)) {
1389 SetWindowLongW(window, GWL_STYLE, This->style);
1390 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1391 }
1392
1393 /* Delete the old values */
1394 This->style = 0;
1395 This->exStyle = 0;
1396
1397 /* Inform the window about the update */
1398 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1399 0, 0, 0, 0, /* Pos, Size, ignored */
1400 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1401}
1402
1403/* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1404static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice* iface,
1405 WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1406 IUnknown* parent, D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1407 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil, WINED3DSURFTYPE surface_type)
1408{
1409 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1410
1411 HDC hDc;
1412 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1413 HRESULT hr;
1414 IUnknown *bufferParent;
1415 BOOL displaymode_set = FALSE;
1416 WINED3DDISPLAYMODE Mode;
1417 const StaticPixelFormatDesc *formatDesc;
1418
1419 TRACE("(%p) : Created Additional Swap Chain\n", This);
1420
1421 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1422 * does a device hold a reference to a swap chain giving them a lifetime of the device
1423 * or does the swap chain notify the device of its destruction.
1424 *******************************/
1425
1426 /* Check the params */
1427 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1428 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1429 return WINED3DERR_INVALIDCALL;
1430 } else if (pPresentationParameters->BackBufferCount > 1) {
1431 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1432 }
1433
1434 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1435 switch(surface_type) {
1436 case SURFACE_GDI:
1437 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1438 break;
1439 case SURFACE_OPENGL:
1440 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1441 break;
1442 case SURFACE_UNKNOWN:
1443 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1444 return WINED3DERR_INVALIDCALL;
1445 }
1446
1447 /*********************
1448 * Lookup the window Handle and the relating X window handle
1449 ********************/
1450
1451 /* Setup hwnd we are using, plus which display this equates to */
1452 object->win_handle = pPresentationParameters->hDeviceWindow;
1453 if (!object->win_handle) {
1454 object->win_handle = This->createParms.hFocusWindow;
1455 }
1456 if(!pPresentationParameters->Windowed && object->win_handle) {
1457 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1458 pPresentationParameters->BackBufferWidth,
1459 pPresentationParameters->BackBufferHeight);
1460 }
1461
1462 hDc = GetDC(object->win_handle);
1463 TRACE("Using hDc %p\n", hDc);
1464
1465 if (NULL == hDc) {
1466 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1467 return WINED3DERR_NOTAVAILABLE;
1468 }
1469
1470 /* Get info on the current display setup */
1471 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1472 object->orig_width = Mode.Width;
1473 object->orig_height = Mode.Height;
1474 object->orig_fmt = Mode.Format;
1475 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1476
1477 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1478 * then the corresponding dimension of the client area of the hDeviceWindow
1479 * (or the focus window, if hDeviceWindow is NULL) is taken.
1480 **********************/
1481
1482 if (pPresentationParameters->Windowed &&
1483 ((pPresentationParameters->BackBufferWidth == 0) ||
1484 (pPresentationParameters->BackBufferHeight == 0) ||
1485 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1486
1487 RECT Rect;
1488 GetClientRect(object->win_handle, &Rect);
1489
1490 if (pPresentationParameters->BackBufferWidth == 0) {
1491 pPresentationParameters->BackBufferWidth = Rect.right;
1492 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1493 }
1494 if (pPresentationParameters->BackBufferHeight == 0) {
1495 pPresentationParameters->BackBufferHeight = Rect.bottom;
1496 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1497 }
1498 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1499 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1500 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1501 }
1502 }
1503
1504 /* Put the correct figures in the presentation parameters */
1505 TRACE("Copying across presentation parameters\n");
1506 object->presentParms = *pPresentationParameters;
1507
1508 TRACE("calling rendertarget CB\n");
1509 hr = D3DCB_CreateRenderTarget(This->parent,
1510 parent,
1511 object->presentParms.BackBufferWidth,
1512 object->presentParms.BackBufferHeight,
1513 object->presentParms.BackBufferFormat,
1514 object->presentParms.MultiSampleType,
1515 object->presentParms.MultiSampleQuality,
1516 TRUE /* Lockable */,
1517 &object->frontBuffer,
1518 NULL /* pShared (always null)*/);
1519 if (SUCCEEDED(hr)) {
1520 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1521 if(surface_type == SURFACE_OPENGL) {
1522 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1523 }
1524 } else {
1525 ERR("Failed to create the front buffer\n");
1526 goto error;
1527 }
1528
1529 /*********************
1530 * Windowed / Fullscreen
1531 *******************/
1532
1533 /**
1534 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1535 * so we should really check to see if there is a fullscreen swapchain already
1536 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1537 **************************************/
1538
1539 if (!pPresentationParameters->Windowed) {
1540 WINED3DDISPLAYMODE mode;
1541
1542
1543 /* Change the display settings */
1544 mode.Width = pPresentationParameters->BackBufferWidth;
1545 mode.Height = pPresentationParameters->BackBufferHeight;
1546 mode.Format = pPresentationParameters->BackBufferFormat;
1547 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1548
1549 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1550 displaymode_set = TRUE;
1551 }
1552
1553 /**
1554 * Create an opengl context for the display visual
1555 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1556 * use different properties after that point in time. FIXME: How to handle when requested format
1557 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1558 * it chooses is identical to the one already being used!
1559 **********************************/
1560 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1561
1562 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1563 if(!object->context) {
1564 ERR("Failed to create the context array\n");
1565 hr = E_OUTOFMEMORY;
1566 goto error;
1567 }
1568 object->num_contexts = 1;
1569
1570 if(surface_type == SURFACE_OPENGL) {
1571 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1572 if (!object->context[0]) {
1573 ERR("Failed to create a new context\n");
1574 hr = WINED3DERR_NOTAVAILABLE;
1575 goto error;
1576 } else {
1577 TRACE("Context created (HWND=%p, glContext=%p)\n",
1578 object->win_handle, object->context[0]->glCtx);
1579 }
1580 }
1581
1582 /*********************
1583 * Create the back, front and stencil buffers
1584 *******************/
1585 if(object->presentParms.BackBufferCount > 0) {
1586 UINT i;
1587
1588 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1589 if(!object->backBuffer) {
1590 ERR("Out of memory\n");
1591 hr = E_OUTOFMEMORY;
1592 goto error;
1593 }
1594
1595 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1596 TRACE("calling rendertarget CB\n");
1597 hr = D3DCB_CreateRenderTarget(This->parent,
1598 parent,
1599 object->presentParms.BackBufferWidth,
1600 object->presentParms.BackBufferHeight,
1601 object->presentParms.BackBufferFormat,
1602 object->presentParms.MultiSampleType,
1603 object->presentParms.MultiSampleQuality,
1604 TRUE /* Lockable */,
1605 &object->backBuffer[i],
1606 NULL /* pShared (always null)*/);
1607 if(SUCCEEDED(hr)) {
1608 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1609 } else {
1610 ERR("Cannot create new back buffer\n");
1611 goto error;
1612 }
1613 if(surface_type == SURFACE_OPENGL) {
1614 ENTER_GL();
1615 glDrawBuffer(GL_BACK);
1616 checkGLcall("glDrawBuffer(GL_BACK)");
1617 LEAVE_GL();
1618 }
1619 }
1620 } else {
1621 object->backBuffer = NULL;
1622
1623 /* Single buffering - draw to front buffer */
1624 if(surface_type == SURFACE_OPENGL) {
1625 ENTER_GL();
1626 glDrawBuffer(GL_FRONT);
1627 checkGLcall("glDrawBuffer(GL_FRONT)");
1628 LEAVE_GL();
1629 }
1630 }
1631
1632 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1633 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1634 TRACE("Creating depth stencil buffer\n");
1635 if (This->auto_depth_stencil_buffer == NULL ) {
1636 hr = D3DCB_CreateDepthStencil(This->parent,
1637 parent,
1638 object->presentParms.BackBufferWidth,
1639 object->presentParms.BackBufferHeight,
1640 object->presentParms.AutoDepthStencilFormat,
1641 object->presentParms.MultiSampleType,
1642 object->presentParms.MultiSampleQuality,
1643 FALSE /* FIXME: Discard */,
1644 &This->auto_depth_stencil_buffer,
1645 NULL /* pShared (always null)*/ );
1646 if (SUCCEEDED(hr)) {
1647 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1648 } else {
1649 ERR("Failed to create the auto depth stencil\n");
1650 goto error;
1651 }
1652 }
1653 }
1654
1655 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1656
1657 TRACE("Created swapchain %p\n", object);
1658 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1659 return WINED3D_OK;
1660
1661error:
1662 if (displaymode_set) {
1663 DEVMODEW devmode;
1664 RECT clip_rc;
1665
1666 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1667 ClipCursor(NULL);
1668
1669 /* Change the display settings */
1670 memset(&devmode, 0, sizeof(devmode));
1671 devmode.dmSize = sizeof(devmode);
1672 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1673 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1674 devmode.dmPelsWidth = object->orig_width;
1675 devmode.dmPelsHeight = object->orig_height;
1676 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1677 }
1678
1679 if (object->backBuffer) {
1680 UINT i;
1681 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1682 if(object->backBuffer[i]) {
1683 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1684 IUnknown_Release(bufferParent); /* once for the get parent */
1685 if (IUnknown_Release(bufferParent) > 0) {
1686 FIXME("(%p) Something's still holding the back buffer\n",This);
1687 }
1688 }
1689 }
1690 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1691 object->backBuffer = NULL;
1692 }
1693 if(object->context && object->context[0])
1694 DestroyContext(This, object->context[0]);
1695 if(object->frontBuffer) {
1696 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1697 IUnknown_Release(bufferParent); /* once for the get parent */
1698 if (IUnknown_Release(bufferParent) > 0) {
1699 FIXME("(%p) Something's still holding the front buffer\n",This);
1700 }
1701 }
1702 HeapFree(GetProcessHeap(), 0, object);
1703 return hr;
1704}
1705
1706/** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1707static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1709 TRACE("(%p)\n", This);
1710
1711 return This->NumberOfSwapChains;
1712}
1713
1714static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1716 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1717
1718 if(iSwapChain < This->NumberOfSwapChains) {
1719 *pSwapChain = This->swapchains[iSwapChain];
1720 IWineD3DSwapChain_AddRef(*pSwapChain);
1721 TRACE("(%p) returning %p\n", This, *pSwapChain);
1722 return WINED3D_OK;
1723 } else {
1724 TRACE("Swapchain out of range\n");
1725 *pSwapChain = NULL;
1726 return WINED3DERR_INVALIDCALL;
1727 }
1728}
1729
1730/*****
1731 * Vertex Declaration
1732 *****/
1733static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1734 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1736 IWineD3DVertexDeclarationImpl *object = NULL;
1737 HRESULT hr = WINED3D_OK;
1738
1739 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1740 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1741
1742 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1743
1744 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1745 if(FAILED(hr)) {
1746 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1747 *ppVertexDeclaration = NULL;
1748 }
1749
1750 return hr;
1751}
1752
1753static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1754 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1755
1756 unsigned int idx, idx2;
1757 unsigned int offset;
1758 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1759 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1760 BOOL has_blend_idx = has_blend &&
1761 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1762 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1763 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1764 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1765 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1766 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1767 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1768
1769 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1770 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1771
1772 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1773 WINED3DVERTEXELEMENT *elements = NULL;
1774
1775 unsigned int size;
1776 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1777 if (has_blend_idx) num_blends--;
1778
1779 /* Compute declaration size */
1780 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1781 has_psize + has_diffuse + has_specular + num_textures + 1;
1782
1783 /* convert the declaration */
1784 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1785 if (!elements)
1786 return 0;
1787
1788 elements[size-1] = end_element;
1789 idx = 0;
1790 if (has_pos) {
1791 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1792 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1793 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1794 }
1795 else {
1796 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1797 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1798 }
1799 elements[idx].UsageIndex = 0;
1800 idx++;
1801 }
1802 if (has_blend && (num_blends > 0)) {
1803 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1804 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1805 else {
1806 switch(num_blends) {
1807 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
1808 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
1809 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
1810 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
1811 default:
1812 ERR("Unexpected amount of blend values: %u\n", num_blends);
1813 }
1814 }
1815 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1816 elements[idx].UsageIndex = 0;
1817 idx++;
1818 }
1819 if (has_blend_idx) {
1820 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1821 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1822 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1823 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1824 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1825 else
1826 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1827 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1828 elements[idx].UsageIndex = 0;
1829 idx++;
1830 }
1831 if (has_normal) {
1832 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1833 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1834 elements[idx].UsageIndex = 0;
1835 idx++;
1836 }
1837 if (has_psize) {
1838 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1839 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1840 elements[idx].UsageIndex = 0;
1841 idx++;
1842 }
1843 if (has_diffuse) {
1844 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1845 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1846 elements[idx].UsageIndex = 0;
1847 idx++;
1848 }
1849 if (has_specular) {
1850 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1851 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1852 elements[idx].UsageIndex = 1;
1853 idx++;
1854 }
1855 for (idx2 = 0; idx2 < num_textures; idx2++) {
1856 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1857 switch (numcoords) {
1858 case WINED3DFVF_TEXTUREFORMAT1:
1859 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1860 break;
1861 case WINED3DFVF_TEXTUREFORMAT2:
1862 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1863 break;
1864 case WINED3DFVF_TEXTUREFORMAT3:
1865 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1866 break;
1867 case WINED3DFVF_TEXTUREFORMAT4:
1868 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1869 break;
1870 }
1871 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1872 elements[idx].UsageIndex = idx2;
1873 idx++;
1874 }
1875
1876 /* Now compute offsets, and initialize the rest of the fields */
1877 for (idx = 0, offset = 0; idx < size-1; idx++) {
1878 elements[idx].Stream = 0;
1879 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1880 elements[idx].Offset = offset;
1881 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1882 }
1883
1884 *ppVertexElements = elements;
1885 return size;
1886}
1887
1888static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1889 WINED3DVERTEXELEMENT* elements = NULL;
1890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1891 unsigned int size;
1892 DWORD hr;
1893
1894 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1895 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1896
1897 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1898 HeapFree(GetProcessHeap(), 0, elements);
1899 if (hr != S_OK) return hr;
1900
1901 return WINED3D_OK;
1902}
1903
1904static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1906 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1907 HRESULT hr = WINED3D_OK;
1908 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1909 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1910
1911 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1912
1913 if (vertex_declaration) {
1914 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1915 }
1916
1917 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1918
1919 if (WINED3D_OK != hr) {
1920 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1921 IWineD3DVertexShader_Release(*ppVertexShader);
1922 return WINED3DERR_INVALIDCALL;
1923 }
1924 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1925
1926 return WINED3D_OK;
1927}
1928
1929static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1931 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1932 HRESULT hr = WINED3D_OK;
1933
1934 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1935 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1936 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1937 if (WINED3D_OK == hr) {
1938 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1939 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1940 } else {
1941 WARN("(%p) : Failed to create pixel shader\n", This);
1942 }
1943
1944 return hr;
1945}
1946
1947static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1948 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1949{
1950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1951 IWineD3DPaletteImpl *object;
1952 HRESULT hr;
1953 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1954
1955 /* Create the new object */
1956 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1957 if(!object) {
1958 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1959 return E_OUTOFMEMORY;
1960 }
1961
1962 object->lpVtbl = &IWineD3DPalette_Vtbl;
1963 object->ref = 1;
1964 object->Flags = Flags;
1965 object->parent = Parent;
1966 object->wineD3DDevice = This;
1967 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1968
1969 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1970
1971 if(!object->hpal) {
1972 HeapFree( GetProcessHeap(), 0, object);
1973 return E_OUTOFMEMORY;
1974 }
1975
1976 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1977 if(FAILED(hr)) {
1978 IWineD3DPalette_Release((IWineD3DPalette *) object);
1979 return hr;
1980 }
1981
1982 *Palette = (IWineD3DPalette *) object;
1983
1984 return WINED3D_OK;
1985}
1986
1987static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1988 HBITMAP hbm;
1989 BITMAP bm;
1990 HRESULT hr;
1991 HDC dcb = NULL, dcs = NULL;
1992 WINEDDCOLORKEY colorkey;
1993
1994 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1995 if(hbm)
1996 {
1997 GetObjectA(hbm, sizeof(BITMAP), &bm);
1998 dcb = CreateCompatibleDC(NULL);
1999 if(!dcb) goto out;
2000 SelectObject(dcb, hbm);
2001 }
2002 else
2003 {
2004 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2005 * couldn't be loaded
2006 */
2007 memset(&bm, 0, sizeof(bm));
2008 bm.bmWidth = 32;
2009 bm.bmHeight = 32;
2010 }
2011
2012 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2013 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2014 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
2015 if(FAILED(hr)) {
2016 ERR("Wine logo requested, but failed to create surface\n");
2017 goto out;
2018 }
2019
2020 if(dcb) {
2021 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2022 if(FAILED(hr)) goto out;
2023 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2024 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2025
2026 colorkey.dwColorSpaceLowValue = 0;
2027 colorkey.dwColorSpaceHighValue = 0;
2028 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2029 } else {
2030 /* Fill the surface with a white color to show that wined3d is there */
2031 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2032 }
2033
2034 out:
2035 if(dcb) {
2036 DeleteDC(dcb);
2037 }
2038 if(hbm) {
2039 DeleteObject(hbm);
2040 }
2041 return;
2042}
2043
2044static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2045 unsigned int i;
2046 /* Under DirectX you can have texture stage operations even if no texture is
2047 bound, whereas opengl will only do texture operations when a valid texture is
2048 bound. We emulate this by creating dummy textures and binding them to each
2049 texture stage, but disable all stages by default. Hence if a stage is enabled
2050 then the default texture will kick in until replaced by a SetTexture call */
2051 ENTER_GL();
2052
2053 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2054 /* The dummy texture does not have client storage backing */
2055 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2056 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2057 }
2058 for (i = 0; i < GL_LIMITS(textures); i++) {
2059 GLubyte white = 255;
2060
2061 /* Make appropriate texture active */
2062 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2063 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2064 checkGLcall("glActiveTextureARB");
2065 } else if (i > 0) {
2066 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2067 }
2068
2069 /* Generate an opengl texture name */
2070 glGenTextures(1, &This->dummyTextureName[i]);
2071 checkGLcall("glGenTextures");
2072 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2073
2074 /* Generate a dummy 2d texture (not using 1d because they cause many
2075 * DRI drivers fall back to sw) */
2076 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2077 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2078 checkGLcall("glBindTexture");
2079
2080 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2081 checkGLcall("glTexImage2D");
2082 }
2083 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2084 /* Reenable because if supported it is enabled by default */
2085 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2086 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2087 }
2088
2089 LEAVE_GL();
2090}
2091
2092static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2094 IWineD3DSwapChainImpl *swapchain = NULL;
2095 HRESULT hr;
2096 DWORD state;
2097 unsigned int i;
2098
2099 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateSwapChain);
2100 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2101 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2102
2103 /* TODO: Test if OpenGL is compiled in and loaded */
2104
2105 TRACE("(%p) : Creating stateblock\n", This);
2106 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2107 hr = IWineD3DDevice_CreateStateBlock(iface,
2108 WINED3DSBT_INIT,
2109 (IWineD3DStateBlock **)&This->stateBlock,
2110 NULL);
2111 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2112 WARN("Failed to create stateblock\n");
2113 goto err_out;
2114 }
2115 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2116 This->updateStateBlock = This->stateBlock;
2117 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2118
2119 hr = allocate_shader_constants(This->updateStateBlock);
2120 if (WINED3D_OK != hr) {
2121 goto err_out;
2122 }
2123
2124 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2125 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2126
2127 This->NumberOfPalettes = 1;
2128 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2129 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2130 ERR("Out of memory!\n");
2131 goto err_out;
2132 }
2133 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2134 if(!This->palettes[0]) {
2135 ERR("Out of memory!\n");
2136 goto err_out;
2137 }
2138 for (i = 0; i < 256; ++i) {
2139 This->palettes[0][i].peRed = 0xFF;
2140 This->palettes[0][i].peGreen = 0xFF;
2141 This->palettes[0][i].peBlue = 0xFF;
2142 This->palettes[0][i].peFlags = 0xFF;
2143 }
2144 This->currentPalette = 0;
2145
2146 /* Initialize the texture unit mapping to a 1:1 mapping */
2147 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2148 if (state < GL_LIMITS(fragment_samplers)) {
2149 This->texUnitMap[state] = state;
2150 This->rev_tex_unit_map[state] = state;
2151 } else {
2152 This->texUnitMap[state] = -1;
2153 This->rev_tex_unit_map[state] = -1;
2154 }
2155 }
2156
2157 /* Setup the implicit swapchain */
2158 TRACE("Creating implicit swapchain\n");
2159 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2160 if (FAILED(hr) || !swapchain) {
2161 WARN("Failed to create implicit swapchain\n");
2162 goto err_out;
2163 }
2164
2165 This->NumberOfSwapChains = 1;
2166 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2167 if(!This->swapchains) {
2168 ERR("Out of memory!\n");
2169 goto err_out;
2170 }
2171 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2172
2173 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2174 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2175 This->render_targets[0] = swapchain->backBuffer[0];
2176 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2177 }
2178 else {
2179 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2180 This->render_targets[0] = swapchain->frontBuffer;
2181 This->lastActiveRenderTarget = swapchain->frontBuffer;
2182 }
2183 IWineD3DSurface_AddRef(This->render_targets[0]);
2184 This->activeContext = swapchain->context[0];
2185 This->lastThread = GetCurrentThreadId();
2186
2187 /* Depth Stencil support */
2188 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2189 if (NULL != This->stencilBufferTarget) {
2190 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2191 }
2192
2193 hr = This->shader_backend->shader_alloc_private(iface);
2194 if(FAILED(hr)) {
2195 TRACE("Shader private data couldn't be allocated\n");
2196 goto err_out;
2197 }
2198 hr = This->frag_pipe->alloc_private(iface);
2199 if(FAILED(hr)) {
2200 TRACE("Fragment pipeline private data couldn't be allocated\n");
2201 goto err_out;
2202 }
2203 hr = This->blitter->alloc_private(iface);
2204 if(FAILED(hr)) {
2205 TRACE("Blitter private data couldn't be allocated\n");
2206 goto err_out;
2207 }
2208
2209 /* Set up some starting GL setup */
2210
2211 /* Setup all the devices defaults */
2212 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2213 create_dummy_textures(This);
2214
2215 ENTER_GL();
2216
2217 { /* Set a default viewport */
2218 WINED3DVIEWPORT vp;
2219 vp.X = 0;
2220 vp.Y = 0;
2221 vp.Width = pPresentationParameters->BackBufferWidth;
2222 vp.Height = pPresentationParameters->BackBufferHeight;
2223 vp.MinZ = 0.0f;
2224 vp.MaxZ = 1.0f;
2225 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2226 }
2227
2228 /* Initialize the current view state */
2229 This->view_ident = 1;
2230 This->contexts[0]->last_was_rhw = 0;
2231 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2232 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2233
2234 switch(wined3d_settings.offscreen_rendering_mode) {
2235 case ORM_FBO:
2236 case ORM_PBUFFER:
2237 This->offscreenBuffer = GL_BACK;
2238 break;
2239
2240 case ORM_BACKBUFFER:
2241 {
2242 if(This->activeContext->aux_buffers > 0) {
2243 TRACE("Using auxilliary buffer for offscreen rendering\n");
2244 This->offscreenBuffer = GL_AUX0;
2245 } else {
2246 TRACE("Using back buffer for offscreen rendering\n");
2247 This->offscreenBuffer = GL_BACK;
2248 }
2249 }
2250 }
2251
2252 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2253 LEAVE_GL();
2254
2255 /* Clear the screen */
2256 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2257 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2258 0x00, 1.0, 0);
2259
2260 This->d3d_initialized = TRUE;
2261
2262 if(wined3d_settings.logo) {
2263 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2264 }
2265 This->highest_dirty_ps_const = 0;
2266 This->highest_dirty_vs_const = 0;
2267 return WINED3D_OK;
2268
2269err_out:
2270 HeapFree(GetProcessHeap(), 0, This->render_targets);
2271 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2272 HeapFree(GetProcessHeap(), 0, This->swapchains);
2273 This->NumberOfSwapChains = 0;
2274 if(This->palettes) {
2275 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2276 HeapFree(GetProcessHeap(), 0, This->palettes);
2277 }
2278 This->NumberOfPalettes = 0;
2279 if(swapchain) {
2280 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2281 }
2282 if(This->stateBlock) {
2283 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2284 This->stateBlock = NULL;
2285 }
2286 if (This->blit_priv) {
2287 This->blitter->free_private(iface);
2288 }
2289 if (This->fragment_priv) {
2290 This->frag_pipe->free_private(iface);
2291 }
2292 if (This->shader_priv) {
2293 This->shader_backend->shader_free_private(iface);
2294 }
2295 return hr;
2296}
2297
2298static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2300 IWineD3DSwapChainImpl *swapchain = NULL;
2301 HRESULT hr;
2302
2303 /* Setup the implicit swapchain */
2304 TRACE("Creating implicit swapchain\n");
2305 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2306 if (FAILED(hr) || !swapchain) {
2307 WARN("Failed to create implicit swapchain\n");
2308 goto err_out;
2309 }
2310
2311 This->NumberOfSwapChains = 1;
2312 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2313 if(!This->swapchains) {
2314 ERR("Out of memory!\n");
2315 goto err_out;
2316 }
2317 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2318 return WINED3D_OK;
2319
2320err_out:
2321 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2322 return hr;
2323}
2324
2325static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2327 int sampler;
2328 UINT i;
2329 TRACE("(%p)\n", This);
2330
2331 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2332
2333 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2334 * it was created. Thus make sure a context is active for the glDelete* calls
2335 */
2336 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2337
2338 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2339
2340 TRACE("Deleting high order patches\n");
2341 for(i = 0; i < PATCHMAP_SIZE; i++) {
2342 struct list *e1, *e2;
2343 struct WineD3DRectPatch *patch;
2344 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2345 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2346 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2347 }
2348 }
2349
2350 /* Delete the palette conversion shader if it is around */
2351 if(This->paletteConversionShader) {
2352 ENTER_GL();
2353 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2354 LEAVE_GL();
2355 This->paletteConversionShader = 0;
2356 }
2357
2358 /* Delete the pbuffer context if there is any */
2359 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2360
2361 /* Delete the mouse cursor texture */
2362 if(This->cursorTexture) {
2363 ENTER_GL();
2364 glDeleteTextures(1, &This->cursorTexture);
2365 LEAVE_GL();
2366 This->cursorTexture = 0;
2367 }
2368
2369 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2370 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2371 }
2372 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2373 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2374 }
2375
2376 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2377 * private data, it might contain opengl pointers
2378 */
2379 if(This->depth_blt_texture) {
2380 glDeleteTextures(1, &This->depth_blt_texture);
2381 This->depth_blt_texture = 0;
2382 }
2383 if (This->depth_blt_rb) {
2384 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2385 This->depth_blt_rb = 0;
2386 This->depth_blt_rb_w = 0;
2387 This->depth_blt_rb_h = 0;
2388 }
2389
2390 /* Release the update stateblock */
2391 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2392 if(This->updateStateBlock != This->stateBlock)
2393 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2394 }
2395 This->updateStateBlock = NULL;
2396
2397 { /* because were not doing proper internal refcounts releasing the primary state block
2398 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2399 to set this->stateBlock = NULL; first */
2400 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2401 This->stateBlock = NULL;
2402
2403 /* Release the stateblock */
2404 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2405 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2406 }
2407 }
2408
2409 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2410 This->blitter->free_private(iface);
2411 This->frag_pipe->free_private(iface);
2412 This->shader_backend->shader_free_private(iface);
2413
2414 /* Release the buffers (with sanity checks)*/
2415 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2416 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2417 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2418 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2419 }
2420 This->stencilBufferTarget = NULL;
2421
2422 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2423 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2424 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2425 }
2426 TRACE("Setting rendertarget to NULL\n");
2427 This->render_targets[0] = NULL;
2428
2429 if (This->auto_depth_stencil_buffer) {
2430 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2431 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2432 }
2433 This->auto_depth_stencil_buffer = NULL;
2434 }
2435
2436 for(i=0; i < This->NumberOfSwapChains; i++) {
2437 TRACE("Releasing the implicit swapchain %d\n", i);
2438 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2439 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2440 }
2441 }
2442
2443 HeapFree(GetProcessHeap(), 0, This->swapchains);
2444 This->swapchains = NULL;
2445 This->NumberOfSwapChains = 0;
2446
2447 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2448 HeapFree(GetProcessHeap(), 0, This->palettes);
2449 This->palettes = NULL;
2450 This->NumberOfPalettes = 0;
2451
2452 HeapFree(GetProcessHeap(), 0, This->render_targets);
2453 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2454 This->render_targets = NULL;
2455 This->draw_buffers = NULL;
2456
2457 This->d3d_initialized = FALSE;
2458 return WINED3D_OK;
2459}
2460
2461static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2463 unsigned int i;
2464
2465 for(i=0; i < This->NumberOfSwapChains; i++) {
2466 TRACE("Releasing the implicit swapchain %d\n", i);
2467 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2468 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2469 }
2470 }
2471
2472 HeapFree(GetProcessHeap(), 0, This->swapchains);
2473 This->swapchains = NULL;
2474 This->NumberOfSwapChains = 0;
2475 return WINED3D_OK;
2476}
2477
2478/* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2479 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2480 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2481 *
2482 * There is no way to deactivate thread safety once it is enabled.
2483 */
2484static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2486
2487 /*For now just store the flag(needed in case of ddraw) */
2488 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2489
2490 return;
2491}
2492
2493static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2494 const WINED3DDISPLAYMODE* pMode) {
2495 DEVMODEW devmode;
2496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2497 LONG ret;
2498 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2499 RECT clip_rc;
2500
2501 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2502
2503 /* Resize the screen even without a window:
2504 * The app could have unset it with SetCooperativeLevel, but not called
2505 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2506 * but we don't have any hwnd
2507 */
2508
2509 memset(&devmode, 0, sizeof(devmode));
2510 devmode.dmSize = sizeof(devmode);
2511 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2512 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2513 devmode.dmPelsWidth = pMode->Width;
2514 devmode.dmPelsHeight = pMode->Height;
2515
2516 devmode.dmDisplayFrequency = pMode->RefreshRate;
2517 if (pMode->RefreshRate != 0) {
2518 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2519 }
2520
2521 /* Only change the mode if necessary */
2522 if( (This->ddraw_width == pMode->Width) &&
2523 (This->ddraw_height == pMode->Height) &&
2524 (This->ddraw_format == pMode->Format) &&
2525 (pMode->RefreshRate == 0) ) {
2526 return WINED3D_OK;
2527 }
2528
2529 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2530 if (ret != DISP_CHANGE_SUCCESSFUL) {
2531 if(devmode.dmDisplayFrequency != 0) {
2532 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2533 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2534 devmode.dmDisplayFrequency = 0;
2535 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2536 }
2537 if(ret != DISP_CHANGE_SUCCESSFUL) {
2538 return WINED3DERR_NOTAVAILABLE;
2539 }
2540 }
2541
2542 /* Store the new values */
2543 This->ddraw_width = pMode->Width;
2544 This->ddraw_height = pMode->Height;
2545 This->ddraw_format = pMode->Format;
2546
2547 /* And finally clip mouse to our screen */
2548 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2549 ClipCursor(&clip_rc);
2550
2551 return WINED3D_OK;
2552}
2553
2554static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2555 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2556 *ppD3D= This->wineD3D;
2557 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2558 IWineD3D_AddRef(*ppD3D);
2559 return WINED3D_OK;
2560}
2561
2562static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2564
2565 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2566 (This->adapter->TextureRam/(1024*1024)),
2567 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2568 /* return simulated texture memory left */
2569 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2570}
2571
2572
2573
2574/*****
2575 * Get / Set FVF
2576 *****/
2577static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2579
2580 /* Update the current state block */
2581 This->updateStateBlock->changed.fvf = TRUE;
2582
2583 if(This->updateStateBlock->fvf == fvf) {
2584 TRACE("Application is setting the old fvf over, nothing to do\n");
2585 return WINED3D_OK;
2586 }
2587
2588 This->updateStateBlock->fvf = fvf;
2589 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2590 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2591 return WINED3D_OK;
2592}
2593
2594
2595static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2597 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2598 *pfvf = This->stateBlock->fvf;
2599 return WINED3D_OK;
2600}
2601
2602/*****
2603 * Get / Set Stream Source
2604 *****/
2605static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2607 IWineD3DVertexBuffer *oldSrc;
2608
2609 if (StreamNumber >= MAX_STREAMS) {
2610 WARN("Stream out of range %d\n", StreamNumber);
2611 return WINED3DERR_INVALIDCALL;
2612 } else if(OffsetInBytes & 0x3) {
2613 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2614 return WINED3DERR_INVALIDCALL;
2615 }
2616
2617 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2618 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2619
2620 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2621
2622 if(oldSrc == pStreamData &&
2623 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2624 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2625 TRACE("Application is setting the old values over, nothing to do\n");
2626 return WINED3D_OK;
2627 }
2628
2629 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2630 if (pStreamData) {
2631 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2632 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2633 }
2634
2635 /* Handle recording of state blocks */
2636 if (This->isRecordingState) {
2637 TRACE("Recording... not performing anything\n");
2638 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2639 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2640 return WINED3D_OK;
2641 }
2642
2643 /* Need to do a getParent and pass the references up */
2644 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2645 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2646 so for now, just count internally */
2647 if (pStreamData != NULL) {
2648 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2649 InterlockedIncrement(&vbImpl->bindCount);
2650 IWineD3DVertexBuffer_AddRef(pStreamData);
2651 }
2652 if (oldSrc != NULL) {
2653 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2654 IWineD3DVertexBuffer_Release(oldSrc);
2655 }
2656
2657 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2658
2659 return WINED3D_OK;
2660}
2661
2662static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2664
2665 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2666 This->stateBlock->streamSource[StreamNumber],
2667 This->stateBlock->streamOffset[StreamNumber],
2668 This->stateBlock->streamStride[StreamNumber]);
2669
2670 if (StreamNumber >= MAX_STREAMS) {
2671 WARN("Stream out of range %d\n", StreamNumber);
2672 return WINED3DERR_INVALIDCALL;
2673 }
2674 *pStream = This->stateBlock->streamSource[StreamNumber];
2675 *pStride = This->stateBlock->streamStride[StreamNumber];
2676 if (pOffset) {
2677 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2678 }
2679
2680 if (*pStream != NULL) {
2681 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2682 }
2683 return WINED3D_OK;
2684}
2685
2686static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2688 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2689 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2690
2691 /* Verify input at least in d3d9 this is invalid*/
2692 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2693 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2694 return WINED3DERR_INVALIDCALL;
2695 }
2696 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2697 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2698 return WINED3DERR_INVALIDCALL;
2699 }
2700 if( Divider == 0 ){
2701 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2702 return WINED3DERR_INVALIDCALL;
2703 }
2704
2705 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2706 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2707
2708 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2709 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2710
2711 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2712 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2713 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2714 }
2715
2716 return WINED3D_OK;
2717}
2718
2719static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2721
2722 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2723 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2724
2725 TRACE("(%p) : returning %d\n", This, *Divider);
2726
2727 return WINED3D_OK;
2728}
2729
2730/*****
2731 * Get / Set & Multiply Transform
2732 *****/
2733static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2735
2736 /* Most of this routine, comments included copied from ddraw tree initially: */
2737 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2738
2739 /* Handle recording of state blocks */
2740 if (This->isRecordingState) {
2741 TRACE("Recording... not performing anything\n");
2742 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2743 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2744 return WINED3D_OK;
2745 }
2746
2747 /*
2748 * If the new matrix is the same as the current one,
2749 * we cut off any further processing. this seems to be a reasonable
2750 * optimization because as was noticed, some apps (warcraft3 for example)
2751 * tend towards setting the same matrix repeatedly for some reason.
2752 *
2753 * From here on we assume that the new matrix is different, wherever it matters.
2754 */
2755 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2756 TRACE("The app is setting the same matrix over again\n");
2757 return WINED3D_OK;
2758 } else {
2759 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2760 }
2761
2762 /*
2763 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2764 where ViewMat = Camera space, WorldMat = world space.
2765
2766 In OpenGL, camera and world space is combined into GL_MODELVIEW
2767 matrix. The Projection matrix stay projection matrix.
2768 */
2769
2770 /* Capture the times we can just ignore the change for now */
2771 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2772 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2773 /* Handled by the state manager */
2774 }
2775
2776 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2777 return WINED3D_OK;
2778
2779}
2780static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2782 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2783 *pMatrix = This->stateBlock->transforms[State];
2784 return WINED3D_OK;
2785}
2786
2787static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2788 const WINED3DMATRIX *mat = NULL;
2789 WINED3DMATRIX temp;
2790
2791 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2792 * below means it will be recorded in a state block change, but it
2793 * works regardless where it is recorded.
2794 * If this is found to be wrong, change to StateBlock.
2795 */
2796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2797 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2798
2799 if (State < HIGHEST_TRANSFORMSTATE)
2800 {
2801 mat = &This->updateStateBlock->transforms[State];
2802 } else {
2803 FIXME("Unhandled transform state!!\n");
2804 }
2805
2806 multiply_matrix(&temp, mat, pMatrix);
2807
2808 /* Apply change via set transform - will reapply to eg. lights this way */
2809 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2810}
2811
2812/*****
2813 * Get / Set Light
2814 *****/
2815/* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2816 you can reference any indexes you want as long as that number max are enabled at any
2817 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2818 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2819 but when recording, just build a chain pretty much of commands to be replayed. */
2820
2821static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2822 float rho;
2823 PLIGHTINFOEL *object = NULL;
2824 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2825 struct list *e;
2826
2827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2828 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2829
2830 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2831 * the gl driver.
2832 */
2833 if(!pLight) {
2834 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2835 return WINED3DERR_INVALIDCALL;
2836 }
2837
2838 switch(pLight->Type) {
2839 case WINED3DLIGHT_POINT:
2840 case WINED3DLIGHT_SPOT:
2841 case WINED3DLIGHT_PARALLELPOINT:
2842 case WINED3DLIGHT_GLSPOT:
2843 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2844 * most wanted
2845 */
2846 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2847 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2848 return WINED3DERR_INVALIDCALL;
2849 }
2850 break;
2851
2852 case WINED3DLIGHT_DIRECTIONAL:
2853 /* Ignores attenuation */
2854 break;
2855
2856 default:
2857 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2858 return WINED3DERR_INVALIDCALL;
2859 }
2860
2861 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2862 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2863 if(object->OriginalIndex == Index) break;
2864 object = NULL;
2865 }
2866
2867 if(!object) {
2868 TRACE("Adding new light\n");
2869 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2870 if(!object) {
2871 ERR("Out of memory error when allocating a light\n");
2872 return E_OUTOFMEMORY;
2873 }
2874 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2875 object->glIndex = -1;
2876 object->OriginalIndex = Index;
2877 object->changed = TRUE;
2878 }
2879
2880 /* Initialize the object */
2881 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2882 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2883 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2884 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2885 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2886 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2887 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2888
2889 /* Save away the information */
2890 object->OriginalParms = *pLight;
2891
2892 switch (pLight->Type) {
2893 case WINED3DLIGHT_POINT:
2894 /* Position */
2895 object->lightPosn[0] = pLight->Position.x;
2896 object->lightPosn[1] = pLight->Position.y;
2897 object->lightPosn[2] = pLight->Position.z;
2898 object->lightPosn[3] = 1.0f;
2899 object->cutoff = 180.0f;
2900 /* FIXME: Range */
2901 break;
2902
2903 case WINED3DLIGHT_DIRECTIONAL:
2904 /* Direction */
2905 object->lightPosn[0] = -pLight->Direction.x;
2906 object->lightPosn[1] = -pLight->Direction.y;
2907 object->lightPosn[2] = -pLight->Direction.z;
2908 object->lightPosn[3] = 0.0;
2909 object->exponent = 0.0f;
2910 object->cutoff = 180.0f;
2911 break;
2912
2913 case WINED3DLIGHT_SPOT:
2914 /* Position */
2915 object->lightPosn[0] = pLight->Position.x;
2916 object->lightPosn[1] = pLight->Position.y;
2917 object->lightPosn[2] = pLight->Position.z;
2918 object->lightPosn[3] = 1.0;
2919
2920 /* Direction */
2921 object->lightDirn[0] = pLight->Direction.x;
2922 object->lightDirn[1] = pLight->Direction.y;
2923 object->lightDirn[2] = pLight->Direction.z;
2924 object->lightDirn[3] = 1.0;
2925
2926 /*
2927 * opengl-ish and d3d-ish spot lights use too different models for the
2928 * light "intensity" as a function of the angle towards the main light direction,
2929 * so we only can approximate very roughly.
2930 * however spot lights are rather rarely used in games (if ever used at all).
2931 * furthermore if still used, probably nobody pays attention to such details.
2932 */
2933 if (pLight->Falloff == 0) {
2934 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2935 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2936 * will always be 1.0 for both of them, and we don't have to care for the
2937 * rest of the rather complex calculation
2938 */
2939 object->exponent = 0;
2940 } else {
2941 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2942 if (rho < 0.0001) rho = 0.0001f;
2943 object->exponent = -0.3/log(cos(rho/2));
2944 }
2945 if (object->exponent > 128.0) {
2946 object->exponent = 128.0;
2947 }
2948 object->cutoff = pLight->Phi*90/M_PI;
2949
2950 /* FIXME: Range */
2951 break;
2952
2953 default:
2954 FIXME("Unrecognized light type %d\n", pLight->Type);
2955 }
2956
2957 /* Update the live definitions if the light is currently assigned a glIndex */
2958 if (object->glIndex != -1 && !This->isRecordingState) {
2959 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2960 }
2961 return WINED3D_OK;
2962}
2963
2964static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2965 PLIGHTINFOEL *lightInfo = NULL;
2966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2967 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2968 struct list *e;
2969 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2970
2971 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2972 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2973 if(lightInfo->OriginalIndex == Index) break;
2974 lightInfo = NULL;
2975 }
2976
2977 if (lightInfo == NULL) {
2978 TRACE("Light information requested but light not defined\n");
2979 return WINED3DERR_INVALIDCALL;
2980 }
2981
2982 *pLight = lightInfo->OriginalParms;
2983 return WINED3D_OK;
2984}
2985
2986/*****
2987 * Get / Set Light Enable
2988 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2989 *****/
2990static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2991 PLIGHTINFOEL *lightInfo = NULL;
2992 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2993 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2994 struct list *e;
2995 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2996
2997 /* Tests show true = 128...not clear why */
2998 Enable = Enable? 128: 0;
2999
3000 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3001 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3002 if(lightInfo->OriginalIndex == Index) break;
3003 lightInfo = NULL;
3004 }
3005 TRACE("Found light: %p\n", lightInfo);
3006
3007 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3008 if (lightInfo == NULL) {
3009
3010 TRACE("Light enabled requested but light not defined, so defining one!\n");
3011 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3012
3013 /* Search for it again! Should be fairly quick as near head of list */
3014 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3015 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3016 if(lightInfo->OriginalIndex == Index) break;
3017 lightInfo = NULL;
3018 }
3019 if (lightInfo == NULL) {
3020 FIXME("Adding default lights has failed dismally\n");
3021 return WINED3DERR_INVALIDCALL;
3022 }
3023 }
3024
3025 lightInfo->enabledChanged = TRUE;
3026 if(!Enable) {
3027 if(lightInfo->glIndex != -1) {
3028 if(!This->isRecordingState) {
3029 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3030 }
3031
3032 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3033 lightInfo->glIndex = -1;
3034 } else {
3035 TRACE("Light already disabled, nothing to do\n");
3036 }
3037 lightInfo->enabled = FALSE;
3038 } else {
3039 lightInfo->enabled = TRUE;
3040 if (lightInfo->glIndex != -1) {
3041 /* nop */
3042 TRACE("Nothing to do as light was enabled\n");
3043 } else {
3044 int i;
3045 /* Find a free gl light */
3046 for(i = 0; i < This->maxConcurrentLights; i++) {
3047 if(This->updateStateBlock->activeLights[i] == NULL) {
3048 This->updateStateBlock->activeLights[i] = lightInfo;
3049 lightInfo->glIndex = i;
3050 break;
3051 }
3052 }
3053 if(lightInfo->glIndex == -1) {
3054 /* Our tests show that Windows returns D3D_OK in this situation, even with
3055 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3056 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3057 * as well for those lights.
3058 *
3059 * TODO: Test how this affects rendering
3060 */
3061 FIXME("Too many concurrently active lights\n");
3062 return WINED3D_OK;
3063 }
3064
3065 /* i == lightInfo->glIndex */
3066 if(!This->isRecordingState) {
3067 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3068 }
3069 }
3070 }
3071
3072 return WINED3D_OK;
3073}
3074
3075static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3076
3077 PLIGHTINFOEL *lightInfo = NULL;
3078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3079 struct list *e;
3080 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3081 TRACE("(%p) : for idx(%d)\n", This, Index);
3082
3083 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3084 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3085 if(lightInfo->OriginalIndex == Index) break;
3086 lightInfo = NULL;
3087 }
3088
3089 if (lightInfo == NULL) {
3090 TRACE("Light enabled state requested but light not defined\n");
3091 return WINED3DERR_INVALIDCALL;
3092 }
3093 /* true is 128 according to SetLightEnable */
3094 *pEnable = lightInfo->enabled ? 128 : 0;
3095 return WINED3D_OK;
3096}
3097
3098/*****
3099 * Get / Set Clip Planes
3100 *****/
3101static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3103 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3104
3105 /* Validate Index */
3106 if (Index >= GL_LIMITS(clipplanes)) {
3107 TRACE("Application has requested clipplane this device doesn't support\n");
3108 return WINED3DERR_INVALIDCALL;
3109 }
3110
3111 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3112
3113 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3114 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3115 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3116 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3117 TRACE("Application is setting old values over, nothing to do\n");
3118 return WINED3D_OK;
3119 }
3120
3121 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3122 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3123 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3124 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3125
3126 /* Handle recording of state blocks */
3127 if (This->isRecordingState) {
3128 TRACE("Recording... not performing anything\n");
3129 return WINED3D_OK;
3130 }
3131
3132 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3133
3134 return WINED3D_OK;
3135}
3136
3137static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3139 TRACE("(%p) : for idx %d\n", This, Index);
3140
3141 /* Validate Index */
3142 if (Index >= GL_LIMITS(clipplanes)) {
3143 TRACE("Application has requested clipplane this device doesn't support\n");
3144 return WINED3DERR_INVALIDCALL;
3145 }
3146
3147 pPlane[0] = This->stateBlock->clipplane[Index][0];
3148 pPlane[1] = This->stateBlock->clipplane[Index][1];
3149 pPlane[2] = This->stateBlock->clipplane[Index][2];
3150 pPlane[3] = This->stateBlock->clipplane[Index][3];
3151 return WINED3D_OK;
3152}
3153
3154/*****
3155 * Get / Set Clip Plane Status
3156 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3157 *****/
3158static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3160 FIXME("(%p) : stub\n", This);
3161 if (NULL == pClipStatus) {
3162 return WINED3DERR_INVALIDCALL;
3163 }
3164 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3165 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3166 return WINED3D_OK;
3167}
3168
3169static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3171 FIXME("(%p) : stub\n", This);
3172 if (NULL == pClipStatus) {
3173 return WINED3DERR_INVALIDCALL;
3174 }
3175 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3176 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3177 return WINED3D_OK;
3178}
3179
3180/*****
3181 * Get / Set Material
3182 *****/
3183static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3185
3186 This->updateStateBlock->changed.material = TRUE;
3187 This->updateStateBlock->material = *pMaterial;
3188
3189 /* Handle recording of state blocks */
3190 if (This->isRecordingState) {
3191 TRACE("Recording... not performing anything\n");
3192 return WINED3D_OK;
3193 }
3194
3195 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3196 return WINED3D_OK;
3197}
3198
3199static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3201 *pMaterial = This->updateStateBlock->material;
3202 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3203 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3204 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3205 pMaterial->Ambient.b, pMaterial->Ambient.a);
3206 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3207 pMaterial->Specular.b, pMaterial->Specular.a);
3208 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3209 pMaterial->Emissive.b, pMaterial->Emissive.a);
3210 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3211
3212 return WINED3D_OK;
3213}
3214
3215/*****
3216 * Get / Set Indices
3217 *****/
3218static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3219 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3220 IWineD3DIndexBuffer *oldIdxs;
3221
3222 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3223 oldIdxs = This->updateStateBlock->pIndexData;
3224
3225 This->updateStateBlock->changed.indices = TRUE;
3226 This->updateStateBlock->pIndexData = pIndexData;
3227
3228 /* Handle recording of state blocks */
3229 if (This->isRecordingState) {
3230 TRACE("Recording... not performing anything\n");
3231 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3232 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3233 return WINED3D_OK;
3234 }
3235
3236 if(oldIdxs != pIndexData) {
3237 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3238 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3239 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3240 }
3241 return WINED3D_OK;
3242}
3243
3244static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3246
3247 *ppIndexData = This->stateBlock->pIndexData;
3248
3249 /* up ref count on ppindexdata */
3250 if (*ppIndexData) {
3251 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3252 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3253 }else{
3254 TRACE("(%p) No index data set\n", This);
3255 }
3256 TRACE("Returning %p\n", *ppIndexData);
3257
3258 return WINED3D_OK;
3259}
3260
3261/* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3262static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3264 TRACE("(%p)->(%d)\n", This, BaseIndex);
3265
3266 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3267 TRACE("Application is setting the old value over, nothing to do\n");
3268 return WINED3D_OK;
3269 }
3270
3271 This->updateStateBlock->baseVertexIndex = BaseIndex;
3272
3273 if (This->isRecordingState) {
3274 TRACE("Recording... not performing anything\n");
3275 return WINED3D_OK;
3276 }
3277 /* The base vertex index affects the stream sources */
3278 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3279 return WINED3D_OK;
3280}
3281
3282static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3284 TRACE("(%p) : base_index %p\n", This, base_index);
3285
3286 *base_index = This->stateBlock->baseVertexIndex;
3287
3288 TRACE("Returning %u\n", *base_index);
3289
3290 return WINED3D_OK;
3291}
3292
3293/*****
3294 * Get / Set Viewports
3295 *****/
3296static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3298
3299 TRACE("(%p)\n", This);
3300 This->updateStateBlock->changed.viewport = TRUE;
3301 This->updateStateBlock->viewport = *pViewport;
3302
3303 /* Handle recording of state blocks */
3304 if (This->isRecordingState) {
3305 TRACE("Recording... not performing anything\n");
3306 return WINED3D_OK;
3307 }
3308
3309 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3310 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3311
3312 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3313 return WINED3D_OK;
3314
3315}
3316
3317static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3319 TRACE("(%p)\n", This);
3320 *pViewport = This->stateBlock->viewport;
3321 return WINED3D_OK;
3322}
3323
3324/*****
3325 * Get / Set Render States
3326 * TODO: Verify against dx9 definitions
3327 *****/
3328static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3329
3330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3331 DWORD oldValue = This->stateBlock->renderState[State];
3332
3333 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3334
3335 This->updateStateBlock->changed.renderState[State] = TRUE;
3336 This->updateStateBlock->renderState[State] = Value;
3337
3338 /* Handle recording of state blocks */
3339 if (This->isRecordingState) {
3340 TRACE("Recording... not performing anything\n");
3341 return WINED3D_OK;
3342 }
3343
3344 /* Compared here and not before the assignment to allow proper stateblock recording */
3345 if(Value == oldValue) {
3346 TRACE("Application is setting the old value over, nothing to do\n");
3347 } else {
3348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3349 }
3350
3351 return WINED3D_OK;
3352}
3353
3354static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3356 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3357 *pValue = This->stateBlock->renderState[State];
3358 return WINED3D_OK;
3359}
3360
3361/*****
3362 * Get / Set Sampler States
3363 * TODO: Verify against dx9 definitions
3364 *****/
3365
3366static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3368 DWORD oldValue;
3369
3370 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3371 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3372
3373 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3374 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3375 }
3376
3377 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3378 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3379 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3380 }
3381 /**
3382 * SetSampler is designed to allow for more than the standard up to 8 textures
3383 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3384 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3385 *
3386 * http://developer.nvidia.com/object/General_FAQ.html#t6
3387 *
3388 * There are two new settings for GForce
3389 * the sampler one:
3390 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3391 * and the texture one:
3392 * GL_MAX_TEXTURE_COORDS_ARB.
3393 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3394 ******************/
3395
3396 oldValue = This->stateBlock->samplerState[Sampler][Type];
3397 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3398 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3399
3400 /* Handle recording of state blocks */
3401 if (This->isRecordingState) {
3402 TRACE("Recording... not performing anything\n");
3403 return WINED3D_OK;
3404 }
3405
3406 if(oldValue == Value) {
3407 TRACE("Application is setting the old value over, nothing to do\n");
3408 return WINED3D_OK;
3409 }
3410
3411 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3412
3413 return WINED3D_OK;
3414}
3415
3416static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3418
3419 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3420 This, Sampler, debug_d3dsamplerstate(Type), Type);
3421
3422 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3423 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3424 }
3425
3426 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3427 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3428 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3429 }
3430 *Value = This->stateBlock->samplerState[Sampler][Type];
3431 TRACE("(%p) : Returning %#x\n", This, *Value);
3432
3433 return WINED3D_OK;
3434}
3435
3436static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3438
3439 This->updateStateBlock->changed.scissorRect = TRUE;
3440 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3441 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3442 return WINED3D_OK;
3443 }
3444 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3445
3446 if(This->isRecordingState) {
3447 TRACE("Recording... not performing anything\n");
3448 return WINED3D_OK;
3449 }
3450
3451 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3452
3453 return WINED3D_OK;
3454}
3455
3456static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3458
3459 *pRect = This->updateStateBlock->scissorRect;
3460 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3461 return WINED3D_OK;
3462}
3463
3464static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3465 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3466 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3467
3468 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3469
3470 This->updateStateBlock->vertexDecl = pDecl;
3471 This->updateStateBlock->changed.vertexDecl = TRUE;
3472
3473 if (This->isRecordingState) {
3474 TRACE("Recording... not performing anything\n");
3475 return WINED3D_OK;
3476 } else if(pDecl == oldDecl) {
3477 /* Checked after the assignment to allow proper stateblock recording */
3478 TRACE("Application is setting the old declaration over, nothing to do\n");
3479 return WINED3D_OK;
3480 }
3481
3482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3483 return WINED3D_OK;
3484}
3485
3486static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3488
3489 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3490
3491 *ppDecl = This->stateBlock->vertexDecl;
3492 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3493 return WINED3D_OK;
3494}
3495
3496static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3498 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3499
3500 This->updateStateBlock->vertexShader = pShader;
3501 This->updateStateBlock->changed.vertexShader = TRUE;
3502
3503 if (This->isRecordingState) {
3504 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3505 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3506 TRACE("Recording... not performing anything\n");
3507 return WINED3D_OK;
3508 } else if(oldShader == pShader) {
3509 /* Checked here to allow proper stateblock recording */
3510 TRACE("App is setting the old shader over, nothing to do\n");
3511 return WINED3D_OK;
3512 }
3513
3514 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3515 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3516 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3517
3518 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3519
3520 return WINED3D_OK;
3521}
3522
3523static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3525
3526 if (NULL == ppShader) {
3527 return WINED3DERR_INVALIDCALL;
3528 }
3529 *ppShader = This->stateBlock->vertexShader;
3530 if( NULL != *ppShader)
3531 IWineD3DVertexShader_AddRef(*ppShader);
3532
3533 TRACE("(%p) : returning %p\n", This, *ppShader);
3534 return WINED3D_OK;
3535}
3536
3537static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3538 IWineD3DDevice *iface,
3539 UINT start,
3540 CONST BOOL *srcData,
3541 UINT count) {
3542
3543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3544 int i, cnt = min(count, MAX_CONST_B - start);
3545
3546 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3547 iface, srcData, start, count);
3548
3549 if (srcData == NULL || cnt < 0)
3550 return WINED3DERR_INVALIDCALL;
3551
3552 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3553 for (i = 0; i < cnt; i++)
3554 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3555
3556 for (i = start; i < cnt + start; ++i) {
3557 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3558 }
3559
3560 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3561
3562 return WINED3D_OK;
3563}
3564
3565static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3566 IWineD3DDevice *iface,
3567 UINT start,
3568 BOOL *dstData,
3569 UINT count) {
3570
3571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3572 int cnt = min(count, MAX_CONST_B - start);
3573
3574 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3575 iface, dstData, start, count);
3576
3577 if (dstData == NULL || cnt < 0)
3578 return WINED3DERR_INVALIDCALL;
3579
3580 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3581 return WINED3D_OK;
3582}
3583
3584static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3585 IWineD3DDevice *iface,
3586 UINT start,
3587 CONST int *srcData,
3588 UINT count) {
3589
3590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3591 int i, cnt = min(count, MAX_CONST_I - start);
3592
3593 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3594 iface, srcData, start, count);
3595
3596 if (srcData == NULL || cnt < 0)
3597 return WINED3DERR_INVALIDCALL;
3598
3599 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3600 for (i = 0; i < cnt; i++)
3601 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3602 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3603
3604 for (i = start; i < cnt + start; ++i) {
3605 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3606 }
3607
3608 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3609
3610 return WINED3D_OK;
3611}
3612
3613static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3614 IWineD3DDevice *iface,
3615 UINT start,
3616 int *dstData,
3617 UINT count) {
3618
3619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3620 int cnt = min(count, MAX_CONST_I - start);
3621
3622 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3623 iface, dstData, start, count);
3624
3625 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3626 return WINED3DERR_INVALIDCALL;
3627
3628 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3629 return WINED3D_OK;
3630}
3631
3632static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3633 IWineD3DDevice *iface,
3634 UINT start,
3635 CONST float *srcData,
3636 UINT count) {
3637
3638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3639 UINT i;
3640
3641 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3642 iface, srcData, start, count);
3643
3644 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3645 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3646 return WINED3DERR_INVALIDCALL;
3647
3648 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3649 if(TRACE_ON(d3d)) {
3650 for (i = 0; i < count; i++)
3651 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3652 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3653 }
3654
3655 for (i = start; i < count + start; ++i) {
3656 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3657 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3658 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3659 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3660 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3661 }
3662 ptr->idx[ptr->count++] = i;
3663 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3664 }
3665 }
3666
3667 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3668
3669 return WINED3D_OK;
3670}
3671
3672static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3673IWineD3DDevice *iface,
3674UINT start,
3675CONST float *srcData,
3676UINT count) {
3677
3678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3679 UINT i;
3680
3681 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3682 iface, srcData, start, count);
3683
3684 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3685 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3686 return WINED3DERR_INVALIDCALL;
3687
3688 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3689 if(TRACE_ON(d3d)) {
3690 for (i = 0; i < count; i++)
3691 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3692 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3693 }
3694
3695 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3696 * context. On a context switch the old context will be fully dirtified
3697 */
3698 memset(This->activeContext->vshader_const_dirty + start, 1,
3699 sizeof(*This->activeContext->vshader_const_dirty) * count);
3700 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3701
3702 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3703
3704 return WINED3D_OK;
3705}
3706
3707static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3708 IWineD3DDevice *iface,
3709 UINT start,
3710 float *dstData,
3711 UINT count) {
3712
3713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3714 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3715
3716 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3717 iface, dstData, start, count);
3718
3719 if (dstData == NULL || cnt < 0)
3720 return WINED3DERR_INVALIDCALL;
3721
3722 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3723 return WINED3D_OK;
3724}
3725
3726static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3727 DWORD i;
3728 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3729 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3730 }
3731}
3732
3733static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3734 int i = This->rev_tex_unit_map[unit];
3735 int j = This->texUnitMap[stage];
3736
3737 This->texUnitMap[stage] = unit;
3738 if (i != -1 && i != stage) {
3739 This->texUnitMap[i] = -1;
3740 }
3741
3742 This->rev_tex_unit_map[unit] = stage;
3743 if (j != -1 && j != unit) {
3744 This->rev_tex_unit_map[j] = -1;
3745 }
3746}
3747
3748static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3749 int i;
3750
3751 for (i = 0; i < MAX_TEXTURES; ++i) {
3752 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3753 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3754 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3755 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3756 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3757 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3758 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3759 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3760
3761 if (color_op == WINED3DTOP_DISABLE) {
3762 /* Not used, and disable higher stages */
3763 while (i < MAX_TEXTURES) {
3764 This->fixed_function_usage_map[i] = FALSE;
3765 ++i;
3766 }
3767 break;
3768 }
3769
3770 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3771 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3772 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3773 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3774 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3775 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3776 This->fixed_function_usage_map[i] = TRUE;
3777 } else {
3778 This->fixed_function_usage_map[i] = FALSE;
3779 }
3780
3781 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3782 This->fixed_function_usage_map[i+1] = TRUE;
3783 }
3784 }
3785}
3786
3787static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3788 int i, tex;
3789
3790 device_update_fixed_function_usage_map(This);
3791
3792 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3793 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3794 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3795 if (!This->fixed_function_usage_map[i]) continue;
3796
3797 if (This->texUnitMap[i] != i) {
3798 device_map_stage(This, i, i);
3799 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3800 markTextureStagesDirty(This, i);
3801 }
3802 }
3803 return;
3804 }
3805
3806 /* Now work out the mapping */
3807 tex = 0;
3808 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3809 if (!This->fixed_function_usage_map[i]) continue;
3810
3811 if (This->texUnitMap[i] != tex) {
3812 device_map_stage(This, i, tex);
3813 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3814 markTextureStagesDirty(This, i);
3815 }
3816
3817 ++tex;
3818 }
3819}
3820
3821static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3822 const DWORD *sampler_tokens =
3823 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3824 int i;
3825
3826 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3827 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3828 device_map_stage(This, i, i);
3829 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3830 if (i < MAX_TEXTURES) {
3831 markTextureStagesDirty(This, i);
3832 }
3833 }
3834 }
3835}
3836
3837static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3838 const DWORD *vshader_sampler_tokens, int unit)
3839{
3840 int current_mapping = This->rev_tex_unit_map[unit];
3841
3842 if (current_mapping == -1) {
3843 /* Not currently used */
3844 return TRUE;
3845 }
3846
3847 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3848 /* Used by a fragment sampler */
3849
3850 if (!pshader_sampler_tokens) {
3851 /* No pixel shader, check fixed function */
3852 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3853 }
3854
3855 /* Pixel shader, check the shader's sampler map */
3856 return !pshader_sampler_tokens[current_mapping];
3857 }
3858
3859 /* Used by a vertex sampler */
3860 return !vshader_sampler_tokens[current_mapping];
3861}
3862
3863static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3864 const DWORD *vshader_sampler_tokens =
3865 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3866 const DWORD *pshader_sampler_tokens = NULL;
3867 int start = GL_LIMITS(combined_samplers) - 1;
3868 int i;
3869
3870 if (ps) {
3871 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3872
3873 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3874 IWineD3DPixelShader_UpdateSamplers((IWineD3DPixelShader *)pshader);
3875 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3876 }
3877
3878 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3879 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3880 if (vshader_sampler_tokens[i]) {
3881 if (This->texUnitMap[vsampler_idx] != -1) {
3882 /* Already mapped somewhere */
3883 continue;
3884 }
3885
3886 while (start >= 0) {
3887 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3888 device_map_stage(This, vsampler_idx, start);
3889 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3890
3891 --start;
3892 break;
3893 }
3894
3895 --start;
3896 }
3897 }
3898 }
3899}
3900
3901void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3902 BOOL vs = use_vs(This);
3903 BOOL ps = use_ps(This);
3904 /*
3905 * Rules are:
3906 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3907 * that would be really messy and require shader recompilation
3908 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3909 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3910 */
3911 if (ps) {
3912 device_map_psamplers(This);
3913 } else {
3914 device_map_fixed_function_samplers(This);
3915 }
3916
3917 if (vs) {
3918 device_map_vsamplers(This, ps);
3919 }
3920}
3921
3922static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3924 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3925 This->updateStateBlock->pixelShader = pShader;
3926 This->updateStateBlock->changed.pixelShader = TRUE;
3927
3928 /* Handle recording of state blocks */
3929 if (This->isRecordingState) {
3930 TRACE("Recording... not performing anything\n");
3931 }
3932
3933 if (This->isRecordingState) {
3934 TRACE("Recording... not performing anything\n");
3935 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3936 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3937 return WINED3D_OK;
3938 }
3939
3940 if(pShader == oldShader) {
3941 TRACE("App is setting the old pixel shader over, nothing to do\n");
3942 return WINED3D_OK;
3943 }
3944
3945 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3946 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3947
3948 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3949 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3950
3951 return WINED3D_OK;
3952}
3953
3954static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3956
3957 if (NULL == ppShader) {
3958 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3959 return WINED3DERR_INVALIDCALL;
3960 }
3961
3962 *ppShader = This->stateBlock->pixelShader;
3963 if (NULL != *ppShader) {
3964 IWineD3DPixelShader_AddRef(*ppShader);
3965 }
3966 TRACE("(%p) : returning %p\n", This, *ppShader);
3967 return WINED3D_OK;
3968}
3969
3970static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3971 IWineD3DDevice *iface,
3972 UINT start,
3973 CONST BOOL *srcData,
3974 UINT count) {
3975
3976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3977 int i, cnt = min(count, MAX_CONST_B - start);
3978
3979 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3980 iface, srcData, start, count);
3981
3982 if (srcData == NULL || cnt < 0)
3983 return WINED3DERR_INVALIDCALL;
3984
3985 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3986 for (i = 0; i < cnt; i++)
3987 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3988
3989 for (i = start; i < cnt + start; ++i) {
3990 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3991 }
3992
3993 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3994
3995 return WINED3D_OK;
3996}
3997
3998static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3999 IWineD3DDevice *iface,
4000 UINT start,
4001 BOOL *dstData,
4002 UINT count) {
4003
4004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4005 int cnt = min(count, MAX_CONST_B - start);
4006
4007 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4008 iface, dstData, start, count);
4009
4010 if (dstData == NULL || cnt < 0)
4011 return WINED3DERR_INVALIDCALL;
4012
4013 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4014 return WINED3D_OK;
4015}
4016
4017static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4018 IWineD3DDevice *iface,
4019 UINT start,
4020 CONST int *srcData,
4021 UINT count) {
4022
4023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4024 int i, cnt = min(count, MAX_CONST_I - start);
4025
4026 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4027 iface, srcData, start, count);
4028
4029 if (srcData == NULL || cnt < 0)
4030 return WINED3DERR_INVALIDCALL;
4031
4032 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4033 for (i = 0; i < cnt; i++)
4034 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4035 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4036
4037 for (i = start; i < cnt + start; ++i) {
4038 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4039 }
4040
4041 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4042
4043 return WINED3D_OK;
4044}
4045
4046static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4047 IWineD3DDevice *iface,
4048 UINT start,
4049 int *dstData,
4050 UINT count) {
4051
4052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4053 int cnt = min(count, MAX_CONST_I - start);
4054
4055 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4056 iface, dstData, start, count);
4057
4058 if (dstData == NULL || cnt < 0)
4059 return WINED3DERR_INVALIDCALL;
4060
4061 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4062 return WINED3D_OK;
4063}
4064
4065static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4066 IWineD3DDevice *iface,
4067 UINT start,
4068 CONST float *srcData,
4069 UINT count) {
4070
4071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4072 UINT i;
4073
4074 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4075 iface, srcData, start, count);
4076
4077 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4078 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4079 return WINED3DERR_INVALIDCALL;
4080
4081 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4082 if(TRACE_ON(d3d)) {
4083 for (i = 0; i < count; i++)
4084 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4085 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4086 }
4087
4088 for (i = start; i < count + start; ++i) {
4089 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
4090 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
4091 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
4092 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
4093 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
4094 }
4095 ptr->idx[ptr->count++] = i;
4096 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4097 }
4098 }
4099
4100 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4101
4102 return WINED3D_OK;
4103}
4104
4105static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4106 IWineD3DDevice *iface,
4107 UINT start,
4108 CONST float *srcData,
4109 UINT count) {
4110
4111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4112 UINT i;
4113
4114 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4115 iface, srcData, start, count);
4116
4117 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4118 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4119 return WINED3DERR_INVALIDCALL;
4120
4121 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4122 if(TRACE_ON(d3d)) {
4123 for (i = 0; i < count; i++)
4124 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4125 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4126 }
4127
4128 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4129 * context. On a context switch the old context will be fully dirtified
4130 */
4131 memset(This->activeContext->pshader_const_dirty + start, 1,
4132 sizeof(*This->activeContext->pshader_const_dirty) * count);
4133 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4134
4135 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4136
4137 return WINED3D_OK;
4138}
4139
4140static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4141 IWineD3DDevice *iface,
4142 UINT start,
4143 float *dstData,
4144 UINT count) {
4145
4146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4147 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4148
4149 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4150 iface, dstData, start, count);
4151
4152 if (dstData == NULL || cnt < 0)
4153 return WINED3DERR_INVALIDCALL;
4154
4155 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4156 return WINED3D_OK;
4157}
4158
4159#define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4160static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4161 const WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags)
4162{
4163 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4164 unsigned int i;
4165 DWORD DestFVF = dest->fvf;
4166 WINED3DVIEWPORT vp;
4167 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4168 BOOL doClip;
4169 DWORD numTextures;
4170
4171 if (lpStrideData->u.s.normal.lpData) {
4172 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4173 }
4174
4175 if (lpStrideData->u.s.position.lpData == NULL) {
4176 ERR("Source has no position mask\n");
4177 return WINED3DERR_INVALIDCALL;
4178 }
4179
4180 /* We might access VBOs from this code, so hold the lock */
4181 ENTER_GL();
4182
4183 if (dest->resource.allocatedMemory == NULL) {
4184 /* This may happen if we do direct locking into a vbo. Unlikely,
4185 * but theoretically possible(ddraw processvertices test)
4186 */
4187 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4188 if(!dest->resource.allocatedMemory) {
4189 LEAVE_GL();
4190 ERR("Out of memory\n");
4191 return E_OUTOFMEMORY;
4192 }
4193 if(dest->vbo) {
4194 const void *src;
4195 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4196 checkGLcall("glBindBufferARB");
4197 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4198 if(src) {
4199 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4200 }
4201 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4202 checkGLcall("glUnmapBufferARB");
4203 }
4204 }
4205
4206 /* Get a pointer into the destination vbo(create one if none exists) and
4207 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4208 */
4209 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4210 dest->Flags |= VBFLAG_CREATEVBO;
4211 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4212 }
4213
4214 if(dest->vbo) {
4215 unsigned char extrabytes = 0;
4216 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4217 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4218 * this may write 4 extra bytes beyond the area that should be written
4219 */
4220 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4221 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4222 if(!dest_conv_addr) {
4223 ERR("Out of memory\n");
4224 /* Continue without storing converted vertices */
4225 }
4226 dest_conv = dest_conv_addr;
4227 }
4228
4229 /* Should I clip?
4230 * a) WINED3DRS_CLIPPING is enabled
4231 * b) WINED3DVOP_CLIP is passed
4232 */
4233 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4234 static BOOL warned = FALSE;
4235 /*
4236 * The clipping code is not quite correct. Some things need
4237 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4238 * so disable clipping for now.
4239 * (The graphics in Half-Life are broken, and my processvertices
4240 * test crashes with IDirect3DDevice3)
4241 doClip = TRUE;
4242 */
4243 doClip = FALSE;
4244 if(!warned) {
4245 warned = TRUE;
4246 FIXME("Clipping is broken and disabled for now\n");
4247 }
4248 } else doClip = FALSE;
4249 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4250
4251 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4252 WINED3DTS_VIEW,
4253 &view_mat);
4254 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4255 WINED3DTS_PROJECTION,
4256 &proj_mat);
4257 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4258 WINED3DTS_WORLDMATRIX(0),
4259 &world_mat);
4260
4261 TRACE("View mat:\n");
4262 TRACE("%f %f %f %f\n", view_mat.u.s._11, view_mat.u.s._12, view_mat.u.s._13, view_mat.u.s._14);
4263 TRACE("%f %f %f %f\n", view_mat.u.s._21, view_mat.u.s._22, view_mat.u.s._23, view_mat.u.s._24);
4264 TRACE("%f %f %f %f\n", view_mat.u.s._31, view_mat.u.s._32, view_mat.u.s._33, view_mat.u.s._34);
4265 TRACE("%f %f %f %f\n", view_mat.u.s._41, view_mat.u.s._42, view_mat.u.s._43, view_mat.u.s._44);
4266
4267 TRACE("Proj mat:\n");
4268 TRACE("%f %f %f %f\n", proj_mat.u.s._11, proj_mat.u.s._12, proj_mat.u.s._13, proj_mat.u.s._14);
4269 TRACE("%f %f %f %f\n", proj_mat.u.s._21, proj_mat.u.s._22, proj_mat.u.s._23, proj_mat.u.s._24);
4270 TRACE("%f %f %f %f\n", proj_mat.u.s._31, proj_mat.u.s._32, proj_mat.u.s._33, proj_mat.u.s._34);
4271 TRACE("%f %f %f %f\n", proj_mat.u.s._41, proj_mat.u.s._42, proj_mat.u.s._43, proj_mat.u.s._44);
4272
4273 TRACE("World mat:\n");
4274 TRACE("%f %f %f %f\n", world_mat.u.s._11, world_mat.u.s._12, world_mat.u.s._13, world_mat.u.s._14);
4275 TRACE("%f %f %f %f\n", world_mat.u.s._21, world_mat.u.s._22, world_mat.u.s._23, world_mat.u.s._24);
4276 TRACE("%f %f %f %f\n", world_mat.u.s._31, world_mat.u.s._32, world_mat.u.s._33, world_mat.u.s._34);
4277 TRACE("%f %f %f %f\n", world_mat.u.s._41, world_mat.u.s._42, world_mat.u.s._43, world_mat.u.s._44);
4278
4279 /* Get the viewport */
4280 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4281 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4282 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4283
4284 multiply_matrix(&mat,&view_mat,&world_mat);
4285 multiply_matrix(&mat,&proj_mat,&mat);
4286
4287 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4288
4289 for (i = 0; i < dwCount; i+= 1) {
4290 unsigned int tex_index;
4291
4292 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4293 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4294 /* The position first */
4295 const float *p =
4296 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4297 float x, y, z, rhw;
4298 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4299
4300 /* Multiplication with world, view and projection matrix */
4301 x = (p[0] * mat.u.s._11) + (p[1] * mat.u.s._21) + (p[2] * mat.u.s._31) + (1.0 * mat.u.s._41);
4302 y = (p[0] * mat.u.s._12) + (p[1] * mat.u.s._22) + (p[2] * mat.u.s._32) + (1.0 * mat.u.s._42);
4303 z = (p[0] * mat.u.s._13) + (p[1] * mat.u.s._23) + (p[2] * mat.u.s._33) + (1.0 * mat.u.s._43);
4304 rhw = (p[0] * mat.u.s._14) + (p[1] * mat.u.s._24) + (p[2] * mat.u.s._34) + (1.0 * mat.u.s._44);
4305
4306 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4307
4308 /* WARNING: The following things are taken from d3d7 and were not yet checked
4309 * against d3d8 or d3d9!
4310 */
4311
4312 /* Clipping conditions: From msdn
4313 *
4314 * A vertex is clipped if it does not match the following requirements
4315 * -rhw < x <= rhw
4316 * -rhw < y <= rhw
4317 * 0 < z <= rhw
4318 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4319 *
4320 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4321 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4322 *
4323 */
4324
4325 if( !doClip ||
4326 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4327 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4328 ( rhw > eps ) ) ) {
4329
4330 /* "Normal" viewport transformation (not clipped)
4331 * 1) The values are divided by rhw
4332 * 2) The y axis is negative, so multiply it with -1
4333 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4334 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4335 * 4) Multiply x with Width/2 and add Width/2
4336 * 5) The same for the height
4337 * 6) Add the viewpoint X and Y to the 2D coordinates and
4338 * The minimum Z value to z
4339 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4340 *
4341 * Well, basically it's simply a linear transformation into viewport
4342 * coordinates
4343 */
4344
4345 x /= rhw;
4346 y /= rhw;
4347 z /= rhw;
4348
4349 y *= -1;
4350
4351 x *= vp.Width / 2;
4352 y *= vp.Height / 2;
4353 z *= vp.MaxZ - vp.MinZ;
4354
4355 x += vp.Width / 2 + vp.X;
4356 y += vp.Height / 2 + vp.Y;
4357 z += vp.MinZ;
4358
4359 rhw = 1 / rhw;
4360 } else {
4361 /* That vertex got clipped
4362 * Contrary to OpenGL it is not dropped completely, it just
4363 * undergoes a different calculation.
4364 */
4365 TRACE("Vertex got clipped\n");
4366 x += rhw;
4367 y += rhw;
4368
4369 x /= 2;
4370 y /= 2;
4371
4372 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4373 * outside of the main vertex buffer memory. That needs some more
4374 * investigation...
4375 */
4376 }
4377
4378 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4379
4380
4381 ( (float *) dest_ptr)[0] = x;
4382 ( (float *) dest_ptr)[1] = y;
4383 ( (float *) dest_ptr)[2] = z;
4384 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4385
4386 dest_ptr += 3 * sizeof(float);
4387
4388 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4389 dest_ptr += sizeof(float);
4390 }
4391
4392 if(dest_conv) {
4393 float w = 1 / rhw;
4394 ( (float *) dest_conv)[0] = x * w;
4395 ( (float *) dest_conv)[1] = y * w;
4396 ( (float *) dest_conv)[2] = z * w;
4397 ( (float *) dest_conv)[3] = w;
4398
4399 dest_conv += 3 * sizeof(float);
4400
4401 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4402 dest_conv += sizeof(float);
4403 }
4404 }
4405 }
4406 if (DestFVF & WINED3DFVF_PSIZE) {
4407 dest_ptr += sizeof(DWORD);
4408 if(dest_conv) dest_conv += sizeof(DWORD);
4409 }
4410 if (DestFVF & WINED3DFVF_NORMAL) {
4411 const float *normal =
4412 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4413 /* AFAIK this should go into the lighting information */
4414 FIXME("Didn't expect the destination to have a normal\n");
4415 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4416 if(dest_conv) {
4417 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4418 }
4419 }
4420
4421 if (DestFVF & WINED3DFVF_DIFFUSE) {
4422 const DWORD *color_d =
4423 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4424 if(!color_d) {
4425 static BOOL warned = FALSE;
4426
4427 if(!warned) {
4428 ERR("No diffuse color in source, but destination has one\n");
4429 warned = TRUE;
4430 }
4431
4432 *( (DWORD *) dest_ptr) = 0xffffffff;
4433 dest_ptr += sizeof(DWORD);
4434
4435 if(dest_conv) {
4436 *( (DWORD *) dest_conv) = 0xffffffff;
4437 dest_conv += sizeof(DWORD);
4438 }
4439 }
4440 else {
4441 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4442 if(dest_conv) {
4443 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4444 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4445 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4446 dest_conv += sizeof(DWORD);
4447 }
4448 }
4449 }
4450
4451 if (DestFVF & WINED3DFVF_SPECULAR) {
4452 /* What's the color value in the feedback buffer? */
4453 const DWORD *color_s =
4454 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4455 if(!color_s) {
4456 static BOOL warned = FALSE;
4457
4458 if(!warned) {
4459 ERR("No specular color in source, but destination has one\n");
4460 warned = TRUE;
4461 }
4462
4463 *( (DWORD *) dest_ptr) = 0xFF000000;
4464 dest_ptr += sizeof(DWORD);
4465
4466 if(dest_conv) {
4467 *( (DWORD *) dest_conv) = 0xFF000000;
4468 dest_conv += sizeof(DWORD);
4469 }
4470 }
4471 else {
4472 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4473 if(dest_conv) {
4474 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4475 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4476 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4477 dest_conv += sizeof(DWORD);
4478 }
4479 }
4480 }
4481
4482 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4483 const float *tex_coord =
4484 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4485 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4486 if(!tex_coord) {
4487 ERR("No source texture, but destination requests one\n");
4488 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4489 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4490 }
4491 else {
4492 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4493 if(dest_conv) {
4494 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4495 }
4496 }
4497 }
4498 }
4499
4500 if(dest_conv) {
4501 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4502 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4503 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4504 dwCount * get_flexible_vertex_size(DestFVF),
4505 dest_conv_addr));
4506 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4507 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4508 }
4509
4510 LEAVE_GL();
4511
4512 return WINED3D_OK;
4513}
4514#undef copy_and_next
4515
4516static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4518 WineDirect3DVertexStridedData strided;
4519 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4520 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4521
4522 if(pVertexDecl) {
4523 ERR("Output vertex declaration not implemented yet\n");
4524 }
4525
4526 /* Need any context to write to the vbo. */
4527 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4528
4529 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4530 * control the streamIsUP flag, thus restore it afterwards.
4531 */
4532 This->stateBlock->streamIsUP = FALSE;
4533 memset(&strided, 0, sizeof(strided));
4534 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4535 This->stateBlock->streamIsUP = streamWasUP;
4536
4537 if(vbo || SrcStartIndex) {
4538 unsigned int i;
4539 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4540 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4541 *
4542 * Also get the start index in, but only loop over all elements if there's something to add at all.
4543 */
4544#define FIXSRC(type) \
4545 if(strided.u.s.type.VBO) { \
4546 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4547 strided.u.s.type.VBO = 0; \
4548 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4549 ENTER_GL(); \
4550 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4551 vb->vbo = 0; \
4552 LEAVE_GL(); \
4553 } \
4554 if(strided.u.s.type.lpData) { \
4555 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4556 }
4557 FIXSRC(position);
4558 FIXSRC(blendWeights);
4559 FIXSRC(blendMatrixIndices);
4560 FIXSRC(normal);
4561 FIXSRC(pSize);
4562 FIXSRC(diffuse);
4563 FIXSRC(specular);
4564 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4565 FIXSRC(texCoords[i]);
4566 }
4567 FIXSRC(position2);
4568 FIXSRC(normal2);
4569 FIXSRC(tangent);
4570 FIXSRC(binormal);
4571 FIXSRC(tessFactor);
4572 FIXSRC(fog);
4573 FIXSRC(depth);
4574 FIXSRC(sample);
4575#undef FIXSRC
4576 }
4577
4578 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4579}
4580
4581/*****
4582 * Get / Set Texture Stage States
4583 * TODO: Verify against dx9 definitions
4584 *****/
4585static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4587 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4588
4589 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4590
4591 if (Stage >= MAX_TEXTURES) {
4592 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4593 return WINED3D_OK;
4594 }
4595
4596 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4597 This->updateStateBlock->textureState[Stage][Type] = Value;
4598
4599 if (This->isRecordingState) {
4600 TRACE("Recording... not performing anything\n");
4601 return WINED3D_OK;
4602 }
4603
4604 /* Checked after the assignments to allow proper stateblock recording */
4605 if(oldValue == Value) {
4606 TRACE("App is setting the old value over, nothing to do\n");
4607 return WINED3D_OK;
4608 }
4609
4610 if(Stage > This->stateBlock->lowest_disabled_stage &&
4611 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4612 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4613 * Changes in other states are important on disabled stages too
4614 */
4615 return WINED3D_OK;
4616 }
4617
4618 if(Type == WINED3DTSS_COLOROP) {
4619 int i;
4620
4621 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4622 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4623 * they have to be disabled
4624 *
4625 * The current stage is dirtified below.
4626 */
4627 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4628 TRACE("Additionally dirtifying stage %d\n", i);
4629 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4630 }
4631 This->stateBlock->lowest_disabled_stage = Stage;
4632 TRACE("New lowest disabled: %d\n", Stage);
4633 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4634 /* Previously disabled stage enabled. Stages above it may need enabling
4635 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4636 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4637 *
4638 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4639 */
4640
4641 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4642 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4643 break;
4644 }
4645 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4646 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4647 }
4648 This->stateBlock->lowest_disabled_stage = i;
4649 TRACE("New lowest disabled: %d\n", i);
4650 }
4651 }
4652
4653 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4654
4655 return WINED3D_OK;
4656}
4657
4658static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4660 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4661 *pValue = This->updateStateBlock->textureState[Stage][Type];
4662 return WINED3D_OK;
4663}
4664
4665/*****
4666 * Get / Set Texture
4667 *****/
4668static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4670 IWineD3DBaseTexture *oldTexture;
4671
4672 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4673
4674 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4675 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4676 }
4677
4678 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4679 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4680 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4681 }
4682
4683 oldTexture = This->updateStateBlock->textures[Stage];
4684
4685 if(pTexture != NULL) {
4686 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4687 */
4688 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4689 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4690 return WINED3DERR_INVALIDCALL;
4691 }
4692 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4693 }
4694
4695 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4696 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4697
4698 This->updateStateBlock->changed.textures[Stage] = TRUE;
4699 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4700 This->updateStateBlock->textures[Stage] = pTexture;
4701
4702 /* Handle recording of state blocks */
4703 if (This->isRecordingState) {
4704 TRACE("Recording... not performing anything\n");
4705 return WINED3D_OK;
4706 }
4707
4708 if(oldTexture == pTexture) {
4709 TRACE("App is setting the same texture again, nothing to do\n");
4710 return WINED3D_OK;
4711 }
4712
4713 /** NOTE: MSDN says that setTexture increases the reference count,
4714 * and that the application must set the texture back to null (or have a leaky application),
4715 * This means we should pass the refcount up to the parent
4716 *******************************/
4717 if (NULL != This->updateStateBlock->textures[Stage]) {
4718 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4719 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4720
4721 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4722 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4723 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4724 * so the COLOROP and ALPHAOP have to be dirtified.
4725 */
4726 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4727 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4728 }
4729 if(bindCount == 1) {
4730 new->baseTexture.sampler = Stage;
4731 }
4732 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4733
4734 }
4735
4736 if (NULL != oldTexture) {
4737 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4738 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4739
4740 IWineD3DBaseTexture_Release(oldTexture);
4741 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4742 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4743 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4744 }
4745
4746 if(bindCount && old->baseTexture.sampler == Stage) {
4747 int i;
4748 /* Have to do a search for the other sampler(s) where the texture is bound to
4749 * Shouldn't happen as long as apps bind a texture only to one stage
4750 */
4751 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4752 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4753 if(This->updateStateBlock->textures[i] == oldTexture) {
4754 old->baseTexture.sampler = i;
4755 break;
4756 }
4757 }
4758 }
4759 }
4760
4761 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4762
4763 return WINED3D_OK;
4764}
4765
4766static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4768
4769 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4770
4771 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4772 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4773 }
4774
4775 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4776 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4777 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4778 }
4779
4780 *ppTexture=This->stateBlock->textures[Stage];
4781 if (*ppTexture)
4782 IWineD3DBaseTexture_AddRef(*ppTexture);
4783
4784 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4785
4786 return WINED3D_OK;
4787}
4788
4789/*****
4790 * Get Back Buffer
4791 *****/
4792static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4793 IWineD3DSurface **ppBackBuffer) {
4794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4795 IWineD3DSwapChain *swapChain;
4796 HRESULT hr;
4797
4798 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4799
4800 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4801 if (hr == WINED3D_OK) {
4802 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4803 IWineD3DSwapChain_Release(swapChain);
4804 } else {
4805 *ppBackBuffer = NULL;
4806 }
4807 return hr;
4808}
4809
4810static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4812 WARN("(%p) : stub, calling idirect3d for now\n", This);
4813 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4814}
4815
4816static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4818 IWineD3DSwapChain *swapChain;
4819 HRESULT hr;
4820
4821 if(iSwapChain > 0) {
4822 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4823 if (hr == WINED3D_OK) {
4824 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4825 IWineD3DSwapChain_Release(swapChain);
4826 } else {
4827 FIXME("(%p) Error getting display mode\n", This);
4828 }
4829 } else {
4830 /* Don't read the real display mode,
4831 but return the stored mode instead. X11 can't change the color
4832 depth, and some apps are pretty angry if they SetDisplayMode from
4833 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4834
4835 Also don't relay to the swapchain because with ddraw it's possible
4836 that there isn't a swapchain at all */
4837 pMode->Width = This->ddraw_width;
4838 pMode->Height = This->ddraw_height;
4839 pMode->Format = This->ddraw_format;
4840 pMode->RefreshRate = 0;
4841 hr = WINED3D_OK;
4842 }
4843
4844 return hr;
4845}
4846
4847/*****
4848 * Stateblock related functions
4849 *****/
4850
4851static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4853 IWineD3DStateBlockImpl *object;
4854 HRESULT temp_result;
4855 int i;
4856
4857 TRACE("(%p)\n", This);
4858
4859 if (This->isRecordingState) {
4860 return WINED3DERR_INVALIDCALL;
4861 }
4862
4863 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4864 if (NULL == object ) {
4865 FIXME("(%p)Error allocating memory for stateblock\n", This);
4866 return E_OUTOFMEMORY;
4867 }
4868 TRACE("(%p) created object %p\n", This, object);
4869 object->wineD3DDevice= This;
4870 /** FIXME: object->parent = parent; **/
4871 object->parent = NULL;
4872 object->blockType = WINED3DSBT_RECORDED;
4873 object->ref = 1;
4874 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4875
4876 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4877 list_init(&object->lightMap[i]);
4878 }
4879
4880 temp_result = allocate_shader_constants(object);
4881 if (WINED3D_OK != temp_result)
4882 return temp_result;
4883
4884 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4885 This->updateStateBlock = object;
4886 This->isRecordingState = TRUE;
4887
4888 TRACE("(%p) recording stateblock %p\n",This , object);
4889 return WINED3D_OK;
4890}
4891
4892static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4894 unsigned int i, j;
4895 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4896
4897 if (!This->isRecordingState) {
4898 FIXME("(%p) not recording! returning error\n", This);
4899 *ppStateBlock = NULL;
4900 return WINED3DERR_INVALIDCALL;
4901 }
4902
4903 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4904 if(object->changed.renderState[i]) {
4905 object->contained_render_states[object->num_contained_render_states] = i;
4906 object->num_contained_render_states++;
4907 }
4908 }
4909 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4910 if(object->changed.transform[i]) {
4911 object->contained_transform_states[object->num_contained_transform_states] = i;
4912 object->num_contained_transform_states++;
4913 }
4914 }
4915 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4916 if(object->changed.vertexShaderConstantsF[i]) {
4917 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4918 object->num_contained_vs_consts_f++;
4919 }
4920 }
4921 for(i = 0; i < MAX_CONST_I; i++) {
4922 if (object->changed.vertexShaderConstantsI & (1 << i))
4923 {
4924 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4925 object->num_contained_vs_consts_i++;
4926 }
4927 }
4928 for(i = 0; i < MAX_CONST_B; i++) {
4929 if (object->changed.vertexShaderConstantsB & (1 << i))
4930 {
4931 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4932 object->num_contained_vs_consts_b++;
4933 }
4934 }
4935 for(i = 0; i < MAX_CONST_I; i++) {
4936 if (object->changed.pixelShaderConstantsI & (1 << i))
4937 {
4938 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4939 object->num_contained_ps_consts_i++;
4940 }
4941 }
4942 for(i = 0; i < MAX_CONST_B; i++) {
4943 if (object->changed.pixelShaderConstantsB & (1 << i))
4944 {
4945 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4946 object->num_contained_ps_consts_b++;
4947 }
4948 }
4949 for(i = 0; i < MAX_TEXTURES; i++) {
4950 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4951 if(object->changed.textureState[i][j]) {
4952 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4953 object->contained_tss_states[object->num_contained_tss_states].state = j;
4954 object->num_contained_tss_states++;
4955 }
4956 }
4957 }
4958 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4959 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4960 if(object->changed.samplerState[i][j]) {
4961 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4962 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4963 object->num_contained_sampler_states++;
4964 }
4965 }
4966 }
4967
4968 *ppStateBlock = (IWineD3DStateBlock*) object;
4969 This->isRecordingState = FALSE;
4970 This->updateStateBlock = This->stateBlock;
4971 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4972 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4973 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4974 return WINED3D_OK;
4975}
4976
4977/*****
4978 * Scene related functions
4979 *****/
4980static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4981 /* At the moment we have no need for any functionality at the beginning
4982 of a scene */
4983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4984 TRACE("(%p)\n", This);
4985
4986 if(This->inScene) {
4987 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4988 return WINED3DERR_INVALIDCALL;
4989 }
4990 This->inScene = TRUE;
4991 return WINED3D_OK;
4992}
4993
4994static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4996 TRACE("(%p)\n", This);
4997
4998 if(!This->inScene) {
4999 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
5000 return WINED3DERR_INVALIDCALL;
5001 }
5002
5003 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5004 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5005 glFlush();
5006 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5007 * fails
5008 */
5009
5010 This->inScene = FALSE;
5011 return WINED3D_OK;
5012}
5013
5014static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5015 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5016 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5018 IWineD3DSwapChain *swapChain = NULL;
5019 int i;
5020 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5021
5022 TRACE("(%p) Presenting the frame\n", This);
5023
5024 for(i = 0 ; i < swapchains ; i ++) {
5025
5026 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5027 TRACE("presentinng chain %d, %p\n", i, swapChain);
5028 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5029 IWineD3DSwapChain_Release(swapChain);
5030 }
5031
5032 return WINED3D_OK;
5033}
5034
5035/* Not called from the VTable (internal subroutine) */
5036HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5037 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5038 float Z, DWORD Stencil) {
5039 GLbitfield glMask = 0;
5040 unsigned int i;
5041 WINED3DRECT curRect;
5042 RECT vp_rect;
5043 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5044 UINT drawable_width, drawable_height;
5045 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5046 IWineD3DSwapChainImpl *swapchain = NULL;
5047
5048 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5049 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5050 * for the cleared parts, and the untouched parts.
5051 *
5052 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5053 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5054 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5055 * checking all this if the dest surface is in the drawable anyway.
5056 */
5057 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5058 while(1) {
5059 if(vp->X != 0 || vp->Y != 0 ||
5060 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5061 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5062 break;
5063 }
5064 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5065 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5066 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5067 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5068 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5069 break;
5070 }
5071 if(Count > 0 && pRects && (
5072 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5073 pRects[0].x2 < target->currentDesc.Width ||
5074 pRects[0].y2 < target->currentDesc.Height)) {
5075 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5076 break;
5077 }
5078 break;
5079 }
5080 }
5081
5082 target->get_drawable_size(target, &drawable_width, &drawable_height);
5083
5084 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5085 ENTER_GL();
5086
5087 /* Only set the values up once, as they are not changing */
5088 if (Flags & WINED3DCLEAR_STENCIL) {
5089 glClearStencil(Stencil);
5090 checkGLcall("glClearStencil");
5091 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5092 glStencilMask(0xFFFFFFFF);
5093 }
5094
5095 if (Flags & WINED3DCLEAR_ZBUFFER) {
5096 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5097 glDepthMask(GL_TRUE);
5098 glClearDepth(Z);
5099 checkGLcall("glClearDepth");
5100 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5101 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5102
5103 if (vp->X != 0 || vp->Y != 0 ||
5104 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5105 surface_load_ds_location(This->stencilBufferTarget, location);
5106 }
5107 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5108 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5109 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5110 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5111 surface_load_ds_location(This->stencilBufferTarget, location);
5112 }
5113 else if (Count > 0 && pRects && (
5114 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5115 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5116 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5117 surface_load_ds_location(This->stencilBufferTarget, location);
5118 }
5119 }
5120
5121 if (Flags & WINED3DCLEAR_TARGET) {
5122 TRACE("Clearing screen with glClear to color %x\n", Color);
5123 glClearColor(D3DCOLOR_R(Color),
5124 D3DCOLOR_G(Color),
5125 D3DCOLOR_B(Color),
5126 D3DCOLOR_A(Color));
5127 checkGLcall("glClearColor");
5128
5129 /* Clear ALL colors! */
5130 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5131 glMask = glMask | GL_COLOR_BUFFER_BIT;
5132 }
5133
5134 vp_rect.left = vp->X;
5135 vp_rect.top = vp->Y;
5136 vp_rect.right = vp->X + vp->Width;
5137 vp_rect.bottom = vp->Y + vp->Height;
5138 if (!(Count > 0 && pRects)) {
5139 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5140 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5141 }
5142 if(This->render_offscreen) {
5143 glScissor(vp_rect.left, vp_rect.top,
5144 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5145 } else {
5146 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5147 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5148 }
5149 checkGLcall("glScissor");
5150 glClear(glMask);
5151 checkGLcall("glClear");
5152 } else {
5153 /* Now process each rect in turn */
5154 for (i = 0; i < Count; i++) {
5155 /* Note gl uses lower left, width/height */
5156 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5157 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5158 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5159 }
5160 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5161 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5162 curRect.x1, (target->currentDesc.Height - curRect.y2),
5163 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5164
5165 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5166 * The rectangle is not cleared, no error is returned, but further rectanlges are
5167 * still cleared if they are valid
5168 */
5169 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5170 TRACE("Rectangle with negative dimensions, ignoring\n");
5171 continue;
5172 }
5173
5174 if(This->render_offscreen) {
5175 glScissor(curRect.x1, curRect.y1,
5176 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5177 } else {
5178 glScissor(curRect.x1, drawable_height - curRect.y2,
5179 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5180 }
5181 checkGLcall("glScissor");
5182
5183 glClear(glMask);
5184 checkGLcall("glClear");
5185 }
5186 }
5187
5188 /* Restore the old values (why..?) */
5189 if (Flags & WINED3DCLEAR_STENCIL) {
5190 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5191 }
5192 if (Flags & WINED3DCLEAR_TARGET) {
5193 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5194 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5195 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5196 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5197 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5198
5199 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5200 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5201 */
5202 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5203 }
5204 if (Flags & WINED3DCLEAR_ZBUFFER) {
5205 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5206 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5207 surface_modify_ds_location(This->stencilBufferTarget, location);
5208 }
5209
5210 LEAVE_GL();
5211
5212 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5213 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5214 glFlush();
5215 }
5216 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5217 }
5218
5219 return WINED3D_OK;
5220}
5221
5222static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5223 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5225 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5226
5227 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5228 Count, pRects, Flags, Color, Z, Stencil);
5229
5230 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5231 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5232 /* TODO: What about depth stencil buffers without stencil bits? */
5233 return WINED3DERR_INVALIDCALL;
5234 }
5235
5236 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5237}
5238
5239/*****
5240 * Drawing functions
5241 *****/
5242static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5243 UINT PrimitiveCount) {
5244
5245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5246
5247 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5248 debug_d3dprimitivetype(PrimitiveType),
5249 StartVertex, PrimitiveCount);
5250
5251 if(!This->stateBlock->vertexDecl) {
5252 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5253 return WINED3DERR_INVALIDCALL;
5254 }
5255
5256 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5257 if(This->stateBlock->streamIsUP) {
5258 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5259 This->stateBlock->streamIsUP = FALSE;
5260 }
5261
5262 if(This->stateBlock->loadBaseVertexIndex != 0) {
5263 This->stateBlock->loadBaseVertexIndex = 0;
5264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5265 }
5266 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5267 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5268 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5269 return WINED3D_OK;
5270}
5271
5272/* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5273static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5274 WINED3DPRIMITIVETYPE PrimitiveType,
5275 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5276
5277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5278 UINT idxStride = 2;
5279 IWineD3DIndexBuffer *pIB;
5280 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5281 GLuint vbo;
5282
5283 pIB = This->stateBlock->pIndexData;
5284 if (!pIB) {
5285 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5286 * without an index buffer set. (The first time at least...)
5287 * D3D8 simply dies, but I doubt it can do much harm to return
5288 * D3DERR_INVALIDCALL there as well. */
5289 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5290 return WINED3DERR_INVALIDCALL;
5291 }
5292
5293 if(!This->stateBlock->vertexDecl) {
5294 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5295 return WINED3DERR_INVALIDCALL;
5296 }
5297
5298 if(This->stateBlock->streamIsUP) {
5299 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5300 This->stateBlock->streamIsUP = FALSE;
5301 }
5302 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5303
5304 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5305 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5306 minIndex, NumVertices, startIndex, primCount);
5307
5308 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5309 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5310 idxStride = 2;
5311 } else {
5312 idxStride = 4;
5313 }
5314
5315 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5316 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5317 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5318 }
5319
5320 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5321 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5322
5323 return WINED3D_OK;
5324}
5325
5326static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5327 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5328 UINT VertexStreamZeroStride) {
5329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5330 IWineD3DVertexBuffer *vb;
5331
5332 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5333 debug_d3dprimitivetype(PrimitiveType),
5334 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5335
5336 if(!This->stateBlock->vertexDecl) {
5337 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5338 return WINED3DERR_INVALIDCALL;
5339 }
5340
5341 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5342 vb = This->stateBlock->streamSource[0];
5343 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5344 if(vb) IWineD3DVertexBuffer_Release(vb);
5345 This->stateBlock->streamOffset[0] = 0;
5346 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5347 This->stateBlock->streamIsUP = TRUE;
5348 This->stateBlock->loadBaseVertexIndex = 0;
5349
5350 /* TODO: Only mark dirty if drawing from a different UP address */
5351 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5352
5353 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5354 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5355
5356 /* MSDN specifies stream zero settings must be set to NULL */
5357 This->stateBlock->streamStride[0] = 0;
5358 This->stateBlock->streamSource[0] = NULL;
5359
5360 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5361 * the new stream sources or use UP drawing again
5362 */
5363 return WINED3D_OK;
5364}
5365
5366static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5367 UINT MinVertexIndex, UINT NumVertices,
5368 UINT PrimitiveCount, CONST void* pIndexData,
5369 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5370 UINT VertexStreamZeroStride) {
5371 int idxStride;
5372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5373 IWineD3DVertexBuffer *vb;
5374 IWineD3DIndexBuffer *ib;
5375
5376 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5377 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5378 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5379 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5380
5381 if(!This->stateBlock->vertexDecl) {
5382 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5383 return WINED3DERR_INVALIDCALL;
5384 }
5385
5386 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5387 idxStride = 2;
5388 } else {
5389 idxStride = 4;
5390 }
5391
5392 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5393 vb = This->stateBlock->streamSource[0];
5394 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5395 if(vb) IWineD3DVertexBuffer_Release(vb);
5396 This->stateBlock->streamIsUP = TRUE;
5397 This->stateBlock->streamOffset[0] = 0;
5398 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5399
5400 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5401 This->stateBlock->baseVertexIndex = 0;
5402 This->stateBlock->loadBaseVertexIndex = 0;
5403 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5404 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5405 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5406
5407 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5408
5409 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5410 This->stateBlock->streamSource[0] = NULL;
5411 This->stateBlock->streamStride[0] = 0;
5412 ib = This->stateBlock->pIndexData;
5413 if(ib) {
5414 IWineD3DIndexBuffer_Release(ib);
5415 This->stateBlock->pIndexData = NULL;
5416 }
5417 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5418 * SetStreamSource to specify a vertex buffer
5419 */
5420
5421 return WINED3D_OK;
5422}
5423
5424static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5425 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5426 const WineDirect3DVertexStridedData *DrawPrimStrideData)
5427{
5428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5429
5430 /* Mark the state dirty until we have nicer tracking
5431 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5432 * that value.
5433 */
5434 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5435 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5436 This->stateBlock->baseVertexIndex = 0;
5437 This->up_strided = DrawPrimStrideData;
5438 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5439 This->up_strided = NULL;
5440 return WINED3D_OK;
5441}
5442
5443static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5444 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5445 const WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, const void *pIndexData,
5446 WINED3DFORMAT IndexDataFormat)
5447{
5448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5449 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5450
5451 /* Mark the state dirty until we have nicer tracking
5452 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5453 * that value.
5454 */
5455 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5456 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5457 This->stateBlock->streamIsUP = TRUE;
5458 This->stateBlock->baseVertexIndex = 0;
5459 This->up_strided = DrawPrimStrideData;
5460 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5461 This->up_strided = NULL;
5462 return WINED3D_OK;
5463}
5464
5465static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5466 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5467 * not callable by the app directly no parameter validation checks are needed here.
5468 */
5469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5470 WINED3DLOCKED_BOX src;
5471 WINED3DLOCKED_BOX dst;
5472 HRESULT hr;
5473 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5474
5475 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5476 * dirtification to improve loading performance.
5477 */
5478 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5479 if(FAILED(hr)) return hr;
5480 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5481 if(FAILED(hr)) {
5482 IWineD3DVolume_UnlockBox(pSourceVolume);
5483 return hr;
5484 }
5485
5486 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5487
5488 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5489 if(FAILED(hr)) {
5490 IWineD3DVolume_UnlockBox(pSourceVolume);
5491 } else {
5492 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5493 }
5494 return hr;
5495}
5496
5497/* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5498static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5499 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5500 HRESULT hr = WINED3D_OK;
5501 WINED3DRESOURCETYPE sourceType;
5502 WINED3DRESOURCETYPE destinationType;
5503 int i ,levels;
5504
5505 /* TODO: think about moving the code into IWineD3DBaseTexture */
5506
5507 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5508
5509 /* verify that the source and destination textures aren't NULL */
5510 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5511 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5512 This, pSourceTexture, pDestinationTexture);
5513 hr = WINED3DERR_INVALIDCALL;
5514 }
5515
5516 if (pSourceTexture == pDestinationTexture) {
5517 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5518 This, pSourceTexture, pDestinationTexture);
5519 hr = WINED3DERR_INVALIDCALL;
5520 }
5521 /* Verify that the source and destination textures are the same type */
5522 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5523 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5524
5525 if (sourceType != destinationType) {
5526 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5527 This);
5528 hr = WINED3DERR_INVALIDCALL;
5529 }
5530
5531 /* check that both textures have the identical numbers of levels */
5532 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5533 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5534 hr = WINED3DERR_INVALIDCALL;
5535 }
5536
5537 if (WINED3D_OK == hr) {
5538
5539 /* Make sure that the destination texture is loaded */
5540 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5541
5542 /* Update every surface level of the texture */
5543 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5544
5545 switch (sourceType) {
5546 case WINED3DRTYPE_TEXTURE:
5547 {
5548 IWineD3DSurface *srcSurface;
5549 IWineD3DSurface *destSurface;
5550
5551 for (i = 0 ; i < levels ; ++i) {
5552 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5553 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5554 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5555 IWineD3DSurface_Release(srcSurface);
5556 IWineD3DSurface_Release(destSurface);
5557 if (WINED3D_OK != hr) {
5558 WARN("(%p) : Call to update surface failed\n", This);
5559 return hr;
5560 }
5561 }
5562 }
5563 break;
5564 case WINED3DRTYPE_CUBETEXTURE:
5565 {
5566 IWineD3DSurface *srcSurface;
5567 IWineD3DSurface *destSurface;
5568 WINED3DCUBEMAP_FACES faceType;
5569
5570 for (i = 0 ; i < levels ; ++i) {
5571 /* Update each cube face */
5572 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5573 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5574 if (WINED3D_OK != hr) {
5575 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5576 } else {
5577 TRACE("Got srcSurface %p\n", srcSurface);
5578 }
5579 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5580 if (WINED3D_OK != hr) {
5581 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5582 } else {
5583 TRACE("Got desrSurface %p\n", destSurface);
5584 }
5585 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5586 IWineD3DSurface_Release(srcSurface);
5587 IWineD3DSurface_Release(destSurface);
5588 if (WINED3D_OK != hr) {
5589 WARN("(%p) : Call to update surface failed\n", This);
5590 return hr;
5591 }
5592 }
5593 }
5594 }
5595 break;
5596
5597 case WINED3DRTYPE_VOLUMETEXTURE:
5598 {
5599 IWineD3DVolume *srcVolume = NULL;
5600 IWineD3DVolume *destVolume = NULL;
5601
5602 for (i = 0 ; i < levels ; ++i) {
5603 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5604 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5605 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5606 IWineD3DVolume_Release(srcVolume);
5607 IWineD3DVolume_Release(destVolume);
5608 if (WINED3D_OK != hr) {
5609 WARN("(%p) : Call to update volume failed\n", This);
5610 return hr;
5611 }
5612 }
5613 }
5614 break;
5615
5616 default:
5617 FIXME("(%p) : Unsupported source and destination type\n", This);
5618 hr = WINED3DERR_INVALIDCALL;
5619 }
5620 }
5621
5622 return hr;
5623}
5624
5625static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5626 IWineD3DSwapChain *swapChain;
5627 HRESULT hr;
5628 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5629 if(hr == WINED3D_OK) {
5630 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5631 IWineD3DSwapChain_Release(swapChain);
5632 }
5633 return hr;
5634}
5635
5636static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5638 IWineD3DBaseTextureImpl *texture;
5639 const struct GlPixelFormatDesc *gl_info;
5640 DWORD i;
5641
5642 TRACE("(%p) : %p\n", This, pNumPasses);
5643
5644 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5645 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5646 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5647 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5648 }
5649 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5650 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5651 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5652 }
5653
5654 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5655 if(!texture) continue;
5656 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5657 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5658
5659 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5660 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5661 return E_FAIL;
5662 }
5663 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5664 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5665 return E_FAIL;
5666 }
5667 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5668 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5669 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5670 return E_FAIL;
5671 }
5672 }
5673
5674 /* return a sensible default */
5675 *pNumPasses = 1;
5676
5677 TRACE("returning D3D_OK\n");
5678 return WINED3D_OK;
5679}
5680
5681static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5682{
5683 int i;
5684
5685 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5686 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5687 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5688 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5689 }
5690 }
5691}
5692
5693static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5695 int j;
5696 UINT NewSize;
5697 PALETTEENTRY **palettes;
5698
5699 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5700
5701 if (PaletteNumber >= MAX_PALETTES) {
5702 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5703 return WINED3DERR_INVALIDCALL;
5704 }
5705
5706 if (PaletteNumber >= This->NumberOfPalettes) {
5707 NewSize = This->NumberOfPalettes;
5708 do {
5709 NewSize *= 2;
5710 } while(PaletteNumber >= NewSize);
5711 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5712 if (!palettes) {
5713 ERR("Out of memory!\n");
5714 return E_OUTOFMEMORY;
5715 }
5716 This->palettes = palettes;
5717 This->NumberOfPalettes = NewSize;
5718 }
5719
5720 if (!This->palettes[PaletteNumber]) {
5721 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5722 if (!This->palettes[PaletteNumber]) {
5723 ERR("Out of memory!\n");
5724 return E_OUTOFMEMORY;
5725 }
5726 }
5727
5728 for (j = 0; j < 256; ++j) {
5729 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5730 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5731 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5732 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5733 }
5734 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5735 TRACE("(%p) : returning\n", This);
5736 return WINED3D_OK;
5737}
5738
5739static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5741 int j;
5742 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5743 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5744 /* What happens in such situation isn't documented; Native seems to silently abort
5745 on such conditions. Return Invalid Call. */
5746 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5747 return WINED3DERR_INVALIDCALL;
5748 }
5749 for (j = 0; j < 256; ++j) {
5750 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5751 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5752 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5753 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5754 }
5755 TRACE("(%p) : returning\n", This);
5756 return WINED3D_OK;
5757}
5758
5759static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5761 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5762 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5763 (tested with reference rasterizer). Return Invalid Call. */
5764 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5765 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5766 return WINED3DERR_INVALIDCALL;
5767 }
5768 /*TODO: stateblocks */
5769 if (This->currentPalette != PaletteNumber) {
5770 This->currentPalette = PaletteNumber;
5771 dirtify_p8_texture_samplers(This);
5772 }
5773 TRACE("(%p) : returning\n", This);
5774 return WINED3D_OK;
5775}
5776
5777static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5779 if (PaletteNumber == NULL) {
5780 WARN("(%p) : returning Invalid Call\n", This);
5781 return WINED3DERR_INVALIDCALL;
5782 }
5783 /*TODO: stateblocks */
5784 *PaletteNumber = This->currentPalette;
5785 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5786 return WINED3D_OK;
5787}
5788
5789static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5791 static BOOL warned;
5792 if (!warned)
5793 {
5794 FIXME("(%p) : stub\n", This);
5795 warned = TRUE;
5796 }
5797
5798 This->softwareVertexProcessing = bSoftware;
5799 return WINED3D_OK;
5800}
5801
5802
5803static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5805 static BOOL warned;
5806 if (!warned)
5807 {
5808 FIXME("(%p) : stub\n", This);
5809 warned = TRUE;
5810 }
5811 return This->softwareVertexProcessing;
5812}
5813
5814
5815static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5817 IWineD3DSwapChain *swapChain;
5818 HRESULT hr;
5819
5820 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5821
5822 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5823 if(hr == WINED3D_OK){
5824 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5825 IWineD3DSwapChain_Release(swapChain);
5826 }else{
5827 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5828 }
5829 return hr;
5830}
5831
5832
5833static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5835 static BOOL warned;
5836 if(nSegments != 0.0f) {
5837 if (!warned)
5838 {
5839 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5840 warned = TRUE;
5841 }
5842 }
5843 return WINED3D_OK;
5844}
5845
5846static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5848 static BOOL warned;
5849 if (!warned)
5850 {
5851 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5852 warned = TRUE;
5853 }
5854 return 0.0f;
5855}
5856
5857static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5859 /** TODO: remove casts to IWineD3DSurfaceImpl
5860 * NOTE: move code to surface to accomplish this
5861 ****************************************/
5862 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5863 int srcWidth, srcHeight;
5864 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5865 WINED3DFORMAT destFormat, srcFormat;
5866 UINT destSize;
5867 int srcLeft, destLeft, destTop;
5868 WINED3DPOOL srcPool, destPool;
5869 int offset = 0;
5870 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5871 glDescriptor *glDescription = NULL;
5872 GLenum dummy;
5873 int sampler;
5874 int bpp;
5875 CONVERT_TYPES convert = NO_CONVERSION;
5876
5877 WINED3DSURFACE_DESC winedesc;
5878
5879 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5880 memset(&winedesc, 0, sizeof(winedesc));
5881 winedesc.Width = &srcSurfaceWidth;
5882 winedesc.Height = &srcSurfaceHeight;
5883 winedesc.Pool = &srcPool;
5884 winedesc.Format = &srcFormat;
5885
5886 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5887
5888 winedesc.Width = &destSurfaceWidth;
5889 winedesc.Height = &destSurfaceHeight;
5890 winedesc.Pool = &destPool;
5891 winedesc.Format = &destFormat;
5892 winedesc.Size = &destSize;
5893
5894 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5895
5896 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5897 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5898 return WINED3DERR_INVALIDCALL;
5899 }
5900
5901 /* This call loads the opengl surface directly, instead of copying the surface to the
5902 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5903 * copy in sysmem and use regular surface loading.
5904 */
5905 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5906 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5907 if(convert != NO_CONVERSION) {
5908 return IWineD3DSurface_BltFast(pDestinationSurface,
5909 pDestPoint ? pDestPoint->x : 0,
5910 pDestPoint ? pDestPoint->y : 0,
5911 pSourceSurface, pSourceRect, 0);
5912 }
5913
5914 if (destFormat == WINED3DFMT_UNKNOWN) {
5915 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5916 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5917
5918 /* Get the update surface description */
5919 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5920 }
5921
5922 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5923
5924 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5925 ENTER_GL();
5926 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5927 checkGLcall("glActiveTextureARB");
5928 LEAVE_GL();
5929 }
5930
5931 /* Make sure the surface is loaded and up to date */
5932 IWineD3DSurface_PreLoad(pDestinationSurface);
5933 IWineD3DSurface_BindTexture(pDestinationSurface);
5934
5935 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5936
5937 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5938 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5939 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5940 srcLeft = pSourceRect ? pSourceRect->left : 0;
5941 destLeft = pDestPoint ? pDestPoint->x : 0;
5942 destTop = pDestPoint ? pDestPoint->y : 0;
5943
5944
5945 /* This function doesn't support compressed textures
5946 the pitch is just bytesPerPixel * width */
5947 if(srcWidth != srcSurfaceWidth || srcLeft ){
5948 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5949 offset += srcLeft * pSrcSurface->bytesPerPixel;
5950 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5951 }
5952 /* TODO DXT formats */
5953
5954 if(pSourceRect != NULL && pSourceRect->top != 0){
5955 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5956 }
5957 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5958 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
5959 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5960
5961 /* Sanity check */
5962 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5963
5964 /* need to lock the surface to get the data */
5965 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5966 }
5967
5968 ENTER_GL();
5969
5970 /* TODO: Cube and volume support */
5971 if(rowoffset != 0){
5972 /* not a whole row so we have to do it a line at a time */
5973 int j;
5974
5975 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5976 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5977
5978 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5979
5980 glTexSubImage2D(glDescription->target
5981 ,glDescription->level
5982 ,destLeft
5983 ,j
5984 ,srcWidth
5985 ,1
5986 ,glDescription->glFormat
5987 ,glDescription->glType
5988 ,data /* could be quicker using */
5989 );
5990 data += rowoffset;
5991 }
5992
5993 } else { /* Full width, so just write out the whole texture */
5994 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5995
5996 if (WINED3DFMT_DXT1 == destFormat ||
5997 WINED3DFMT_DXT2 == destFormat ||
5998 WINED3DFMT_DXT3 == destFormat ||
5999 WINED3DFMT_DXT4 == destFormat ||
6000 WINED3DFMT_DXT5 == destFormat) {
6001 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6002 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6003 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6004 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6005 } if (destFormat != srcFormat) {
6006 FIXME("Updating mixed format compressed texture is not curretly support\n");
6007 } else {
6008 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6009 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
6010 }
6011 } else {
6012 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6013 }
6014
6015
6016 } else {
6017 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6018 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
6019 }
6020 }
6021 checkGLcall("glTexSubImage2D");
6022
6023 LEAVE_GL();
6024
6025 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6026 sampler = This->rev_tex_unit_map[0];
6027 if (sampler != -1) {
6028 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6029 }
6030
6031 return WINED3D_OK;
6032}
6033
6034static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6036 struct WineD3DRectPatch *patch;
6037 unsigned int i;
6038 struct list *e;
6039 BOOL found;
6040 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6041
6042 if(!(Handle || pRectPatchInfo)) {
6043 /* TODO: Write a test for the return value, thus the FIXME */
6044 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6045 return WINED3DERR_INVALIDCALL;
6046 }
6047
6048 if(Handle) {
6049 i = PATCHMAP_HASHFUNC(Handle);
6050 found = FALSE;
6051 LIST_FOR_EACH(e, &This->patches[i]) {
6052 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6053 if(patch->Handle == Handle) {
6054 found = TRUE;
6055 break;
6056 }
6057 }
6058
6059 if(!found) {
6060 TRACE("Patch does not exist. Creating a new one\n");
6061 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6062 patch->Handle = Handle;
6063 list_add_head(&This->patches[i], &patch->entry);
6064 } else {
6065 TRACE("Found existing patch %p\n", patch);
6066 }
6067 } else {
6068 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6069 * attributes we have to tesselate, read back, and draw. This needs a patch
6070 * management structure instance. Create one.
6071 *
6072 * A possible improvement is to check if a vertex shader is used, and if not directly
6073 * draw the patch.
6074 */
6075 FIXME("Drawing an uncached patch. This is slow\n");
6076 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6077 }
6078
6079 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6080 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6081 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6082 HRESULT hr;
6083 TRACE("Tesselation density or patch info changed, retesselating\n");
6084
6085 if(pRectPatchInfo) {
6086 patch->RectPatchInfo = *pRectPatchInfo;
6087 }
6088 patch->numSegs[0] = pNumSegs[0];
6089 patch->numSegs[1] = pNumSegs[1];
6090 patch->numSegs[2] = pNumSegs[2];
6091 patch->numSegs[3] = pNumSegs[3];
6092
6093 hr = tesselate_rectpatch(This, patch);
6094 if(FAILED(hr)) {
6095 WARN("Patch tesselation failed\n");
6096
6097 /* Do not release the handle to store the params of the patch */
6098 if(!Handle) {
6099 HeapFree(GetProcessHeap(), 0, patch);
6100 }
6101 return hr;
6102 }
6103 }
6104
6105 This->currentPatch = patch;
6106 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6107 This->currentPatch = NULL;
6108
6109 /* Destroy uncached patches */
6110 if(!Handle) {
6111 HeapFree(GetProcessHeap(), 0, patch->mem);
6112 HeapFree(GetProcessHeap(), 0, patch);
6113 }
6114 return WINED3D_OK;
6115}
6116
6117static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6119 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6120 FIXME("(%p) : Stub\n", This);
6121 return WINED3D_OK;
6122}
6123
6124static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6126 int i;
6127 struct WineD3DRectPatch *patch;
6128 struct list *e;
6129 TRACE("(%p) Handle(%d)\n", This, Handle);
6130
6131 i = PATCHMAP_HASHFUNC(Handle);
6132 LIST_FOR_EACH(e, &This->patches[i]) {
6133 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6134 if(patch->Handle == Handle) {
6135 TRACE("Deleting patch %p\n", patch);
6136 list_remove(&patch->entry);
6137 HeapFree(GetProcessHeap(), 0, patch->mem);
6138 HeapFree(GetProcessHeap(), 0, patch);
6139 return WINED3D_OK;
6140 }
6141 }
6142
6143 /* TODO: Write a test for the return value */
6144 FIXME("Attempt to destroy nonexistent patch\n");
6145 return WINED3DERR_INVALIDCALL;
6146}
6147
6148static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6149 HRESULT hr;
6150 IWineD3DSwapChain *swapchain;
6151
6152 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6153 if (SUCCEEDED(hr)) {
6154 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6155 return swapchain;
6156 }
6157
6158 return NULL;
6159}
6160
6161static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6163 IWineD3DSwapChain *swapchain;
6164
6165 swapchain = get_swapchain(surface);
6166 if (swapchain) {
6167 GLenum buffer;
6168
6169 TRACE("Surface %p is onscreen\n", surface);
6170
6171 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6172 ENTER_GL();
6173 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6174 buffer = surface_get_gl_buffer(surface, swapchain);
6175 glDrawBuffer(buffer);
6176 checkGLcall("glDrawBuffer()");
6177 } else {
6178 TRACE("Surface %p is offscreen\n", surface);
6179
6180 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6181 ENTER_GL();
6182 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6183 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6184 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6185 checkGLcall("glFramebufferRenderbufferEXT");
6186 }
6187
6188 if (rect) {
6189 glEnable(GL_SCISSOR_TEST);
6190 if(!swapchain) {
6191 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6192 } else {
6193 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6194 rect->x2 - rect->x1, rect->y2 - rect->y1);
6195 }
6196 checkGLcall("glScissor");
6197 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6198 } else {
6199 glDisable(GL_SCISSOR_TEST);
6200 }
6201 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6202
6203 glDisable(GL_BLEND);
6204 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6205
6206 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6207 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6208
6209 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6210 glClear(GL_COLOR_BUFFER_BIT);
6211 checkGLcall("glClear");
6212
6213 if (This->activeContext->current_fbo) {
6214 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6215 } else {
6216 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6217 checkGLcall("glBindFramebuffer()");
6218 }
6219
6220 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6221 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6222 glDrawBuffer(GL_BACK);
6223 checkGLcall("glDrawBuffer()");
6224 }
6225
6226 LEAVE_GL();
6227}
6228
6229static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6230 unsigned int r, g, b, a;
6231 DWORD ret;
6232
6233 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6234 destfmt == WINED3DFMT_R8G8B8)
6235 return color;
6236
6237 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6238
6239 a = (color & 0xff000000) >> 24;
6240 r = (color & 0x00ff0000) >> 16;
6241 g = (color & 0x0000ff00) >> 8;
6242 b = (color & 0x000000ff) >> 0;
6243
6244 switch(destfmt)
6245 {
6246 case WINED3DFMT_R5G6B5:
6247 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6248 r = (r * 32) / 256;
6249 g = (g * 64) / 256;
6250 b = (b * 32) / 256;
6251 ret = r << 11;
6252 ret |= g << 5;
6253 ret |= b;
6254 TRACE("Returning %08x\n", ret);
6255 return ret;
6256
6257 case WINED3DFMT_X1R5G5B5:
6258 case WINED3DFMT_A1R5G5B5:
6259 a = (a * 2) / 256;
6260 r = (r * 32) / 256;
6261 g = (g * 32) / 256;
6262 b = (b * 32) / 256;
6263 ret = a << 15;
6264 ret |= r << 10;
6265 ret |= g << 5;
6266 ret |= b << 0;
6267 TRACE("Returning %08x\n", ret);
6268 return ret;
6269
6270 case WINED3DFMT_A8:
6271 TRACE("Returning %08x\n", a);
6272 return a;
6273
6274 case WINED3DFMT_X4R4G4B4:
6275 case WINED3DFMT_A4R4G4B4:
6276 a = (a * 16) / 256;
6277 r = (r * 16) / 256;
6278 g = (g * 16) / 256;
6279 b = (b * 16) / 256;
6280 ret = a << 12;
6281 ret |= r << 8;
6282 ret |= g << 4;
6283 ret |= b << 0;
6284 TRACE("Returning %08x\n", ret);
6285 return ret;
6286
6287 case WINED3DFMT_R3G3B2:
6288 r = (r * 8) / 256;
6289 g = (g * 8) / 256;
6290 b = (b * 4) / 256;
6291 ret = r << 5;
6292 ret |= g << 2;
6293 ret |= b << 0;
6294 TRACE("Returning %08x\n", ret);
6295 return ret;
6296
6297 case WINED3DFMT_X8B8G8R8:
6298 case WINED3DFMT_A8B8G8R8:
6299 ret = a << 24;
6300 ret |= b << 16;
6301 ret |= g << 8;
6302 ret |= r << 0;
6303 TRACE("Returning %08x\n", ret);
6304 return ret;
6305
6306 case WINED3DFMT_A2R10G10B10:
6307 a = (a * 4) / 256;
6308 r = (r * 1024) / 256;
6309 g = (g * 1024) / 256;
6310 b = (b * 1024) / 256;
6311 ret = a << 30;
6312 ret |= r << 20;
6313 ret |= g << 10;
6314 ret |= b << 0;
6315 TRACE("Returning %08x\n", ret);
6316 return ret;
6317
6318 case WINED3DFMT_A2B10G10R10:
6319 a = (a * 4) / 256;
6320 r = (r * 1024) / 256;
6321 g = (g * 1024) / 256;
6322 b = (b * 1024) / 256;
6323 ret = a << 30;
6324 ret |= b << 20;
6325 ret |= g << 10;
6326 ret |= r << 0;
6327 TRACE("Returning %08x\n", ret);
6328 return ret;
6329
6330 default:
6331 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6332 return 0;
6333 }
6334}
6335
6336static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6338 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6339 WINEDDBLTFX BltFx;
6340 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6341
6342 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6343 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6344 return WINED3DERR_INVALIDCALL;
6345 }
6346
6347 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6348 color_fill_fbo(iface, pSurface, pRect, color);
6349 return WINED3D_OK;
6350 } else {
6351 /* Just forward this to the DirectDraw blitting engine */
6352 memset(&BltFx, 0, sizeof(BltFx));
6353 BltFx.dwSize = sizeof(BltFx);
6354 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6355 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6356 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6357 }
6358}
6359
6360/* rendertarget and depth stencil functions */
6361static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6363
6364 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6365 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6366 return WINED3DERR_INVALIDCALL;
6367 }
6368
6369 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6370 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6371 /* Note inc ref on returned surface */
6372 if(*ppRenderTarget != NULL)
6373 IWineD3DSurface_AddRef(*ppRenderTarget);
6374 return WINED3D_OK;
6375}
6376
6377static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6379 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6380 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6381 IWineD3DSwapChainImpl *Swapchain;
6382 HRESULT hr;
6383
6384 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6385
6386 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6387 if(hr != WINED3D_OK) {
6388 ERR("Can't get the swapchain\n");
6389 return hr;
6390 }
6391
6392 /* Make sure to release the swapchain */
6393 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6394
6395 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6396 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6397 return WINED3DERR_INVALIDCALL;
6398 }
6399 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6400 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6401 return WINED3DERR_INVALIDCALL;
6402 }
6403
6404 if(Swapchain->frontBuffer != Front) {
6405 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6406
6407 if(Swapchain->frontBuffer)
6408 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6409 Swapchain->frontBuffer = Front;
6410
6411 if(Swapchain->frontBuffer) {
6412 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6413 }
6414 }
6415
6416 if(Back && !Swapchain->backBuffer) {
6417 /* We need memory for the back buffer array - only one back buffer this way */
6418 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6419 if(!Swapchain->backBuffer) {
6420 ERR("Out of memory\n");
6421 return E_OUTOFMEMORY;
6422 }
6423 }
6424
6425 if(Swapchain->backBuffer[0] != Back) {
6426 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6427
6428 /* What to do about the context here in the case of multithreading? Not sure.
6429 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6430 */
6431 ENTER_GL();
6432 if(!Swapchain->backBuffer[0]) {
6433 /* GL was told to draw to the front buffer at creation,
6434 * undo that
6435 */
6436 glDrawBuffer(GL_BACK);
6437 checkGLcall("glDrawBuffer(GL_BACK)");
6438 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6439 Swapchain->presentParms.BackBufferCount = 1;
6440 } else if (!Back) {
6441 /* That makes problems - disable for now */
6442 /* glDrawBuffer(GL_FRONT); */
6443 checkGLcall("glDrawBuffer(GL_FRONT)");
6444 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6445 Swapchain->presentParms.BackBufferCount = 0;
6446 }
6447 LEAVE_GL();
6448
6449 if(Swapchain->backBuffer[0])
6450 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6451 Swapchain->backBuffer[0] = Back;
6452
6453 if(Swapchain->backBuffer[0]) {
6454 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6455 } else {
6456 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6457 Swapchain->backBuffer = NULL;
6458 }
6459
6460 }
6461
6462 return WINED3D_OK;
6463}
6464
6465static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6467 *ppZStencilSurface = This->stencilBufferTarget;
6468 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6469
6470 if(*ppZStencilSurface != NULL) {
6471 /* Note inc ref on returned surface */
6472 IWineD3DSurface_AddRef(*ppZStencilSurface);
6473 return WINED3D_OK;
6474 } else {
6475 return WINED3DERR_NOTFOUND;
6476 }
6477}
6478
6479void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6480 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6481{
6482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6483 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6484 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6485 GLenum gl_filter;
6486 POINT offset = {0, 0};
6487
6488 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6489 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6490 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6491 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6492
6493 switch (filter) {
6494 case WINED3DTEXF_LINEAR:
6495 gl_filter = GL_LINEAR;
6496 break;
6497
6498 default:
6499 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6500 case WINED3DTEXF_NONE:
6501 case WINED3DTEXF_POINT:
6502 gl_filter = GL_NEAREST;
6503 break;
6504 }
6505
6506 /* Attach src surface to src fbo */
6507 src_swapchain = get_swapchain(src_surface);
6508 if (src_swapchain) {
6509 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6510
6511 TRACE("Source surface %p is onscreen\n", src_surface);
6512 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6513 /* Make sure the drawable is up to date. In the offscreen case
6514 * attach_surface_fbo() implicitly takes care of this. */
6515 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6516
6517 if(buffer == GL_FRONT) {
6518 RECT windowsize;
6519 UINT h;
6520 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6521 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6522 h = windowsize.bottom - windowsize.top;
6523 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6524 src_rect->y1 = offset.y + h - src_rect->y1;
6525 src_rect->y2 = offset.y + h - src_rect->y2;
6526 } else {
6527 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6528 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6529 }
6530
6531 ENTER_GL();
6532 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6533 glReadBuffer(buffer);
6534 checkGLcall("glReadBuffer()");
6535 } else {
6536 TRACE("Source surface %p is offscreen\n", src_surface);
6537 ENTER_GL();
6538 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6539 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6540 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6541 checkGLcall("glReadBuffer()");
6542 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6543 checkGLcall("glFramebufferRenderbufferEXT");
6544 }
6545 LEAVE_GL();
6546
6547 /* Attach dst surface to dst fbo */
6548 dst_swapchain = get_swapchain(dst_surface);
6549 if (dst_swapchain) {
6550 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6551
6552 TRACE("Destination surface %p is onscreen\n", dst_surface);
6553 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6554 /* Make sure the drawable is up to date. In the offscreen case
6555 * attach_surface_fbo() implicitly takes care of this. */
6556 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6557
6558 if(buffer == GL_FRONT) {
6559 RECT windowsize;
6560 UINT h;
6561 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6562 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6563 h = windowsize.bottom - windowsize.top;
6564 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6565 dst_rect->y1 = offset.y + h - dst_rect->y1;
6566 dst_rect->y2 = offset.y + h - dst_rect->y2;
6567 } else {
6568 /* Screen coords = window coords, surface height = window height */
6569 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6570 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6571 }
6572
6573 ENTER_GL();
6574 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6575 glDrawBuffer(buffer);
6576 checkGLcall("glDrawBuffer()");
6577 } else {
6578 TRACE("Destination surface %p is offscreen\n", dst_surface);
6579
6580 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6581 if(!src_swapchain) {
6582 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6583 }
6584
6585 ENTER_GL();
6586 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6587 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6588 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6589 checkGLcall("glDrawBuffer()");
6590 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6591 checkGLcall("glFramebufferRenderbufferEXT");
6592 }
6593 glDisable(GL_SCISSOR_TEST);
6594 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6595
6596 if (flip) {
6597 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6598 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6599 checkGLcall("glBlitFramebuffer()");
6600 } else {
6601 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6602 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6603 checkGLcall("glBlitFramebuffer()");
6604 }
6605
6606 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6607
6608 if (This->activeContext->current_fbo) {
6609 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6610 } else {
6611 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6612 checkGLcall("glBindFramebuffer()");
6613 }
6614
6615 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6616 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6617 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6618 glDrawBuffer(GL_BACK);
6619 checkGLcall("glDrawBuffer()");
6620 }
6621 LEAVE_GL();
6622}
6623
6624static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6626 WINED3DVIEWPORT viewport;
6627
6628 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6629
6630 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6631 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6632 This, RenderTargetIndex, GL_LIMITS(buffers));
6633 return WINED3DERR_INVALIDCALL;
6634 }
6635
6636 /* MSDN says that null disables the render target
6637 but a device must always be associated with a render target
6638 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6639 */
6640 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6641 FIXME("Trying to set render target 0 to NULL\n");
6642 return WINED3DERR_INVALIDCALL;
6643 }
6644 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6645 FIXME("(%p)Trying to set the render target to a surface(%p) that wasn't created with a usage of WINED3DUSAGE_RENDERTARGET\n",This ,pRenderTarget);
6646 return WINED3DERR_INVALIDCALL;
6647 }
6648
6649 /* If we are trying to set what we already have, don't bother */
6650 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6651 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6652 return WINED3D_OK;
6653 }
6654 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6655 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6656 This->render_targets[RenderTargetIndex] = pRenderTarget;
6657
6658 /* Render target 0 is special */
6659 if(RenderTargetIndex == 0) {
6660 /* Finally, reset the viewport as the MSDN states. */
6661 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6662 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6663 viewport.X = 0;
6664 viewport.Y = 0;
6665 viewport.MaxZ = 1.0f;
6666 viewport.MinZ = 0.0f;
6667 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6668 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6669 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6670 */
6671 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6672 }
6673 return WINED3D_OK;
6674}
6675
6676static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6678 HRESULT hr = WINED3D_OK;
6679 IWineD3DSurface *tmp;
6680
6681 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6682
6683 if (pNewZStencil == This->stencilBufferTarget) {
6684 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6685 } else {
6686 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6687 * depending on the renter target implementation being used.
6688 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6689 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6690 * stencil buffer and incur an extra memory overhead
6691 ******************************************************/
6692
6693 if (This->stencilBufferTarget) {
6694 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6695 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6696 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6697 } else {
6698 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6699 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6700 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6701 }
6702 }
6703
6704 tmp = This->stencilBufferTarget;
6705 This->stencilBufferTarget = pNewZStencil;
6706 /* should we be calling the parent or the wined3d surface? */
6707 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6708 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6709 hr = WINED3D_OK;
6710
6711 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6712 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6713 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6714 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6715 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6716 }
6717 }
6718
6719 return hr;
6720}
6721
6722static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6723 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6725 /* TODO: the use of Impl is deprecated. */
6726 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6727 WINED3DLOCKED_RECT lockedRect;
6728
6729 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6730
6731 /* some basic validation checks */
6732 if(This->cursorTexture) {
6733 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6734 ENTER_GL();
6735 glDeleteTextures(1, &This->cursorTexture);
6736 LEAVE_GL();
6737 This->cursorTexture = 0;
6738 }
6739
6740 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6741 This->haveHardwareCursor = TRUE;
6742 else
6743 This->haveHardwareCursor = FALSE;
6744
6745 if(pCursorBitmap) {
6746 WINED3DLOCKED_RECT rect;
6747
6748 /* MSDN: Cursor must be A8R8G8B8 */
6749 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6750 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6751 return WINED3DERR_INVALIDCALL;
6752 }
6753
6754 /* MSDN: Cursor must be smaller than the display mode */
6755 if(pSur->currentDesc.Width > This->ddraw_width ||
6756 pSur->currentDesc.Height > This->ddraw_height) {
6757 ERR("(%p) : Surface(%p) is %dx%d pixels, but screen res is %dx%d\n", This, pSur, pSur->currentDesc.Width, pSur->currentDesc.Height, This->ddraw_width, This->ddraw_height);
6758 return WINED3DERR_INVALIDCALL;
6759 }
6760
6761 if (!This->haveHardwareCursor) {
6762 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6763
6764 /* Do not store the surface's pointer because the application may
6765 * release it after setting the cursor image. Windows doesn't
6766 * addref the set surface, so we can't do this either without
6767 * creating circular refcount dependencies. Copy out the gl texture
6768 * instead.
6769 */
6770 This->cursorWidth = pSur->currentDesc.Width;
6771 This->cursorHeight = pSur->currentDesc.Height;
6772 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6773 {
6774 const struct GlPixelFormatDesc *glDesc;
6775 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6776 char *mem, *bits = (char *)rect.pBits;
6777 GLint intfmt = glDesc->glInternal;
6778 GLint format = glDesc->glFormat;
6779 GLint type = glDesc->glType;
6780 INT height = This->cursorHeight;
6781 INT width = This->cursorWidth;
6782 INT bpp = tableEntry->bpp;
6783 INT i, sampler;
6784
6785 /* Reformat the texture memory (pitch and width can be
6786 * different) */
6787 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6788 for(i = 0; i < height; i++)
6789 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6790 IWineD3DSurface_UnlockRect(pCursorBitmap);
6791 ENTER_GL();
6792
6793 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6794 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6795 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6796 }
6797
6798 /* Make sure that a proper texture unit is selected */
6799 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6800 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6801 checkGLcall("glActiveTextureARB");
6802 }
6803 sampler = This->rev_tex_unit_map[0];
6804 if (sampler != -1) {
6805 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6806 }
6807 /* Create a new cursor texture */
6808 glGenTextures(1, &This->cursorTexture);
6809 checkGLcall("glGenTextures");
6810 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6811 checkGLcall("glBindTexture");
6812 /* Copy the bitmap memory into the cursor texture */
6813 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6814 HeapFree(GetProcessHeap(), 0, mem);
6815 checkGLcall("glTexImage2D");
6816
6817 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6818 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6819 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6820 }
6821
6822 LEAVE_GL();
6823 }
6824 else
6825 {
6826 FIXME("A cursor texture was not returned.\n");
6827 This->cursorTexture = 0;
6828 }
6829 }
6830 else
6831 {
6832 /* Draw a hardware cursor */
6833 ICONINFO cursorInfo;
6834 HCURSOR cursor;
6835 /* Create and clear maskBits because it is not needed for
6836 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6837 * chunks. */
6838 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6839 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6840 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6841 WINED3DLOCK_NO_DIRTY_UPDATE |
6842 WINED3DLOCK_READONLY
6843 );
6844 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6845 pSur->currentDesc.Height);
6846
6847 cursorInfo.fIcon = FALSE;
6848 cursorInfo.xHotspot = XHotSpot;
6849 cursorInfo.yHotspot = YHotSpot;
6850 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6851 pSur->currentDesc.Height, 1,
6852 1, &maskBits);
6853 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6854 pSur->currentDesc.Height, 1,
6855 32, lockedRect.pBits);
6856 IWineD3DSurface_UnlockRect(pCursorBitmap);
6857 /* Create our cursor and clean up. */
6858 cursor = CreateIconIndirect(&cursorInfo);
6859 SetCursor(cursor);
6860 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6861 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6862 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6863 This->hardwareCursor = cursor;
6864 HeapFree(GetProcessHeap(), 0, maskBits);
6865 }
6866 }
6867
6868 This->xHotSpot = XHotSpot;
6869 This->yHotSpot = YHotSpot;
6870 return WINED3D_OK;
6871}
6872
6873static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6875 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6876
6877 This->xScreenSpace = XScreenSpace;
6878 This->yScreenSpace = YScreenSpace;
6879
6880 return;
6881
6882}
6883
6884static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6886 BOOL oldVisible = This->bCursorVisible;
6887 POINT pt;
6888
6889 TRACE("(%p) : visible(%d)\n", This, bShow);
6890
6891 /*
6892 * When ShowCursor is first called it should make the cursor appear at the OS's last
6893 * known cursor position. Because of this, some applications just repetitively call
6894 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6895 */
6896 GetCursorPos(&pt);
6897 This->xScreenSpace = pt.x;
6898 This->yScreenSpace = pt.y;
6899
6900 if (This->haveHardwareCursor) {
6901 This->bCursorVisible = bShow;
6902 if (bShow)
6903 SetCursor(This->hardwareCursor);
6904 else
6905 SetCursor(NULL);
6906 }
6907 else
6908 {
6909 if (This->cursorTexture)
6910 This->bCursorVisible = bShow;
6911 }
6912
6913 return oldVisible;
6914}
6915
6916static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6918 IWineD3DResourceImpl *resource;
6919 TRACE("(%p) : state (%u)\n", This, This->state);
6920
6921 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6922 switch (This->state) {
6923 case WINED3D_OK:
6924 return WINED3D_OK;
6925 case WINED3DERR_DEVICELOST:
6926 {
6927 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6928 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6929 return WINED3DERR_DEVICENOTRESET;
6930 }
6931 return WINED3DERR_DEVICELOST;
6932 }
6933 case WINED3DERR_DRIVERINTERNALERROR:
6934 return WINED3DERR_DRIVERINTERNALERROR;
6935 }
6936
6937 /* Unknown state */
6938 return WINED3DERR_DRIVERINTERNALERROR;
6939}
6940
6941
6942static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6944 /** FIXME: Resource tracking needs to be done,
6945 * The closes we can do to this is set the priorities of all managed textures low
6946 * and then reset them.
6947 ***********************************************************/
6948 FIXME("(%p) : stub\n", This);
6949 return WINED3D_OK;
6950}
6951
6952static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6953{
6954 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6955
6956 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6957 if(surface->Flags & SFLAG_DIBSECTION) {
6958 /* Release the DC */
6959 SelectObject(surface->hDC, surface->dib.holdbitmap);
6960 DeleteDC(surface->hDC);
6961 /* Release the DIB section */
6962 DeleteObject(surface->dib.DIBsection);
6963 surface->dib.bitmap_data = NULL;
6964 surface->resource.allocatedMemory = NULL;
6965 surface->Flags &= ~SFLAG_DIBSECTION;
6966 }
6967 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6968 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6969 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6970 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6971 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6972 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6973 } else {
6974 surface->pow2Width = surface->pow2Height = 1;
6975 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6976 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6977 }
6978 surface->glRect.left = 0;
6979 surface->glRect.top = 0;
6980 surface->glRect.right = surface->pow2Width;
6981 surface->glRect.bottom = surface->pow2Height;
6982
6983 if(surface->glDescription.textureName) {
6984 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6985 ENTER_GL();
6986 glDeleteTextures(1, &surface->glDescription.textureName);
6987 LEAVE_GL();
6988 surface->glDescription.textureName = 0;
6989 surface->Flags &= ~SFLAG_CLIENT;
6990 }
6991 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6992 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6993 surface->Flags |= SFLAG_NONPOW2;
6994 } else {
6995 surface->Flags &= ~SFLAG_NONPOW2;
6996 }
6997 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6998 surface->resource.allocatedMemory = NULL;
6999 surface->resource.heapMemory = NULL;
7000 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7001 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7002 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7003 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7004 } else {
7005 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7006 }
7007}
7008
7009static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7010 TRACE("Unloading resource %p\n", resource);
7011 IWineD3DResource_UnLoad(resource);
7012 IWineD3DResource_Release(resource);
7013 return S_OK;
7014}
7015
7016static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7017{
7018 UINT i, count;
7019 WINED3DDISPLAYMODE m;
7020 HRESULT hr;
7021
7022 /* All Windowed modes are supported, as is leaving the current mode */
7023 if(pp->Windowed) return TRUE;
7024 if(!pp->BackBufferWidth) return TRUE;
7025 if(!pp->BackBufferHeight) return TRUE;
7026
7027 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7028 for(i = 0; i < count; i++) {
7029 memset(&m, 0, sizeof(m));
7030 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7031 if(FAILED(hr)) {
7032 ERR("EnumAdapterModes failed\n");
7033 }
7034 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7035 /* Mode found, it is supported */
7036 return TRUE;
7037 }
7038 }
7039 /* Mode not found -> not supported */
7040 return FALSE;
7041}
7042
7043void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7045 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7046 UINT i;
7047 IWineD3DBaseShaderImpl *shader;
7048
7049 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7050 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7051 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7052 }
7053
7054 ENTER_GL();
7055 if(This->depth_blt_texture) {
7056 glDeleteTextures(1, &This->depth_blt_texture);
7057 This->depth_blt_texture = 0;
7058 }
7059 if (This->depth_blt_rb) {
7060 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7061 This->depth_blt_rb = 0;
7062 This->depth_blt_rb_w = 0;
7063 This->depth_blt_rb_h = 0;
7064 }
7065 LEAVE_GL();
7066
7067 This->blitter->free_private(iface);
7068 This->frag_pipe->free_private(iface);
7069 This->shader_backend->shader_free_private(iface);
7070
7071 ENTER_GL();
7072 for (i = 0; i < GL_LIMITS(textures); i++) {
7073 /* Textures are recreated below */
7074 glDeleteTextures(1, &This->dummyTextureName[i]);
7075 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7076 This->dummyTextureName[i] = 0;
7077 }
7078 LEAVE_GL();
7079
7080 while(This->numContexts) {
7081 DestroyContext(This, This->contexts[0]);
7082 }
7083 This->activeContext = NULL;
7084 HeapFree(GetProcessHeap(), 0, swapchain->context);
7085 swapchain->context = NULL;
7086 swapchain->num_contexts = 0;
7087}
7088
7089HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7091 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7092 HRESULT hr;
7093 IWineD3DSurfaceImpl *target;
7094
7095 /* Recreate the primary swapchain's context */
7096 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7097 if(swapchain->backBuffer) {
7098 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7099 } else {
7100 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7101 }
7102 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7103 &swapchain->presentParms);
7104 swapchain->num_contexts = 1;
7105 This->activeContext = swapchain->context[0];
7106
7107 create_dummy_textures(This);
7108
7109 hr = This->shader_backend->shader_alloc_private(iface);
7110 if(FAILED(hr)) {
7111 ERR("Failed to recreate shader private data\n");
7112 goto err_out;
7113 }
7114 hr = This->frag_pipe->alloc_private(iface);
7115 if(FAILED(hr)) {
7116 TRACE("Fragment pipeline private data couldn't be allocated\n");
7117 goto err_out;
7118 }
7119 hr = This->blitter->alloc_private(iface);
7120 if(FAILED(hr)) {
7121 TRACE("Blitter private data couldn't be allocated\n");
7122 goto err_out;
7123 }
7124
7125 return WINED3D_OK;
7126
7127err_out:
7128 This->blitter->free_private(iface);
7129 This->frag_pipe->free_private(iface);
7130 This->shader_backend->shader_free_private(iface);
7131 return hr;
7132}
7133
7134static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7136 IWineD3DSwapChainImpl *swapchain;
7137 HRESULT hr;
7138 BOOL DisplayModeChanged = FALSE;
7139 WINED3DDISPLAYMODE mode;
7140 TRACE("(%p)\n", This);
7141
7142 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7143 if(FAILED(hr)) {
7144 ERR("Failed to get the first implicit swapchain\n");
7145 return hr;
7146 }
7147
7148 if(!is_display_mode_supported(This, pPresentationParameters)) {
7149 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7150 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7151 pPresentationParameters->BackBufferHeight);
7152 return WINED3DERR_INVALIDCALL;
7153 }
7154
7155 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7156 * on an existing gl context, so there's no real need for recreation.
7157 *
7158 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7159 *
7160 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7161 */
7162 TRACE("New params:\n");
7163 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7164 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7165 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7166 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7167 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7168 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7169 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7170 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7171 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7172 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7173 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7174 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7175 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7176
7177 /* No special treatment of these parameters. Just store them */
7178 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7179 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7180 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7181 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7182
7183 /* What to do about these? */
7184 if(pPresentationParameters->BackBufferCount != 0 &&
7185 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7186 ERR("Cannot change the back buffer count yet\n");
7187 }
7188 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7189 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7190 ERR("Cannot change the back buffer format yet\n");
7191 }
7192 if(pPresentationParameters->hDeviceWindow != NULL &&
7193 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7194 ERR("Cannot change the device window yet\n");
7195 }
7196 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7197 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7198 return WINED3DERR_INVALIDCALL;
7199 }
7200
7201 /* Reset the depth stencil */
7202 if (pPresentationParameters->EnableAutoDepthStencil)
7203 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7204 else
7205 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7206
7207 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7208
7209 if(pPresentationParameters->Windowed) {
7210 mode.Width = swapchain->orig_width;
7211 mode.Height = swapchain->orig_height;
7212 mode.RefreshRate = 0;
7213 mode.Format = swapchain->presentParms.BackBufferFormat;
7214 } else {
7215 mode.Width = pPresentationParameters->BackBufferWidth;
7216 mode.Height = pPresentationParameters->BackBufferHeight;
7217 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7218 mode.Format = swapchain->presentParms.BackBufferFormat;
7219 }
7220
7221 /* Should Width == 800 && Height == 0 set 800x600? */
7222 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7223 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7224 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7225 {
7226 WINED3DVIEWPORT vp;
7227 UINT i;
7228
7229 vp.X = 0;
7230 vp.Y = 0;
7231 vp.Width = pPresentationParameters->BackBufferWidth;
7232 vp.Height = pPresentationParameters->BackBufferHeight;
7233 vp.MinZ = 0;
7234 vp.MaxZ = 1;
7235
7236 if(!pPresentationParameters->Windowed) {
7237 DisplayModeChanged = TRUE;
7238 }
7239 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7240 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7241
7242 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7243 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7244 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7245 }
7246 if(This->auto_depth_stencil_buffer) {
7247 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7248 }
7249
7250
7251 /* Now set the new viewport */
7252 IWineD3DDevice_SetViewport(iface, &vp);
7253 }
7254
7255 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7256 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7257 DisplayModeChanged) {
7258
7259 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7260
7261 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7262 if(swapchain->presentParms.Windowed) {
7263 /* switch from windowed to fs */
7264 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7265 pPresentationParameters->BackBufferWidth,
7266 pPresentationParameters->BackBufferHeight);
7267 } else {
7268 /* Fullscreen -> fullscreen mode change */
7269 MoveWindow(swapchain->win_handle, 0, 0,
7270 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7271 TRUE);
7272 }
7273 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7274 /* Fullscreen -> windowed switch */
7275 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7276 }
7277 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7278 } else if(!pPresentationParameters->Windowed) {
7279 DWORD style = This->style, exStyle = This->exStyle;
7280 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7281 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7282 * Reset to clear up their mess. Guild Wars also loses the device during that.
7283 */
7284 This->style = 0;
7285 This->exStyle = 0;
7286 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7287 pPresentationParameters->BackBufferWidth,
7288 pPresentationParameters->BackBufferHeight);
7289 This->style = style;
7290 This->exStyle = exStyle;
7291 }
7292
7293 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7294 if(FAILED(hr)) {
7295 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7296 }
7297
7298 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7299 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7300
7301 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7302 * first use
7303 */
7304 return hr;
7305}
7306
7307static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7309 /** FIXME: always true at the moment **/
7310 if(!bEnableDialogs) {
7311 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7312 }
7313 return WINED3D_OK;
7314}
7315
7316
7317static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7319 TRACE("(%p) : pParameters %p\n", This, pParameters);
7320
7321 *pParameters = This->createParms;
7322 return WINED3D_OK;
7323}
7324
7325static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7326 IWineD3DSwapChain *swapchain;
7327
7328 TRACE("Relaying to swapchain\n");
7329
7330 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7331 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7332 IWineD3DSwapChain_Release(swapchain);
7333 }
7334 return;
7335}
7336
7337static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7338 IWineD3DSwapChain *swapchain;
7339
7340 TRACE("Relaying to swapchain\n");
7341
7342 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7343 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7344 IWineD3DSwapChain_Release(swapchain);
7345 }
7346 return;
7347}
7348
7349
7350/** ********************************************************
7351* Notification functions
7352** ********************************************************/
7353/** This function must be called in the release of a resource when ref == 0,
7354* the contents of resource must still be correct,
7355* any handles to other resource held by the caller must be closed
7356* (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7357 *****************************************************/
7358static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7360
7361 TRACE("(%p) : Adding Resource %p\n", This, resource);
7362 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7363}
7364
7365static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7367
7368 TRACE("(%p) : Removing resource %p\n", This, resource);
7369
7370 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7371}
7372
7373
7374static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7376 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7377 int counter;
7378
7379 TRACE("(%p) : resource %p\n", This, resource);
7380
7381 context_resource_released(iface, resource, type);
7382
7383 switch (type) {
7384 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7385 case WINED3DRTYPE_SURFACE: {
7386 unsigned int i;
7387
7388 /* Cleanup any FBO attachments if d3d is enabled */
7389 if(This->d3d_initialized) {
7390 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7391 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7392
7393 TRACE("Last active render target destroyed\n");
7394 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7395 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7396 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7397 * and the lastActiveRenderTarget member shouldn't matter
7398 */
7399 if(swapchain) {
7400 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7401 TRACE("Activating primary back buffer\n");
7402 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7403 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7404 /* Single buffering environment */
7405 TRACE("Activating primary front buffer\n");
7406 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7407 } else {
7408 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7409 /* Implicit render target destroyed, that means the device is being destroyed
7410 * whatever we set here, it shouldn't matter
7411 */
7412 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7413 }
7414 } else {
7415 /* May happen during ddraw uninitialization */
7416 TRACE("Render target set, but swapchain does not exist!\n");
7417 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7418 }
7419 }
7420
7421 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7422 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7423 This->render_targets[i] = NULL;
7424 }
7425 }
7426 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7427 This->stencilBufferTarget = NULL;
7428 }
7429 }
7430
7431 break;
7432 }
7433 case WINED3DRTYPE_TEXTURE:
7434 case WINED3DRTYPE_CUBETEXTURE:
7435 case WINED3DRTYPE_VOLUMETEXTURE:
7436 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7437 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7438 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7439 This->stateBlock->textures[counter] = NULL;
7440 }
7441 if (This->updateStateBlock != This->stateBlock ){
7442 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7443 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7444 This->updateStateBlock->textures[counter] = NULL;
7445 }
7446 }
7447 }
7448 break;
7449 case WINED3DRTYPE_VOLUME:
7450 /* TODO: nothing really? */
7451 break;
7452 case WINED3DRTYPE_VERTEXBUFFER:
7453 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7454 {
7455 int streamNumber;
7456 TRACE("Cleaning up stream pointers\n");
7457
7458 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7459 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7460 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7461 */
7462 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7463 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7464 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7465 This->updateStateBlock->streamSource[streamNumber] = 0;
7466 /* Set changed flag? */
7467 }
7468 }
7469 if (This->stateBlock != NULL ) { /* only happens if there is an error in the application, or on reset/release (because we don't manage internal tracking properly) */
7470 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7471 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7472 This->stateBlock->streamSource[streamNumber] = 0;
7473 }
7474 }
7475 }
7476 }
7477 break;
7478 case WINED3DRTYPE_INDEXBUFFER:
7479 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7480 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7481 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7482 This->updateStateBlock->pIndexData = NULL;
7483 }
7484 }
7485 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7486 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7487 This->stateBlock->pIndexData = NULL;
7488 }
7489 }
7490
7491 break;
7492 default:
7493 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7494 break;
7495 }
7496
7497
7498 /* Remove the resource from the resourceStore */
7499 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7500
7501 TRACE("Resource released\n");
7502
7503}
7504
7505static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7507 IWineD3DResourceImpl *resource, *cursor;
7508 HRESULT ret;
7509 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7510
7511 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7512 TRACE("enumerating resource %p\n", resource);
7513 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7514 ret = pCallback((IWineD3DResource *) resource, pData);
7515 if(ret == S_FALSE) {
7516 TRACE("Canceling enumeration\n");
7517 break;
7518 }
7519 }
7520 return WINED3D_OK;
7521}
7522
7523/**********************************************************
7524 * IWineD3DDevice VTbl follows
7525 **********************************************************/
7526
7527const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7528{
7529 /*** IUnknown methods ***/
7530 IWineD3DDeviceImpl_QueryInterface,
7531 IWineD3DDeviceImpl_AddRef,
7532 IWineD3DDeviceImpl_Release,
7533 /*** IWineD3DDevice methods ***/
7534 IWineD3DDeviceImpl_GetParent,
7535 /*** Creation methods**/
7536 IWineD3DDeviceImpl_CreateVertexBuffer,
7537 IWineD3DDeviceImpl_CreateIndexBuffer,
7538 IWineD3DDeviceImpl_CreateStateBlock,
7539 IWineD3DDeviceImpl_CreateSurface,
7540 IWineD3DDeviceImpl_CreateTexture,
7541 IWineD3DDeviceImpl_CreateVolumeTexture,
7542 IWineD3DDeviceImpl_CreateVolume,
7543 IWineD3DDeviceImpl_CreateCubeTexture,
7544 IWineD3DDeviceImpl_CreateQuery,
7545 IWineD3DDeviceImpl_CreateSwapChain,
7546 IWineD3DDeviceImpl_CreateVertexDeclaration,
7547 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7548 IWineD3DDeviceImpl_CreateVertexShader,
7549 IWineD3DDeviceImpl_CreatePixelShader,
7550 IWineD3DDeviceImpl_CreatePalette,
7551 /*** Odd functions **/
7552 IWineD3DDeviceImpl_Init3D,
7553 IWineD3DDeviceImpl_InitGDI,
7554 IWineD3DDeviceImpl_Uninit3D,
7555 IWineD3DDeviceImpl_UninitGDI,
7556 IWineD3DDeviceImpl_SetMultithreaded,
7557 IWineD3DDeviceImpl_EvictManagedResources,
7558 IWineD3DDeviceImpl_GetAvailableTextureMem,
7559 IWineD3DDeviceImpl_GetBackBuffer,
7560 IWineD3DDeviceImpl_GetCreationParameters,
7561 IWineD3DDeviceImpl_GetDeviceCaps,
7562 IWineD3DDeviceImpl_GetDirect3D,
7563 IWineD3DDeviceImpl_GetDisplayMode,
7564 IWineD3DDeviceImpl_SetDisplayMode,
7565 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7566 IWineD3DDeviceImpl_GetRasterStatus,
7567 IWineD3DDeviceImpl_GetSwapChain,
7568 IWineD3DDeviceImpl_Reset,
7569 IWineD3DDeviceImpl_SetDialogBoxMode,
7570 IWineD3DDeviceImpl_SetCursorProperties,
7571 IWineD3DDeviceImpl_SetCursorPosition,
7572 IWineD3DDeviceImpl_ShowCursor,
7573 IWineD3DDeviceImpl_TestCooperativeLevel,
7574 /*** Getters and setters **/
7575 IWineD3DDeviceImpl_SetClipPlane,
7576 IWineD3DDeviceImpl_GetClipPlane,
7577 IWineD3DDeviceImpl_SetClipStatus,
7578 IWineD3DDeviceImpl_GetClipStatus,
7579 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7580 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7581 IWineD3DDeviceImpl_SetDepthStencilSurface,
7582 IWineD3DDeviceImpl_GetDepthStencilSurface,
7583 IWineD3DDeviceImpl_SetFVF,
7584 IWineD3DDeviceImpl_GetFVF,
7585 IWineD3DDeviceImpl_SetGammaRamp,
7586 IWineD3DDeviceImpl_GetGammaRamp,
7587 IWineD3DDeviceImpl_SetIndices,
7588 IWineD3DDeviceImpl_GetIndices,
7589 IWineD3DDeviceImpl_SetBaseVertexIndex,
7590 IWineD3DDeviceImpl_GetBaseVertexIndex,
7591 IWineD3DDeviceImpl_SetLight,
7592 IWineD3DDeviceImpl_GetLight,
7593 IWineD3DDeviceImpl_SetLightEnable,
7594 IWineD3DDeviceImpl_GetLightEnable,
7595 IWineD3DDeviceImpl_SetMaterial,
7596 IWineD3DDeviceImpl_GetMaterial,
7597 IWineD3DDeviceImpl_SetNPatchMode,
7598 IWineD3DDeviceImpl_GetNPatchMode,
7599 IWineD3DDeviceImpl_SetPaletteEntries,
7600 IWineD3DDeviceImpl_GetPaletteEntries,
7601 IWineD3DDeviceImpl_SetPixelShader,
7602 IWineD3DDeviceImpl_GetPixelShader,
7603 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7604 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7605 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7606 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7607 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7608 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7609 IWineD3DDeviceImpl_SetRenderState,
7610 IWineD3DDeviceImpl_GetRenderState,
7611 IWineD3DDeviceImpl_SetRenderTarget,
7612 IWineD3DDeviceImpl_GetRenderTarget,
7613 IWineD3DDeviceImpl_SetFrontBackBuffers,
7614 IWineD3DDeviceImpl_SetSamplerState,
7615 IWineD3DDeviceImpl_GetSamplerState,
7616 IWineD3DDeviceImpl_SetScissorRect,
7617 IWineD3DDeviceImpl_GetScissorRect,
7618 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7619 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7620 IWineD3DDeviceImpl_SetStreamSource,
7621 IWineD3DDeviceImpl_GetStreamSource,
7622 IWineD3DDeviceImpl_SetStreamSourceFreq,
7623 IWineD3DDeviceImpl_GetStreamSourceFreq,
7624 IWineD3DDeviceImpl_SetTexture,
7625 IWineD3DDeviceImpl_GetTexture,
7626 IWineD3DDeviceImpl_SetTextureStageState,
7627 IWineD3DDeviceImpl_GetTextureStageState,
7628 IWineD3DDeviceImpl_SetTransform,
7629 IWineD3DDeviceImpl_GetTransform,
7630 IWineD3DDeviceImpl_SetVertexDeclaration,
7631 IWineD3DDeviceImpl_GetVertexDeclaration,
7632 IWineD3DDeviceImpl_SetVertexShader,
7633 IWineD3DDeviceImpl_GetVertexShader,
7634 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7635 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7636 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7637 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7638 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7639 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7640 IWineD3DDeviceImpl_SetViewport,
7641 IWineD3DDeviceImpl_GetViewport,
7642 IWineD3DDeviceImpl_MultiplyTransform,
7643 IWineD3DDeviceImpl_ValidateDevice,
7644 IWineD3DDeviceImpl_ProcessVertices,
7645 /*** State block ***/
7646 IWineD3DDeviceImpl_BeginStateBlock,
7647 IWineD3DDeviceImpl_EndStateBlock,
7648 /*** Scene management ***/
7649 IWineD3DDeviceImpl_BeginScene,
7650 IWineD3DDeviceImpl_EndScene,
7651 IWineD3DDeviceImpl_Present,
7652 IWineD3DDeviceImpl_Clear,
7653 /*** Drawing ***/
7654 IWineD3DDeviceImpl_DrawPrimitive,
7655 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7656 IWineD3DDeviceImpl_DrawPrimitiveUP,
7657 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7658 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7659 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7660 IWineD3DDeviceImpl_DrawRectPatch,
7661 IWineD3DDeviceImpl_DrawTriPatch,
7662 IWineD3DDeviceImpl_DeletePatch,
7663 IWineD3DDeviceImpl_ColorFill,
7664 IWineD3DDeviceImpl_UpdateTexture,
7665 IWineD3DDeviceImpl_UpdateSurface,
7666 IWineD3DDeviceImpl_GetFrontBufferData,
7667 /*** object tracking ***/
7668 IWineD3DDeviceImpl_ResourceReleased,
7669 IWineD3DDeviceImpl_EnumResources
7670};
7671
7672const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7673{
7674 /*** IUnknown methods ***/
7675 IWineD3DDeviceImpl_QueryInterface,
7676 IWineD3DDeviceImpl_AddRef,
7677 IWineD3DDeviceImpl_Release,
7678 /*** IWineD3DDevice methods ***/
7679 IWineD3DDeviceImpl_GetParent,
7680 /*** Creation methods**/
7681 IWineD3DDeviceImpl_CreateVertexBuffer,
7682 IWineD3DDeviceImpl_CreateIndexBuffer,
7683 IWineD3DDeviceImpl_CreateStateBlock,
7684 IWineD3DDeviceImpl_CreateSurface,
7685 IWineD3DDeviceImpl_CreateTexture,
7686 IWineD3DDeviceImpl_CreateVolumeTexture,
7687 IWineD3DDeviceImpl_CreateVolume,
7688 IWineD3DDeviceImpl_CreateCubeTexture,
7689 IWineD3DDeviceImpl_CreateQuery,
7690 IWineD3DDeviceImpl_CreateSwapChain,
7691 IWineD3DDeviceImpl_CreateVertexDeclaration,
7692 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7693 IWineD3DDeviceImpl_CreateVertexShader,
7694 IWineD3DDeviceImpl_CreatePixelShader,
7695 IWineD3DDeviceImpl_CreatePalette,
7696 /*** Odd functions **/
7697 IWineD3DDeviceImpl_Init3D,
7698 IWineD3DDeviceImpl_InitGDI,
7699 IWineD3DDeviceImpl_Uninit3D,
7700 IWineD3DDeviceImpl_UninitGDI,
7701 IWineD3DDeviceImpl_SetMultithreaded,
7702 IWineD3DDeviceImpl_EvictManagedResources,
7703 IWineD3DDeviceImpl_GetAvailableTextureMem,
7704 IWineD3DDeviceImpl_GetBackBuffer,
7705 IWineD3DDeviceImpl_GetCreationParameters,
7706 IWineD3DDeviceImpl_GetDeviceCaps,
7707 IWineD3DDeviceImpl_GetDirect3D,
7708 IWineD3DDeviceImpl_GetDisplayMode,
7709 IWineD3DDeviceImpl_SetDisplayMode,
7710 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7711 IWineD3DDeviceImpl_GetRasterStatus,
7712 IWineD3DDeviceImpl_GetSwapChain,
7713 IWineD3DDeviceImpl_Reset,
7714 IWineD3DDeviceImpl_SetDialogBoxMode,
7715 IWineD3DDeviceImpl_SetCursorProperties,
7716 IWineD3DDeviceImpl_SetCursorPosition,
7717 IWineD3DDeviceImpl_ShowCursor,
7718 IWineD3DDeviceImpl_TestCooperativeLevel,
7719 /*** Getters and setters **/
7720 IWineD3DDeviceImpl_SetClipPlane,
7721 IWineD3DDeviceImpl_GetClipPlane,
7722 IWineD3DDeviceImpl_SetClipStatus,
7723 IWineD3DDeviceImpl_GetClipStatus,
7724 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7725 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7726 IWineD3DDeviceImpl_SetDepthStencilSurface,
7727 IWineD3DDeviceImpl_GetDepthStencilSurface,
7728 IWineD3DDeviceImpl_SetFVF,
7729 IWineD3DDeviceImpl_GetFVF,
7730 IWineD3DDeviceImpl_SetGammaRamp,
7731 IWineD3DDeviceImpl_GetGammaRamp,
7732 IWineD3DDeviceImpl_SetIndices,
7733 IWineD3DDeviceImpl_GetIndices,
7734 IWineD3DDeviceImpl_SetBaseVertexIndex,
7735 IWineD3DDeviceImpl_GetBaseVertexIndex,
7736 IWineD3DDeviceImpl_SetLight,
7737 IWineD3DDeviceImpl_GetLight,
7738 IWineD3DDeviceImpl_SetLightEnable,
7739 IWineD3DDeviceImpl_GetLightEnable,
7740 IWineD3DDeviceImpl_SetMaterial,
7741 IWineD3DDeviceImpl_GetMaterial,
7742 IWineD3DDeviceImpl_SetNPatchMode,
7743 IWineD3DDeviceImpl_GetNPatchMode,
7744 IWineD3DDeviceImpl_SetPaletteEntries,
7745 IWineD3DDeviceImpl_GetPaletteEntries,
7746 IWineD3DDeviceImpl_SetPixelShader,
7747 IWineD3DDeviceImpl_GetPixelShader,
7748 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7749 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7750 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7751 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7752 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7753 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7754 IWineD3DDeviceImpl_SetRenderState,
7755 IWineD3DDeviceImpl_GetRenderState,
7756 IWineD3DDeviceImpl_SetRenderTarget,
7757 IWineD3DDeviceImpl_GetRenderTarget,
7758 IWineD3DDeviceImpl_SetFrontBackBuffers,
7759 IWineD3DDeviceImpl_SetSamplerState,
7760 IWineD3DDeviceImpl_GetSamplerState,
7761 IWineD3DDeviceImpl_SetScissorRect,
7762 IWineD3DDeviceImpl_GetScissorRect,
7763 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7764 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7765 IWineD3DDeviceImpl_SetStreamSource,
7766 IWineD3DDeviceImpl_GetStreamSource,
7767 IWineD3DDeviceImpl_SetStreamSourceFreq,
7768 IWineD3DDeviceImpl_GetStreamSourceFreq,
7769 IWineD3DDeviceImpl_SetTexture,
7770 IWineD3DDeviceImpl_GetTexture,
7771 IWineD3DDeviceImpl_SetTextureStageState,
7772 IWineD3DDeviceImpl_GetTextureStageState,
7773 IWineD3DDeviceImpl_SetTransform,
7774 IWineD3DDeviceImpl_GetTransform,
7775 IWineD3DDeviceImpl_SetVertexDeclaration,
7776 IWineD3DDeviceImpl_GetVertexDeclaration,
7777 IWineD3DDeviceImpl_SetVertexShader,
7778 IWineD3DDeviceImpl_GetVertexShader,
7779 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7780 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7781 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7782 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7783 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7784 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7785 IWineD3DDeviceImpl_SetViewport,
7786 IWineD3DDeviceImpl_GetViewport,
7787 IWineD3DDeviceImpl_MultiplyTransform,
7788 IWineD3DDeviceImpl_ValidateDevice,
7789 IWineD3DDeviceImpl_ProcessVertices,
7790 /*** State block ***/
7791 IWineD3DDeviceImpl_BeginStateBlock,
7792 IWineD3DDeviceImpl_EndStateBlock,
7793 /*** Scene management ***/
7794 IWineD3DDeviceImpl_BeginScene,
7795 IWineD3DDeviceImpl_EndScene,
7796 IWineD3DDeviceImpl_Present,
7797 IWineD3DDeviceImpl_Clear,
7798 /*** Drawing ***/
7799 IWineD3DDeviceImpl_DrawPrimitive,
7800 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7801 IWineD3DDeviceImpl_DrawPrimitiveUP,
7802 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7803 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7804 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7805 IWineD3DDeviceImpl_DrawRectPatch,
7806 IWineD3DDeviceImpl_DrawTriPatch,
7807 IWineD3DDeviceImpl_DeletePatch,
7808 IWineD3DDeviceImpl_ColorFill,
7809 IWineD3DDeviceImpl_UpdateTexture,
7810 IWineD3DDeviceImpl_UpdateSurface,
7811 IWineD3DDeviceImpl_GetFrontBufferData,
7812 /*** object tracking ***/
7813 IWineD3DDeviceImpl_ResourceReleased,
7814 IWineD3DDeviceImpl_EnumResources
7815};
7816
7817const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7818 WINED3DRS_ALPHABLENDENABLE ,
7819 WINED3DRS_ALPHAFUNC ,
7820 WINED3DRS_ALPHAREF ,
7821 WINED3DRS_ALPHATESTENABLE ,
7822 WINED3DRS_BLENDOP ,
7823 WINED3DRS_COLORWRITEENABLE ,
7824 WINED3DRS_DESTBLEND ,
7825 WINED3DRS_DITHERENABLE ,
7826 WINED3DRS_FILLMODE ,
7827 WINED3DRS_FOGDENSITY ,
7828 WINED3DRS_FOGEND ,
7829 WINED3DRS_FOGSTART ,
7830 WINED3DRS_LASTPIXEL ,
7831 WINED3DRS_SHADEMODE ,
7832 WINED3DRS_SRCBLEND ,
7833 WINED3DRS_STENCILENABLE ,
7834 WINED3DRS_STENCILFAIL ,
7835 WINED3DRS_STENCILFUNC ,
7836 WINED3DRS_STENCILMASK ,
7837 WINED3DRS_STENCILPASS ,
7838 WINED3DRS_STENCILREF ,
7839 WINED3DRS_STENCILWRITEMASK ,
7840 WINED3DRS_STENCILZFAIL ,
7841 WINED3DRS_TEXTUREFACTOR ,
7842 WINED3DRS_WRAP0 ,
7843 WINED3DRS_WRAP1 ,
7844 WINED3DRS_WRAP2 ,
7845 WINED3DRS_WRAP3 ,
7846 WINED3DRS_WRAP4 ,
7847 WINED3DRS_WRAP5 ,
7848 WINED3DRS_WRAP6 ,
7849 WINED3DRS_WRAP7 ,
7850 WINED3DRS_ZENABLE ,
7851 WINED3DRS_ZFUNC ,
7852 WINED3DRS_ZWRITEENABLE
7853};
7854
7855const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7856 WINED3DTSS_ADDRESSW ,
7857 WINED3DTSS_ALPHAARG0 ,
7858 WINED3DTSS_ALPHAARG1 ,
7859 WINED3DTSS_ALPHAARG2 ,
7860 WINED3DTSS_ALPHAOP ,
7861 WINED3DTSS_BUMPENVLOFFSET ,
7862 WINED3DTSS_BUMPENVLSCALE ,
7863 WINED3DTSS_BUMPENVMAT00 ,
7864 WINED3DTSS_BUMPENVMAT01 ,
7865 WINED3DTSS_BUMPENVMAT10 ,
7866 WINED3DTSS_BUMPENVMAT11 ,
7867 WINED3DTSS_COLORARG0 ,
7868 WINED3DTSS_COLORARG1 ,
7869 WINED3DTSS_COLORARG2 ,
7870 WINED3DTSS_COLOROP ,
7871 WINED3DTSS_RESULTARG ,
7872 WINED3DTSS_TEXCOORDINDEX ,
7873 WINED3DTSS_TEXTURETRANSFORMFLAGS
7874};
7875
7876const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7877 WINED3DSAMP_ADDRESSU ,
7878 WINED3DSAMP_ADDRESSV ,
7879 WINED3DSAMP_ADDRESSW ,
7880 WINED3DSAMP_BORDERCOLOR ,
7881 WINED3DSAMP_MAGFILTER ,
7882 WINED3DSAMP_MINFILTER ,
7883 WINED3DSAMP_MIPFILTER ,
7884 WINED3DSAMP_MIPMAPLODBIAS ,
7885 WINED3DSAMP_MAXMIPLEVEL ,
7886 WINED3DSAMP_MAXANISOTROPY ,
7887 WINED3DSAMP_SRGBTEXTURE ,
7888 WINED3DSAMP_ELEMENTINDEX
7889};
7890
7891const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7892 WINED3DRS_AMBIENT ,
7893 WINED3DRS_AMBIENTMATERIALSOURCE ,
7894 WINED3DRS_CLIPPING ,
7895 WINED3DRS_CLIPPLANEENABLE ,
7896 WINED3DRS_COLORVERTEX ,
7897 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7898 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7899 WINED3DRS_FOGDENSITY ,
7900 WINED3DRS_FOGEND ,
7901 WINED3DRS_FOGSTART ,
7902 WINED3DRS_FOGTABLEMODE ,
7903 WINED3DRS_FOGVERTEXMODE ,
7904 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7905 WINED3DRS_LIGHTING ,
7906 WINED3DRS_LOCALVIEWER ,
7907 WINED3DRS_MULTISAMPLEANTIALIAS ,
7908 WINED3DRS_MULTISAMPLEMASK ,
7909 WINED3DRS_NORMALIZENORMALS ,
7910 WINED3DRS_PATCHEDGESTYLE ,
7911 WINED3DRS_POINTSCALE_A ,
7912 WINED3DRS_POINTSCALE_B ,
7913 WINED3DRS_POINTSCALE_C ,
7914 WINED3DRS_POINTSCALEENABLE ,
7915 WINED3DRS_POINTSIZE ,
7916 WINED3DRS_POINTSIZE_MAX ,
7917 WINED3DRS_POINTSIZE_MIN ,
7918 WINED3DRS_POINTSPRITEENABLE ,
7919 WINED3DRS_RANGEFOGENABLE ,
7920 WINED3DRS_SPECULARMATERIALSOURCE ,
7921 WINED3DRS_TWEENFACTOR ,
7922 WINED3DRS_VERTEXBLEND ,
7923 WINED3DRS_CULLMODE ,
7924 WINED3DRS_FOGCOLOR
7925};
7926
7927const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7928 WINED3DTSS_TEXCOORDINDEX ,
7929 WINED3DTSS_TEXTURETRANSFORMFLAGS
7930};
7931
7932const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7933 WINED3DSAMP_DMAPOFFSET
7934};
7935
7936void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7937 DWORD rep = This->StateTable[state].representative;
7938 DWORD idx;
7939 BYTE shift;
7940 UINT i;
7941 WineD3DContext *context;
7942
7943 if(!rep) return;
7944 for(i = 0; i < This->numContexts; i++) {
7945 context = This->contexts[i];
7946 if(isStateDirty(context, rep)) continue;
7947
7948 context->dirtyArray[context->numDirtyEntries++] = rep;
7949 idx = rep >> 5;
7950 shift = rep & 0x1f;
7951 context->isStateDirty[idx] |= (1 << shift);
7952 }
7953}
7954
7955void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7956 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7957 /* The drawable size of a pbuffer render target is the current pbuffer size
7958 */
7959 *width = dev->pbufferWidth;
7960 *height = dev->pbufferHeight;
7961}
7962
7963void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7964 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7965 */
7966 *width = This->pow2Width;
7967 *height = This->pow2Height;
7968}
7969
7970void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7971 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7972 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7973 * current context's drawable, which is the size of the back buffer of the swapchain
7974 * the active context belongs to. The back buffer of the swapchain is stored as the
7975 * surface the context belongs to.
7976 */
7977 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7978 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;
7979}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette