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