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