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