push 0f15bbd80d260bbd8adf052e820484a405c49375
[wine/hacks.git] / dlls / wined3d / device.c
blobf9b399d503db839735588c875c953ffe8309ae72
1 /*
2 * IWineD3DDevice implementation
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
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.
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.
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
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
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 */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
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; \
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; \
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; \
102 WineD3DAdapterChangeGLRam(This, _size); \
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; \
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); \
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; \
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 */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
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;
147 *ppobj = NULL;
148 return E_NOINTERFACE;
151 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 ULONG refCount = InterlockedIncrement(&This->ref);
155 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
156 return refCount;
159 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 ULONG refCount = InterlockedDecrement(&This->ref);
163 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
165 if (!refCount) {
166 if (This->fbo) {
167 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
169 if (This->src_fbo) {
170 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
172 if (This->dst_fbo) {
173 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
176 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
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 ** ***************************/
182 if (!list_empty(&This->resources)) {
183 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
184 dumpResources(&This->resources);
187 if(This->contexts) ERR("Context array not freed!\n");
188 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
189 This->haveHardwareCursor = FALSE;
191 IWineD3D_Release(This->wineD3D);
192 This->wineD3D = NULL;
193 HeapFree(GetProcessHeap(), 0, This);
194 TRACE("Freed device %p\n", This);
195 This = NULL;
197 return refCount;
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;
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;
219 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
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();
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)
230 while(glGetError() != GL_NO_ERROR);
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.
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;
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;
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.
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;
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
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;
281 LEAVE_GL();
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;
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;
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
311 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
312 *ppVertexBuffer = NULL;
313 return WINED3DERR_INVALIDCALL;
316 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
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;
321 object->fvf = FVF;
323 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
324 * drawStridedFast (half-life 2).
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.
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.
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);
343 return WINED3D_OK;
346 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
347 GLenum error, glUsage;
348 TRACE("Creating VBO for Index Buffer %p\n", object);
350 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
351 * restored on the next draw
353 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
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();
359 while(glGetError());
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;
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;
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
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;
385 LEAVE_GL();
386 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
387 return;
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;
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);
403 /* Allocate the storage for the device */
404 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
406 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
407 CreateIndexBufferVBO(This, object);
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;
414 return WINED3D_OK;
417 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
420 IWineD3DStateBlockImpl *object;
421 int i, j;
422 HRESULT temp_result;
424 D3DCREATEOBJECTINSTANCE(object, StateBlock)
425 object->blockType = Type;
427 for(i = 0; i < LIGHTMAP_SIZE; i++) {
428 list_init(&object->lightMap[i]);
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;
439 temp_result = allocate_shader_constants(object);
440 if (WINED3D_OK != temp_result)
441 return temp_result;
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));
449 /* Reset the ref and type after kludging it */
450 object->wineD3DDevice = This;
451 object->ref = 1;
452 object->blockType = Type;
454 TRACE("Updating changed flags appropriate for type %d\n", Type);
456 if (Type == WINED3DSBT_ALL) {
458 TRACE("ALL => Pretend everything has changed\n");
459 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
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;
470 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
471 object->contained_render_states[j - 1] = j;
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;
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;
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;
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;
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;
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;
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;
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++;
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++;
518 for(i = 0; i < MAX_STREAMS; i++) {
519 if(object->streamSource[i]) {
520 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
523 if(object->pIndexData) {
524 IWineD3DIndexBuffer_AddRef(object->pIndexData);
526 if(object->vertexShader) {
527 IWineD3DVertexShader_AddRef(object->vertexShader);
529 if(object->pixelShader) {
530 IWineD3DPixelShader_AddRef(object->pixelShader);
533 } else if (Type == WINED3DSBT_PIXELSTATE) {
535 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
536 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
538 object->changed.pixelShader = TRUE;
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;
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;
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;
555 object->num_contained_ps_consts_i = MAX_CONST_I;
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];
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++;
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++;
578 if(object->pixelShader) {
579 IWineD3DPixelShader_AddRef(object->pixelShader);
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
585 for(i = 0; i < MAX_STREAMS; i++) {
586 object->streamSource[i] = NULL;
588 object->pIndexData = NULL;
589 object->vertexShader = NULL;
591 } else if (Type == WINED3DSBT_VERTEXSTATE) {
593 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
594 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
596 object->changed.vertexShader = TRUE;
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;
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;
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;
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];
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++;
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++;
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;
645 for(i = 0; i < MAX_STREAMS; i++) {
646 if(object->streamSource[i]) {
647 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
650 if(object->vertexShader) {
651 IWineD3DVertexShader_AddRef(object->vertexShader);
653 object->pIndexData = NULL;
654 object->pixelShader = NULL;
655 } else {
656 FIXME("Unrecognized state block type %d\n", Type);
659 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
660 return WINED3D_OK;
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.
667 Discard
668 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
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.
672 ******************************** */
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);
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 *******************************/
693 * TODO: Discard MSDN
694 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
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.
700 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
701 ***************************/
703 if(MultisampleQuality < 0) {
704 FIXME("Invalid multisample level %d\n", MultisampleQuality);
705 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
708 if(MultisampleQuality > 0) {
709 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
710 MultisampleQuality=0;
713 /** FIXME: Check that the format is supported
714 * by the device.
715 *******************************/
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;
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;
736 /** Create and initialise the surface resource **/
737 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
738 /* "Standalone" surface */
739 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
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;
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;
754 if (WINED3DFMT_UNKNOWN != Format) {
755 object->bytesPerPixel = tableEntry->bpp;
756 } else {
757 object->bytesPerPixel = 0;
760 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
762 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
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;
793 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
794 FIXME("Trying to create a render target that isn't in the default pool\n");
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);
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;
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;
817 break;
819 case SURFACE_GDI:
820 object->lpVtbl = &IWineGDISurface_Vtbl;
821 break;
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;
830 list_init(&object->renderbuffers);
832 /* Call the private setup routine */
833 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
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) {
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);
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);
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;
865 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
866 D3DINITIALIZEBASETEXTURE(object->baseTexture);
867 object->width = Width;
868 object->height = Height;
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;
880 if(pow2Width != Width || pow2Height != Height) {
881 if(Levels > 1) {
882 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
883 HeapFree(GetProcessHeap(), 0, object);
884 *ppTexture = NULL;
885 return WINED3DERR_INVALIDCALL;
886 } else {
887 Levels = 1;
892 /** FIXME: add support for real non-power-two if it's provided by the video card **/
893 /* Precalculated scaling for 'faked' non power of two texture coords */
894 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
895 (Width != pow2Width || Height != pow2Height)) {
896 object->baseTexture.pow2Matrix[0] = (float)Width;
897 object->baseTexture.pow2Matrix[5] = (float)Height;
898 object->baseTexture.pow2Matrix[10] = 1.0;
899 object->baseTexture.pow2Matrix[15] = 1.0;
900 object->target = GL_TEXTURE_RECTANGLE_ARB;
901 } else {
902 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
903 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
904 object->baseTexture.pow2Matrix[10] = 1.0;
905 object->baseTexture.pow2Matrix[15] = 1.0;
906 object->target = GL_TEXTURE_2D;
908 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
910 /* Calculate levels for mip mapping */
911 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
912 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
913 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
914 return WINED3DERR_INVALIDCALL;
916 if(Levels > 1) {
917 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
918 return WINED3DERR_INVALIDCALL;
920 object->baseTexture.levels = 1;
921 } else if (Levels == 0) {
922 TRACE("calculating levels %d\n", object->baseTexture.levels);
923 object->baseTexture.levels++;
924 tmpW = Width;
925 tmpH = Height;
926 while (tmpW > 1 || tmpH > 1) {
927 tmpW = max(1, tmpW >> 1);
928 tmpH = max(1, tmpH >> 1);
929 object->baseTexture.levels++;
931 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
934 /* Generate all the surfaces */
935 tmpW = Width;
936 tmpH = Height;
937 for (i = 0; i < object->baseTexture.levels; i++)
939 /* use the callback to create the texture surface */
940 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
941 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
942 FIXME("Failed to create surface %p\n", object);
943 /* clean up */
944 object->surfaces[i] = NULL;
945 IWineD3DTexture_Release((IWineD3DTexture *)object);
947 *ppTexture = NULL;
948 return hr;
951 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
952 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
953 /* calculate the next mipmap level */
954 tmpW = max(1, tmpW >> 1);
955 tmpH = max(1, tmpH >> 1);
957 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
959 TRACE("(%p) : Created texture %p\n", This, object);
960 return WINED3D_OK;
963 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
964 UINT Width, UINT Height, UINT Depth,
965 UINT Levels, DWORD Usage,
966 WINED3DFORMAT Format, WINED3DPOOL Pool,
967 IWineD3DVolumeTexture **ppVolumeTexture,
968 HANDLE *pSharedHandle, IUnknown *parent,
969 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
972 IWineD3DVolumeTextureImpl *object;
973 unsigned int i;
974 UINT tmpW;
975 UINT tmpH;
976 UINT tmpD;
977 const GlPixelFormatDesc *glDesc;
979 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
981 /* TODO: It should only be possible to create textures for formats
982 that are reported as supported */
983 if (WINED3DFMT_UNKNOWN >= Format) {
984 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
985 return WINED3DERR_INVALIDCALL;
987 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
988 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
989 return WINED3DERR_INVALIDCALL;
992 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
993 D3DINITIALIZEBASETEXTURE(object->baseTexture);
995 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
996 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
998 object->width = Width;
999 object->height = Height;
1000 object->depth = Depth;
1002 /* Is NP2 support for volumes needed? */
1003 object->baseTexture.pow2Matrix[ 0] = 1.0;
1004 object->baseTexture.pow2Matrix[ 5] = 1.0;
1005 object->baseTexture.pow2Matrix[10] = 1.0;
1006 object->baseTexture.pow2Matrix[15] = 1.0;
1008 /* Calculate levels for mip mapping */
1009 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1010 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1011 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1012 return WINED3DERR_INVALIDCALL;
1014 if(Levels > 1) {
1015 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1016 return WINED3DERR_INVALIDCALL;
1018 Levels = 1;
1019 } else if (Levels == 0) {
1020 object->baseTexture.levels++;
1021 tmpW = Width;
1022 tmpH = Height;
1023 tmpD = Depth;
1024 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1025 tmpW = max(1, tmpW >> 1);
1026 tmpH = max(1, tmpH >> 1);
1027 tmpD = max(1, tmpD >> 1);
1028 object->baseTexture.levels++;
1030 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1033 /* Generate all the surfaces */
1034 tmpW = Width;
1035 tmpH = Height;
1036 tmpD = Depth;
1038 for (i = 0; i < object->baseTexture.levels; i++)
1040 HRESULT hr;
1041 /* Create the volume */
1042 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
1043 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1045 if(FAILED(hr)) {
1046 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1047 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1048 *ppVolumeTexture = NULL;
1049 return hr;
1052 /* Set its container to this object */
1053 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1055 /* calcualte the next mipmap level */
1056 tmpW = max(1, tmpW >> 1);
1057 tmpH = max(1, tmpH >> 1);
1058 tmpD = max(1, tmpD >> 1);
1060 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1062 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1063 TRACE("(%p) : Created volume texture %p\n", This, object);
1064 return WINED3D_OK;
1067 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1068 UINT Width, UINT Height, UINT Depth,
1069 DWORD Usage,
1070 WINED3DFORMAT Format, WINED3DPOOL Pool,
1071 IWineD3DVolume** ppVolume,
1072 HANDLE* pSharedHandle, IUnknown *parent) {
1074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1075 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1076 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1078 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1079 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1080 return WINED3DERR_INVALIDCALL;
1083 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1085 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1086 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1088 object->currentDesc.Width = Width;
1089 object->currentDesc.Height = Height;
1090 object->currentDesc.Depth = Depth;
1091 object->bytesPerPixel = formatDesc->bpp;
1093 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1094 object->lockable = TRUE;
1095 object->locked = FALSE;
1096 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1097 object->dirty = TRUE;
1099 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1102 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1103 UINT Levels, DWORD Usage,
1104 WINED3DFORMAT Format, WINED3DPOOL Pool,
1105 IWineD3DCubeTexture **ppCubeTexture,
1106 HANDLE *pSharedHandle, IUnknown *parent,
1107 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1110 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1111 unsigned int i, j;
1112 UINT tmpW;
1113 HRESULT hr;
1114 unsigned int pow2EdgeLength = EdgeLength;
1115 const GlPixelFormatDesc *glDesc;
1116 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1118 /* TODO: It should only be possible to create textures for formats
1119 that are reported as supported */
1120 if (WINED3DFMT_UNKNOWN >= Format) {
1121 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1122 return WINED3DERR_INVALIDCALL;
1125 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1126 WARN("(%p) : Tried to create not supported cube texture\n", This);
1127 return WINED3DERR_INVALIDCALL;
1130 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1131 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1133 TRACE("(%p) Create Cube Texture\n", This);
1135 /** Non-power2 support **/
1137 /* Find the nearest pow2 match */
1138 pow2EdgeLength = 1;
1139 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1141 object->edgeLength = EdgeLength;
1142 /* TODO: support for native non-power 2 */
1143 /* Precalculated scaling for 'faked' non power of two texture coords */
1144 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1145 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1146 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1147 object->baseTexture.pow2Matrix[15] = 1.0;
1149 /* Calculate levels for mip mapping */
1150 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1151 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1152 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1153 HeapFree(GetProcessHeap(), 0, object);
1154 *ppCubeTexture = NULL;
1156 return WINED3DERR_INVALIDCALL;
1158 if(Levels > 1) {
1159 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1160 HeapFree(GetProcessHeap(), 0, object);
1161 *ppCubeTexture = NULL;
1163 return WINED3DERR_INVALIDCALL;
1165 Levels = 1;
1166 } else if (Levels == 0) {
1167 object->baseTexture.levels++;
1168 tmpW = EdgeLength;
1169 while (tmpW > 1) {
1170 tmpW = max(1, tmpW >> 1);
1171 object->baseTexture.levels++;
1173 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1176 /* Generate all the surfaces */
1177 tmpW = EdgeLength;
1178 for (i = 0; i < object->baseTexture.levels; i++) {
1180 /* Create the 6 faces */
1181 for (j = 0; j < 6; j++) {
1183 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1184 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1186 if(hr!= WINED3D_OK) {
1187 /* clean up */
1188 int k;
1189 int l;
1190 for (l = 0; l < j; l++) {
1191 IWineD3DSurface_Release(object->surfaces[l][i]);
1193 for (k = 0; k < i; k++) {
1194 for (l = 0; l < 6; l++) {
1195 IWineD3DSurface_Release(object->surfaces[l][k]);
1199 FIXME("(%p) Failed to create surface\n",object);
1200 HeapFree(GetProcessHeap(),0,object);
1201 *ppCubeTexture = NULL;
1202 return hr;
1204 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1205 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1207 tmpW = max(1, tmpW >> 1);
1209 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1211 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1212 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1213 return WINED3D_OK;
1216 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1218 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1219 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1221 /* Just a check to see if we support this type of query */
1222 switch(Type) {
1223 case WINED3DQUERYTYPE_OCCLUSION:
1224 TRACE("(%p) occlusion query\n", This);
1225 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1226 hr = WINED3D_OK;
1227 else
1228 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1229 break;
1231 case WINED3DQUERYTYPE_EVENT:
1232 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1233 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1234 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1236 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1238 hr = WINED3D_OK;
1239 break;
1241 case WINED3DQUERYTYPE_VCACHE:
1242 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1243 case WINED3DQUERYTYPE_VERTEXSTATS:
1244 case WINED3DQUERYTYPE_TIMESTAMP:
1245 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1246 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1247 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1248 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1249 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1250 case WINED3DQUERYTYPE_PIXELTIMINGS:
1251 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1252 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1253 default:
1254 FIXME("(%p) Unhandled query type %d\n", This, Type);
1256 if(NULL == ppQuery || hr != WINED3D_OK) {
1257 return hr;
1260 D3DCREATEOBJECTINSTANCE(object, Query)
1261 object->type = Type;
1262 /* allocated the 'extended' data based on the type of query requested */
1263 switch(Type){
1264 case WINED3DQUERYTYPE_OCCLUSION:
1265 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1266 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1268 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1269 TRACE("(%p) Allocating data for an occlusion query\n", This);
1270 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1271 break;
1273 case WINED3DQUERYTYPE_EVENT:
1274 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1275 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1277 if(GL_SUPPORT(APPLE_FENCE)) {
1278 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1279 checkGLcall("glGenFencesAPPLE");
1280 } else if(GL_SUPPORT(NV_FENCE)) {
1281 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1282 checkGLcall("glGenFencesNV");
1284 break;
1286 case WINED3DQUERYTYPE_VCACHE:
1287 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1288 case WINED3DQUERYTYPE_VERTEXSTATS:
1289 case WINED3DQUERYTYPE_TIMESTAMP:
1290 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1291 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1292 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1293 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1294 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1295 case WINED3DQUERYTYPE_PIXELTIMINGS:
1296 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1297 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1298 default:
1299 object->extendedData = 0;
1300 FIXME("(%p) Unhandled query type %d\n",This , Type);
1302 TRACE("(%p) : Created Query %p\n", This, object);
1303 return WINED3D_OK;
1306 /*****************************************************************************
1307 * IWineD3DDeviceImpl_SetupFullscreenWindow
1309 * Helper function that modifies a HWND's Style and ExStyle for proper
1310 * fullscreen use.
1312 * Params:
1313 * iface: Pointer to the IWineD3DDevice interface
1314 * window: Window to setup
1316 *****************************************************************************/
1317 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1320 LONG style, exStyle;
1321 /* Don't do anything if an original style is stored.
1322 * That shouldn't happen
1324 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1325 if (This->style || This->exStyle) {
1326 ERR("(%p): Want to change the window parameters of HWND %p, but "
1327 "another style is stored for restoration afterwards\n", This, window);
1330 /* Get the parameters and save them */
1331 style = GetWindowLongW(window, GWL_STYLE);
1332 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1333 This->style = style;
1334 This->exStyle = exStyle;
1336 /* Filter out window decorations */
1337 style &= ~WS_CAPTION;
1338 style &= ~WS_THICKFRAME;
1339 exStyle &= ~WS_EX_WINDOWEDGE;
1340 exStyle &= ~WS_EX_CLIENTEDGE;
1342 /* Make sure the window is managed, otherwise we won't get keyboard input */
1343 style |= WS_POPUP | WS_SYSMENU;
1345 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1346 This->style, This->exStyle, style, exStyle);
1348 SetWindowLongW(window, GWL_STYLE, style);
1349 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1351 /* Inform the window about the update. */
1352 SetWindowPos(window, HWND_TOP, 0, 0,
1353 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1354 ShowWindow(window, SW_NORMAL);
1357 /*****************************************************************************
1358 * IWineD3DDeviceImpl_RestoreWindow
1360 * Helper function that restores a windows' properties when taking it out
1361 * of fullscreen mode
1363 * Params:
1364 * iface: Pointer to the IWineD3DDevice interface
1365 * window: Window to setup
1367 *****************************************************************************/
1368 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1371 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1372 * switch, do nothing
1374 if (!This->style && !This->exStyle) return;
1376 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1377 This, window, This->style, This->exStyle);
1379 SetWindowLongW(window, GWL_STYLE, This->style);
1380 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1382 /* Delete the old values */
1383 This->style = 0;
1384 This->exStyle = 0;
1386 /* Inform the window about the update */
1387 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1388 0, 0, 0, 0, /* Pos, Size, ignored */
1389 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1392 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1393 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1394 IUnknown* parent,
1395 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1396 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1399 HDC hDc;
1400 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1401 HRESULT hr = WINED3D_OK;
1402 IUnknown *bufferParent;
1403 BOOL displaymode_set = FALSE;
1405 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1407 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1408 * does a device hold a reference to a swap chain giving them a lifetime of the device
1409 * or does the swap chain notify the device of its destruction.
1410 *******************************/
1412 /* Check the params */
1413 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1414 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1415 return WINED3DERR_INVALIDCALL;
1416 } else if (pPresentationParameters->BackBufferCount > 1) {
1417 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");
1420 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1422 /*********************
1423 * Lookup the window Handle and the relating X window handle
1424 ********************/
1426 /* Setup hwnd we are using, plus which display this equates to */
1427 object->win_handle = pPresentationParameters->hDeviceWindow;
1428 if (!object->win_handle) {
1429 object->win_handle = This->createParms.hFocusWindow;
1431 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1433 hDc = GetDC(object->win_handle);
1434 TRACE("Using hDc %p\n", hDc);
1436 if (NULL == hDc) {
1437 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1438 return WINED3DERR_NOTAVAILABLE;
1441 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1442 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1443 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1444 ReleaseDC(object->win_handle, hDc);
1446 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1447 * then the corresponding dimension of the client area of the hDeviceWindow
1448 * (or the focus window, if hDeviceWindow is NULL) is taken.
1449 **********************/
1451 if (pPresentationParameters->Windowed &&
1452 ((pPresentationParameters->BackBufferWidth == 0) ||
1453 (pPresentationParameters->BackBufferHeight == 0) ||
1454 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1456 RECT Rect;
1457 GetClientRect(object->win_handle, &Rect);
1459 if (pPresentationParameters->BackBufferWidth == 0) {
1460 pPresentationParameters->BackBufferWidth = Rect.right;
1461 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1463 if (pPresentationParameters->BackBufferHeight == 0) {
1464 pPresentationParameters->BackBufferHeight = Rect.bottom;
1465 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1467 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1468 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1469 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1473 /* Put the correct figures in the presentation parameters */
1474 TRACE("Copying across presentation parameters\n");
1475 object->presentParms = *pPresentationParameters;
1477 TRACE("calling rendertarget CB\n");
1478 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1479 parent,
1480 object->presentParms.BackBufferWidth,
1481 object->presentParms.BackBufferHeight,
1482 object->presentParms.BackBufferFormat,
1483 object->presentParms.MultiSampleType,
1484 object->presentParms.MultiSampleQuality,
1485 TRUE /* Lockable */,
1486 &object->frontBuffer,
1487 NULL /* pShared (always null)*/);
1488 if (object->frontBuffer != NULL) {
1489 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1490 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1491 } else {
1492 ERR("Failed to create the front buffer\n");
1493 goto error;
1496 /*********************
1497 * Windowed / Fullscreen
1498 *******************/
1501 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1502 * so we should really check to see if there is a fullscreen swapchain already
1503 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1504 **************************************/
1506 if (!pPresentationParameters->Windowed) {
1508 DEVMODEW devmode;
1509 HDC hdc;
1510 int bpp = 0;
1511 RECT clip_rc;
1513 /* Get info on the current display setup */
1514 hdc = GetDC(0);
1515 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1516 ReleaseDC(0, hdc);
1518 /* Change the display settings */
1519 memset(&devmode, 0, sizeof(devmode));
1520 devmode.dmSize = sizeof(devmode);
1521 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1522 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1523 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1524 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1525 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1526 displaymode_set = TRUE;
1528 /* For GetDisplayMode */
1529 This->ddraw_width = devmode.dmPelsWidth;
1530 This->ddraw_height = devmode.dmPelsHeight;
1531 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1533 IWineD3DDevice_SetFullscreen(iface, TRUE);
1535 /* And finally clip mouse to our screen */
1536 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1537 ClipCursor(&clip_rc);
1541 * Create an opengl context for the display visual
1542 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1543 * use different properties after that point in time. FIXME: How to handle when requested format
1544 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1545 * it chooses is identical to the one already being used!
1546 **********************************/
1547 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1549 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1550 if(!object->context)
1551 return E_OUTOFMEMORY;
1552 object->num_contexts = 1;
1554 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1555 if (!object->context[0]) {
1556 ERR("Failed to create a new context\n");
1557 hr = WINED3DERR_NOTAVAILABLE;
1558 goto error;
1559 } else {
1560 TRACE("Context created (HWND=%p, glContext=%p)\n",
1561 object->win_handle, object->context[0]->glCtx);
1564 /*********************
1565 * Create the back, front and stencil buffers
1566 *******************/
1567 if(object->presentParms.BackBufferCount > 0) {
1568 int i;
1570 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1571 if(!object->backBuffer) {
1572 ERR("Out of memory\n");
1573 hr = E_OUTOFMEMORY;
1574 goto error;
1577 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1578 TRACE("calling rendertarget CB\n");
1579 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1580 parent,
1581 object->presentParms.BackBufferWidth,
1582 object->presentParms.BackBufferHeight,
1583 object->presentParms.BackBufferFormat,
1584 object->presentParms.MultiSampleType,
1585 object->presentParms.MultiSampleQuality,
1586 TRUE /* Lockable */,
1587 &object->backBuffer[i],
1588 NULL /* pShared (always null)*/);
1589 if(hr == WINED3D_OK && object->backBuffer[i]) {
1590 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1591 } else {
1592 ERR("Cannot create new back buffer\n");
1593 goto error;
1595 ENTER_GL();
1596 glDrawBuffer(GL_BACK);
1597 checkGLcall("glDrawBuffer(GL_BACK)");
1598 LEAVE_GL();
1600 } else {
1601 object->backBuffer = NULL;
1603 /* Single buffering - draw to front buffer */
1604 ENTER_GL();
1605 glDrawBuffer(GL_FRONT);
1606 checkGLcall("glDrawBuffer(GL_FRONT)");
1607 LEAVE_GL();
1610 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1611 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1612 TRACE("Creating depth stencil buffer\n");
1613 if (This->auto_depth_stencil_buffer == NULL ) {
1614 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1615 parent,
1616 object->presentParms.BackBufferWidth,
1617 object->presentParms.BackBufferHeight,
1618 object->presentParms.AutoDepthStencilFormat,
1619 object->presentParms.MultiSampleType,
1620 object->presentParms.MultiSampleQuality,
1621 FALSE /* FIXME: Discard */,
1622 &This->auto_depth_stencil_buffer,
1623 NULL /* pShared (always null)*/ );
1624 if (This->auto_depth_stencil_buffer != NULL)
1625 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1628 /** TODO: A check on width, height and multisample types
1629 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1630 ****************************/
1631 object->wantsDepthStencilBuffer = TRUE;
1632 } else {
1633 object->wantsDepthStencilBuffer = FALSE;
1636 TRACE("Created swapchain %p\n", object);
1637 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1638 return WINED3D_OK;
1640 error:
1641 if (displaymode_set) {
1642 DEVMODEW devmode;
1643 HDC hdc;
1644 int bpp = 0;
1645 RECT clip_rc;
1647 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1648 ClipCursor(NULL);
1650 /* Get info on the current display setup */
1651 hdc = GetDC(0);
1652 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1653 ReleaseDC(0, hdc);
1655 /* Change the display settings */
1656 memset(&devmode, 0, sizeof(devmode));
1657 devmode.dmSize = sizeof(devmode);
1658 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1659 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1660 devmode.dmPelsWidth = object->orig_width;
1661 devmode.dmPelsHeight = object->orig_height;
1662 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1665 if (object->backBuffer) {
1666 int i;
1667 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1668 if(object->backBuffer[i]) {
1669 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1670 IUnknown_Release(bufferParent); /* once for the get parent */
1671 if (IUnknown_Release(bufferParent) > 0) {
1672 FIXME("(%p) Something's still holding the back buffer\n",This);
1676 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1677 object->backBuffer = NULL;
1679 if(object->context[0])
1680 DestroyContext(This, object->context[0]);
1681 if(object->frontBuffer) {
1682 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1683 IUnknown_Release(bufferParent); /* once for the get parent */
1684 if (IUnknown_Release(bufferParent) > 0) {
1685 FIXME("(%p) Something's still holding the front buffer\n",This);
1688 HeapFree(GetProcessHeap(), 0, object);
1689 return hr;
1692 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1693 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1695 TRACE("(%p)\n", This);
1697 return This->NumberOfSwapChains;
1700 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1702 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1704 if(iSwapChain < This->NumberOfSwapChains) {
1705 *pSwapChain = This->swapchains[iSwapChain];
1706 IWineD3DSwapChain_AddRef(*pSwapChain);
1707 TRACE("(%p) returning %p\n", This, *pSwapChain);
1708 return WINED3D_OK;
1709 } else {
1710 TRACE("Swapchain out of range\n");
1711 *pSwapChain = NULL;
1712 return WINED3DERR_INVALIDCALL;
1716 /*****
1717 * Vertex Declaration
1718 *****/
1719 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1720 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1722 IWineD3DVertexDeclarationImpl *object = NULL;
1723 HRESULT hr = WINED3D_OK;
1725 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1726 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1728 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1730 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1732 return hr;
1735 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1737 unsigned int idx, idx2;
1738 unsigned int offset;
1739 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1740 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1741 BOOL has_blend_idx = has_blend &&
1742 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1743 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1744 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1745 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1746 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1747 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1748 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1750 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1751 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1753 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1754 WINED3DVERTEXELEMENT *elements = NULL;
1756 unsigned int size;
1757 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1758 if (has_blend_idx) num_blends--;
1760 /* Compute declaration size */
1761 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1762 has_psize + has_diffuse + has_specular + num_textures + 1;
1764 /* convert the declaration */
1765 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1766 if (!elements)
1767 return 0;
1769 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1770 idx = 0;
1771 if (has_pos) {
1772 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1773 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1774 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1776 else {
1777 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1778 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1780 elements[idx].UsageIndex = 0;
1781 idx++;
1783 if (has_blend && (num_blends > 0)) {
1784 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1785 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1786 else
1787 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1788 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1789 elements[idx].UsageIndex = 0;
1790 idx++;
1792 if (has_blend_idx) {
1793 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1794 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1795 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1796 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1797 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1798 else
1799 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1800 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1801 elements[idx].UsageIndex = 0;
1802 idx++;
1804 if (has_normal) {
1805 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1806 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1807 elements[idx].UsageIndex = 0;
1808 idx++;
1810 if (has_psize) {
1811 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1812 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1813 elements[idx].UsageIndex = 0;
1814 idx++;
1816 if (has_diffuse) {
1817 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1818 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1819 elements[idx].UsageIndex = 0;
1820 idx++;
1822 if (has_specular) {
1823 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1824 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1825 elements[idx].UsageIndex = 1;
1826 idx++;
1828 for (idx2 = 0; idx2 < num_textures; idx2++) {
1829 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1830 switch (numcoords) {
1831 case WINED3DFVF_TEXTUREFORMAT1:
1832 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1833 break;
1834 case WINED3DFVF_TEXTUREFORMAT2:
1835 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1836 break;
1837 case WINED3DFVF_TEXTUREFORMAT3:
1838 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1839 break;
1840 case WINED3DFVF_TEXTUREFORMAT4:
1841 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1842 break;
1844 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1845 elements[idx].UsageIndex = idx2;
1846 idx++;
1849 /* Now compute offsets, and initialize the rest of the fields */
1850 for (idx = 0, offset = 0; idx < size-1; idx++) {
1851 elements[idx].Stream = 0;
1852 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1853 elements[idx].Offset = offset;
1854 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1857 *ppVertexElements = elements;
1858 return size;
1861 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1862 WINED3DVERTEXELEMENT* elements = NULL;
1863 size_t size;
1864 DWORD hr;
1866 size = ConvertFvfToDeclaration(Fvf, &elements);
1867 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1869 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1870 HeapFree(GetProcessHeap(), 0, elements);
1871 if (hr != S_OK) return hr;
1873 return WINED3D_OK;
1876 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1877 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1879 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1880 HRESULT hr = WINED3D_OK;
1881 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1882 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1884 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1886 if (vertex_declaration) {
1887 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1890 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1892 if (WINED3D_OK != hr) {
1893 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1894 IWineD3DVertexShader_Release(*ppVertexShader);
1895 return WINED3DERR_INVALIDCALL;
1898 return WINED3D_OK;
1901 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1903 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1904 HRESULT hr = WINED3D_OK;
1906 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1907 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1908 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1909 if (WINED3D_OK == hr) {
1910 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1911 } else {
1912 WARN("(%p) : Failed to create pixel shader\n", This);
1915 return hr;
1918 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1920 IWineD3DPaletteImpl *object;
1921 HRESULT hr;
1922 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1924 /* Create the new object */
1925 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1926 if(!object) {
1927 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1928 return E_OUTOFMEMORY;
1931 object->lpVtbl = &IWineD3DPalette_Vtbl;
1932 object->ref = 1;
1933 object->Flags = Flags;
1934 object->parent = Parent;
1935 object->wineD3DDevice = This;
1936 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1938 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1940 if(!object->hpal) {
1941 HeapFree( GetProcessHeap(), 0, object);
1942 return E_OUTOFMEMORY;
1945 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1946 if(FAILED(hr)) {
1947 IWineD3DPalette_Release((IWineD3DPalette *) object);
1948 return hr;
1951 *Palette = (IWineD3DPalette *) object;
1953 return WINED3D_OK;
1956 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1957 HBITMAP hbm;
1958 BITMAP bm;
1959 HRESULT hr;
1960 HDC dcb = NULL, dcs = NULL;
1961 WINEDDCOLORKEY colorkey;
1963 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1964 if(hbm)
1966 GetObjectA(hbm, sizeof(BITMAP), &bm);
1967 dcb = CreateCompatibleDC(NULL);
1968 if(!dcb) goto out;
1969 SelectObject(dcb, hbm);
1971 else
1973 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1974 * couldn't be loaded
1976 memset(&bm, 0, sizeof(bm));
1977 bm.bmWidth = 32;
1978 bm.bmHeight = 32;
1981 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1982 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1983 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1984 if(FAILED(hr)) {
1985 ERR("Wine logo requested, but failed to create surface\n");
1986 goto out;
1989 if(dcb) {
1990 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1991 if(FAILED(hr)) goto out;
1992 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1993 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1995 colorkey.dwColorSpaceLowValue = 0;
1996 colorkey.dwColorSpaceHighValue = 0;
1997 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1998 } else {
1999 /* Fill the surface with a white color to show that wined3d is there */
2000 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2003 out:
2004 if(dcb) {
2005 DeleteDC(dcb);
2007 if(hbm) {
2008 DeleteObject(hbm);
2010 return;
2013 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2015 IWineD3DSwapChainImpl *swapchain;
2016 HRESULT hr;
2017 DWORD state;
2019 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2020 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2022 /* TODO: Test if OpenGL is compiled in and loaded */
2024 TRACE("(%p) : Creating stateblock\n", This);
2025 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2026 hr = IWineD3DDevice_CreateStateBlock(iface,
2027 WINED3DSBT_INIT,
2028 (IWineD3DStateBlock **)&This->stateBlock,
2029 NULL);
2030 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2031 WARN("Failed to create stateblock\n");
2032 goto err_out;
2034 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2035 This->updateStateBlock = This->stateBlock;
2036 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2038 hr = allocate_shader_constants(This->updateStateBlock);
2039 if (WINED3D_OK != hr) {
2040 goto err_out;
2043 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2044 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2045 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2047 /* Initialize the texture unit mapping to a 1:1 mapping */
2048 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2049 if (state < GL_LIMITS(fragment_samplers)) {
2050 This->texUnitMap[state] = state;
2051 This->rev_tex_unit_map[state] = state;
2052 } else {
2053 This->texUnitMap[state] = -1;
2054 This->rev_tex_unit_map[state] = -1;
2058 /* Setup the implicit swapchain */
2059 TRACE("Creating implicit swapchain\n");
2060 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2061 if (FAILED(hr) || !swapchain) {
2062 WARN("Failed to create implicit swapchain\n");
2063 goto err_out;
2066 This->NumberOfSwapChains = 1;
2067 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2068 if(!This->swapchains) {
2069 ERR("Out of memory!\n");
2070 goto err_out;
2072 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2074 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2075 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2076 This->render_targets[0] = swapchain->backBuffer[0];
2077 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2079 else {
2080 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2081 This->render_targets[0] = swapchain->frontBuffer;
2082 This->lastActiveRenderTarget = swapchain->frontBuffer;
2084 IWineD3DSurface_AddRef(This->render_targets[0]);
2085 This->activeContext = swapchain->context[0];
2086 This->lastThread = GetCurrentThreadId();
2088 /* Depth Stencil support */
2089 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2090 if (NULL != This->stencilBufferTarget) {
2091 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2094 /* Set up some starting GL setup */
2095 ENTER_GL();
2097 /* Setup all the devices defaults */
2098 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2099 #if 0
2100 IWineD3DImpl_CheckGraphicsMemory();
2101 #endif
2103 { /* Set a default viewport */
2104 WINED3DVIEWPORT vp;
2105 vp.X = 0;
2106 vp.Y = 0;
2107 vp.Width = pPresentationParameters->BackBufferWidth;
2108 vp.Height = pPresentationParameters->BackBufferHeight;
2109 vp.MinZ = 0.0f;
2110 vp.MaxZ = 1.0f;
2111 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2114 /* Initialize the current view state */
2115 This->view_ident = 1;
2116 This->contexts[0]->last_was_rhw = 0;
2117 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2118 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2120 switch(wined3d_settings.offscreen_rendering_mode) {
2121 case ORM_FBO:
2122 case ORM_PBUFFER:
2123 This->offscreenBuffer = GL_BACK;
2124 break;
2126 case ORM_BACKBUFFER:
2128 if(GL_LIMITS(aux_buffers) > 0) {
2129 TRACE("Using auxilliary buffer for offscreen rendering\n");
2130 This->offscreenBuffer = GL_AUX0;
2131 } else {
2132 TRACE("Using back buffer for offscreen rendering\n");
2133 This->offscreenBuffer = GL_BACK;
2138 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2139 LEAVE_GL();
2141 /* Clear the screen */
2142 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2143 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2144 0x00, 1.0, 0);
2146 This->d3d_initialized = TRUE;
2148 if(wined3d_settings.logo) {
2149 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2151 return WINED3D_OK;
2153 err_out:
2154 HeapFree(GetProcessHeap(), 0, This->render_targets);
2155 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2156 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2157 HeapFree(GetProcessHeap(), 0, This->swapchains);
2158 This->NumberOfSwapChains = 0;
2159 if(swapchain) {
2160 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2162 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2163 if(This->stateBlock) {
2164 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2165 This->stateBlock = NULL;
2167 return hr;
2170 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2172 int sampler;
2173 UINT i;
2174 TRACE("(%p)\n", This);
2176 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2178 /* I don't think that the interface guarants that the device is destroyed from the same thread
2179 * it was created. Thus make sure a context is active for the glDelete* calls
2181 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2183 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2185 TRACE("Deleting high order patches\n");
2186 for(i = 0; i < PATCHMAP_SIZE; i++) {
2187 struct list *e1, *e2;
2188 struct WineD3DRectPatch *patch;
2189 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2190 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2191 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2195 /* Delete the palette conversion shader if it is around */
2196 if(This->paletteConversionShader) {
2197 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2198 This->paletteConversionShader = 0;
2201 /* Delete the pbuffer context if there is any */
2202 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2204 /* Delete the mouse cursor texture */
2205 if(This->cursorTexture) {
2206 ENTER_GL();
2207 glDeleteTextures(1, &This->cursorTexture);
2208 LEAVE_GL();
2209 This->cursorTexture = 0;
2212 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2213 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2215 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2216 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2219 /* Release the update stateblock */
2220 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2221 if(This->updateStateBlock != This->stateBlock)
2222 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2224 This->updateStateBlock = NULL;
2226 { /* because were not doing proper internal refcounts releasing the primary state block
2227 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2228 to set this->stateBlock = NULL; first */
2229 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2230 This->stateBlock = NULL;
2232 /* Release the stateblock */
2233 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2234 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2238 /* Release the buffers (with sanity checks)*/
2239 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2240 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2241 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2242 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2244 This->stencilBufferTarget = NULL;
2246 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2247 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2248 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2250 TRACE("Setting rendertarget to NULL\n");
2251 This->render_targets[0] = NULL;
2253 if (This->auto_depth_stencil_buffer) {
2254 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2255 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2257 This->auto_depth_stencil_buffer = NULL;
2260 for(i=0; i < This->NumberOfSwapChains; i++) {
2261 TRACE("Releasing the implicit swapchain %d\n", i);
2262 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2263 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2267 HeapFree(GetProcessHeap(), 0, This->swapchains);
2268 This->swapchains = NULL;
2269 This->NumberOfSwapChains = 0;
2271 HeapFree(GetProcessHeap(), 0, This->render_targets);
2272 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2273 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2274 This->render_targets = NULL;
2275 This->fbo_color_attachments = NULL;
2276 This->draw_buffers = NULL;
2279 This->d3d_initialized = FALSE;
2280 return WINED3D_OK;
2283 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2285 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2287 /* Setup the window for fullscreen mode */
2288 if(fullscreen && !This->ddraw_fullscreen) {
2289 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2290 } else if(!fullscreen && This->ddraw_fullscreen) {
2291 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2294 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2295 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2296 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2297 * separately.
2299 This->ddraw_fullscreen = fullscreen;
2302 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2303 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2304 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2306 * There is no way to deactivate thread safety once it is enabled.
2308 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2311 /*For now just store the flag(needed in case of ddraw) */
2312 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2314 return;
2317 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2318 DEVMODEW devmode;
2319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2320 LONG ret;
2321 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2322 RECT clip_rc;
2324 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2326 /* Resize the screen even without a window:
2327 * The app could have unset it with SetCooperativeLevel, but not called
2328 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2329 * but we don't have any hwnd
2332 memset(&devmode, 0, sizeof(devmode));
2333 devmode.dmSize = sizeof(devmode);
2334 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2335 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2336 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2337 devmode.dmPelsWidth = pMode->Width;
2338 devmode.dmPelsHeight = pMode->Height;
2340 devmode.dmDisplayFrequency = pMode->RefreshRate;
2341 if (pMode->RefreshRate != 0) {
2342 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2345 /* Only change the mode if necessary */
2346 if( (This->ddraw_width == pMode->Width) &&
2347 (This->ddraw_height == pMode->Height) &&
2348 (This->ddraw_format == pMode->Format) &&
2349 (pMode->RefreshRate == 0) ) {
2350 return WINED3D_OK;
2353 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2354 if (ret != DISP_CHANGE_SUCCESSFUL) {
2355 if(devmode.dmDisplayFrequency != 0) {
2356 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2357 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2358 devmode.dmDisplayFrequency = 0;
2359 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2361 if(ret != DISP_CHANGE_SUCCESSFUL) {
2362 return WINED3DERR_NOTAVAILABLE;
2366 /* Store the new values */
2367 This->ddraw_width = pMode->Width;
2368 This->ddraw_height = pMode->Height;
2369 This->ddraw_format = pMode->Format;
2371 /* Only do this with a window of course */
2372 if(This->ddraw_window)
2373 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2375 /* And finally clip mouse to our screen */
2376 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2377 ClipCursor(&clip_rc);
2379 return WINED3D_OK;
2382 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2384 *ppD3D= This->wineD3D;
2385 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2386 IWineD3D_AddRef(*ppD3D);
2387 return WINED3D_OK;
2390 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2393 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2394 (This->adapter->TextureRam/(1024*1024)),
2395 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2396 /* return simulated texture memory left */
2397 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2402 /*****
2403 * Get / Set FVF
2404 *****/
2405 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2408 /* Update the current state block */
2409 This->updateStateBlock->changed.fvf = TRUE;
2411 if(This->updateStateBlock->fvf == fvf) {
2412 TRACE("Application is setting the old fvf over, nothing to do\n");
2413 return WINED3D_OK;
2416 This->updateStateBlock->fvf = fvf;
2417 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2418 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2419 return WINED3D_OK;
2423 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2425 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2426 *pfvf = This->stateBlock->fvf;
2427 return WINED3D_OK;
2430 /*****
2431 * Get / Set Stream Source
2432 *****/
2433 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2435 IWineD3DVertexBuffer *oldSrc;
2437 if (StreamNumber >= MAX_STREAMS) {
2438 WARN("Stream out of range %d\n", StreamNumber);
2439 return WINED3DERR_INVALIDCALL;
2442 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2443 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2445 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2447 if(oldSrc == pStreamData &&
2448 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2449 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2450 TRACE("Application is setting the old values over, nothing to do\n");
2451 return WINED3D_OK;
2454 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2455 if (pStreamData) {
2456 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2457 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2460 /* Handle recording of state blocks */
2461 if (This->isRecordingState) {
2462 TRACE("Recording... not performing anything\n");
2463 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2464 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2465 return WINED3D_OK;
2468 /* Need to do a getParent and pass the reffs up */
2469 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2470 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2471 so for now, just count internally */
2472 if (pStreamData != NULL) {
2473 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2474 InterlockedIncrement(&vbImpl->bindCount);
2475 IWineD3DVertexBuffer_AddRef(pStreamData);
2477 if (oldSrc != NULL) {
2478 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2479 IWineD3DVertexBuffer_Release(oldSrc);
2482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2484 return WINED3D_OK;
2487 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2490 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2491 This->stateBlock->streamSource[StreamNumber],
2492 This->stateBlock->streamOffset[StreamNumber],
2493 This->stateBlock->streamStride[StreamNumber]);
2495 if (StreamNumber >= MAX_STREAMS) {
2496 WARN("Stream out of range %d\n", StreamNumber);
2497 return WINED3DERR_INVALIDCALL;
2499 *pStream = This->stateBlock->streamSource[StreamNumber];
2500 *pStride = This->stateBlock->streamStride[StreamNumber];
2501 if (pOffset) {
2502 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2505 if (*pStream != NULL) {
2506 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2508 return WINED3D_OK;
2511 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2513 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2514 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2516 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2517 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2519 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2520 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2522 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2523 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2524 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2527 return WINED3D_OK;
2530 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2533 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2534 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2536 TRACE("(%p) : returning %d\n", This, *Divider);
2538 return WINED3D_OK;
2541 /*****
2542 * Get / Set & Multiply Transform
2543 *****/
2544 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2547 /* Most of this routine, comments included copied from ddraw tree initially: */
2548 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2550 /* Handle recording of state blocks */
2551 if (This->isRecordingState) {
2552 TRACE("Recording... not performing anything\n");
2553 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2554 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2555 return WINED3D_OK;
2559 * If the new matrix is the same as the current one,
2560 * we cut off any further processing. this seems to be a reasonable
2561 * optimization because as was noticed, some apps (warcraft3 for example)
2562 * tend towards setting the same matrix repeatedly for some reason.
2564 * From here on we assume that the new matrix is different, wherever it matters.
2566 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2567 TRACE("The app is setting the same matrix over again\n");
2568 return WINED3D_OK;
2569 } else {
2570 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2574 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2575 where ViewMat = Camera space, WorldMat = world space.
2577 In OpenGL, camera and world space is combined into GL_MODELVIEW
2578 matrix. The Projection matrix stay projection matrix.
2581 /* Capture the times we can just ignore the change for now */
2582 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2583 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2584 /* Handled by the state manager */
2587 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2588 return WINED3D_OK;
2591 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2593 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2594 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2595 return WINED3D_OK;
2598 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2599 WINED3DMATRIX *mat = NULL;
2600 WINED3DMATRIX temp;
2602 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2603 * below means it will be recorded in a state block change, but it
2604 * works regardless where it is recorded.
2605 * If this is found to be wrong, change to StateBlock.
2607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2608 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2610 if (State < HIGHEST_TRANSFORMSTATE)
2612 mat = &This->updateStateBlock->transforms[State];
2613 } else {
2614 FIXME("Unhandled transform state!!\n");
2617 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2619 /* Apply change via set transform - will reapply to eg. lights this way */
2620 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2623 /*****
2624 * Get / Set Light
2625 *****/
2626 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2627 you can reference any indexes you want as long as that number max are enabled at any
2628 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2629 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2630 but when recording, just build a chain pretty much of commands to be replayed. */
2632 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2633 float rho;
2634 PLIGHTINFOEL *object = NULL;
2635 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2636 struct list *e;
2638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2639 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2641 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2642 * the gl driver.
2644 if(!pLight) {
2645 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2646 return WINED3DERR_INVALIDCALL;
2649 switch(pLight->Type) {
2650 case WINED3DLIGHT_POINT:
2651 case WINED3DLIGHT_SPOT:
2652 case WINED3DLIGHT_PARALLELPOINT:
2653 case WINED3DLIGHT_GLSPOT:
2654 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2655 * most wanted
2657 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2658 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2659 return WINED3DERR_INVALIDCALL;
2661 break;
2663 case WINED3DLIGHT_DIRECTIONAL:
2664 /* Ignores attenuation */
2665 break;
2667 default:
2668 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2669 return WINED3DERR_INVALIDCALL;
2672 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2673 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2674 if(object->OriginalIndex == Index) break;
2675 object = NULL;
2678 if(!object) {
2679 TRACE("Adding new light\n");
2680 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2681 if(!object) {
2682 ERR("Out of memory error when allocating a light\n");
2683 return E_OUTOFMEMORY;
2685 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2686 object->glIndex = -1;
2687 object->OriginalIndex = Index;
2688 object->changed = TRUE;
2691 /* Initialize the object */
2692 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,
2693 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2694 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2695 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2696 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2697 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2698 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2700 /* Save away the information */
2701 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2703 switch (pLight->Type) {
2704 case WINED3DLIGHT_POINT:
2705 /* Position */
2706 object->lightPosn[0] = pLight->Position.x;
2707 object->lightPosn[1] = pLight->Position.y;
2708 object->lightPosn[2] = pLight->Position.z;
2709 object->lightPosn[3] = 1.0f;
2710 object->cutoff = 180.0f;
2711 /* FIXME: Range */
2712 break;
2714 case WINED3DLIGHT_DIRECTIONAL:
2715 /* Direction */
2716 object->lightPosn[0] = -pLight->Direction.x;
2717 object->lightPosn[1] = -pLight->Direction.y;
2718 object->lightPosn[2] = -pLight->Direction.z;
2719 object->lightPosn[3] = 0.0;
2720 object->exponent = 0.0f;
2721 object->cutoff = 180.0f;
2722 break;
2724 case WINED3DLIGHT_SPOT:
2725 /* Position */
2726 object->lightPosn[0] = pLight->Position.x;
2727 object->lightPosn[1] = pLight->Position.y;
2728 object->lightPosn[2] = pLight->Position.z;
2729 object->lightPosn[3] = 1.0;
2731 /* Direction */
2732 object->lightDirn[0] = pLight->Direction.x;
2733 object->lightDirn[1] = pLight->Direction.y;
2734 object->lightDirn[2] = pLight->Direction.z;
2735 object->lightDirn[3] = 1.0;
2738 * opengl-ish and d3d-ish spot lights use too different models for the
2739 * light "intensity" as a function of the angle towards the main light direction,
2740 * so we only can approximate very roughly.
2741 * however spot lights are rather rarely used in games (if ever used at all).
2742 * furthermore if still used, probably nobody pays attention to such details.
2744 if (pLight->Falloff == 0) {
2745 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2746 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2747 * will always be 1.0 for both of them, and we don't have to care for the
2748 * rest of the rather complex calculation
2750 object->exponent = 0;
2751 } else {
2752 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2753 if (rho < 0.0001) rho = 0.0001f;
2754 object->exponent = -0.3/log(cos(rho/2));
2756 if (object->exponent > 128.0) {
2757 object->exponent = 128.0;
2759 object->cutoff = pLight->Phi*90/M_PI;
2761 /* FIXME: Range */
2762 break;
2764 default:
2765 FIXME("Unrecognized light type %d\n", pLight->Type);
2768 /* Update the live definitions if the light is currently assigned a glIndex */
2769 if (object->glIndex != -1 && !This->isRecordingState) {
2770 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2772 return WINED3D_OK;
2775 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2776 PLIGHTINFOEL *lightInfo = NULL;
2777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2778 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2779 struct list *e;
2780 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2782 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2783 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2784 if(lightInfo->OriginalIndex == Index) break;
2785 lightInfo = NULL;
2788 if (lightInfo == NULL) {
2789 TRACE("Light information requested but light not defined\n");
2790 return WINED3DERR_INVALIDCALL;
2793 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2794 return WINED3D_OK;
2797 /*****
2798 * Get / Set Light Enable
2799 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2800 *****/
2801 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2802 PLIGHTINFOEL *lightInfo = NULL;
2803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2804 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2805 struct list *e;
2806 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2808 /* Tests show true = 128...not clear why */
2809 Enable = Enable? 128: 0;
2811 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2812 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2813 if(lightInfo->OriginalIndex == Index) break;
2814 lightInfo = NULL;
2816 TRACE("Found light: %p\n", lightInfo);
2818 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2819 if (lightInfo == NULL) {
2821 TRACE("Light enabled requested but light not defined, so defining one!\n");
2822 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2824 /* Search for it again! Should be fairly quick as near head of list */
2825 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2826 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2827 if(lightInfo->OriginalIndex == Index) break;
2828 lightInfo = NULL;
2830 if (lightInfo == NULL) {
2831 FIXME("Adding default lights has failed dismally\n");
2832 return WINED3DERR_INVALIDCALL;
2836 lightInfo->enabledChanged = TRUE;
2837 if(!Enable) {
2838 if(lightInfo->glIndex != -1) {
2839 if(!This->isRecordingState) {
2840 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2843 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2844 lightInfo->glIndex = -1;
2845 } else {
2846 TRACE("Light already disabled, nothing to do\n");
2848 } else {
2849 if (lightInfo->glIndex != -1) {
2850 /* nop */
2851 TRACE("Nothing to do as light was enabled\n");
2852 } else {
2853 int i;
2854 /* Find a free gl light */
2855 for(i = 0; i < This->maxConcurrentLights; i++) {
2856 if(This->stateBlock->activeLights[i] == NULL) {
2857 This->stateBlock->activeLights[i] = lightInfo;
2858 lightInfo->glIndex = i;
2859 break;
2862 if(lightInfo->glIndex == -1) {
2863 ERR("Too many concurrently active lights\n");
2864 return WINED3DERR_INVALIDCALL;
2867 /* i == lightInfo->glIndex */
2868 if(!This->isRecordingState) {
2869 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2874 return WINED3D_OK;
2877 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2879 PLIGHTINFOEL *lightInfo = NULL;
2880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2881 struct list *e;
2882 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2883 TRACE("(%p) : for idx(%d)\n", This, Index);
2885 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2886 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2887 if(lightInfo->OriginalIndex == Index) break;
2888 lightInfo = NULL;
2891 if (lightInfo == NULL) {
2892 TRACE("Light enabled state requested but light not defined\n");
2893 return WINED3DERR_INVALIDCALL;
2895 /* true is 128 according to SetLightEnable */
2896 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2897 return WINED3D_OK;
2900 /*****
2901 * Get / Set Clip Planes
2902 *****/
2903 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2905 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2907 /* Validate Index */
2908 if (Index >= GL_LIMITS(clipplanes)) {
2909 TRACE("Application has requested clipplane this device doesn't support\n");
2910 return WINED3DERR_INVALIDCALL;
2913 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2915 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2916 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2917 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2918 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2919 TRACE("Application is setting old values over, nothing to do\n");
2920 return WINED3D_OK;
2923 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2924 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2925 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2926 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2928 /* Handle recording of state blocks */
2929 if (This->isRecordingState) {
2930 TRACE("Recording... not performing anything\n");
2931 return WINED3D_OK;
2934 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2936 return WINED3D_OK;
2939 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2941 TRACE("(%p) : for idx %d\n", This, Index);
2943 /* Validate Index */
2944 if (Index >= GL_LIMITS(clipplanes)) {
2945 TRACE("Application has requested clipplane this device doesn't support\n");
2946 return WINED3DERR_INVALIDCALL;
2949 pPlane[0] = This->stateBlock->clipplane[Index][0];
2950 pPlane[1] = This->stateBlock->clipplane[Index][1];
2951 pPlane[2] = This->stateBlock->clipplane[Index][2];
2952 pPlane[3] = This->stateBlock->clipplane[Index][3];
2953 return WINED3D_OK;
2956 /*****
2957 * Get / Set Clip Plane Status
2958 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2959 *****/
2960 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2962 FIXME("(%p) : stub\n", This);
2963 if (NULL == pClipStatus) {
2964 return WINED3DERR_INVALIDCALL;
2966 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2967 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2968 return WINED3D_OK;
2971 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2973 FIXME("(%p) : stub\n", This);
2974 if (NULL == pClipStatus) {
2975 return WINED3DERR_INVALIDCALL;
2977 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2978 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2979 return WINED3D_OK;
2982 /*****
2983 * Get / Set Material
2984 *****/
2985 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2988 This->updateStateBlock->changed.material = TRUE;
2989 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2991 /* Handle recording of state blocks */
2992 if (This->isRecordingState) {
2993 TRACE("Recording... not performing anything\n");
2994 return WINED3D_OK;
2997 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2998 return WINED3D_OK;
3001 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3003 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3004 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3005 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3006 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3007 pMaterial->Ambient.b, pMaterial->Ambient.a);
3008 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3009 pMaterial->Specular.b, pMaterial->Specular.a);
3010 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3011 pMaterial->Emissive.b, pMaterial->Emissive.a);
3012 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3014 return WINED3D_OK;
3017 /*****
3018 * Get / Set Indices
3019 *****/
3020 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3022 IWineD3DIndexBuffer *oldIdxs;
3024 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3025 oldIdxs = This->updateStateBlock->pIndexData;
3027 This->updateStateBlock->changed.indices = TRUE;
3028 This->updateStateBlock->pIndexData = pIndexData;
3030 /* Handle recording of state blocks */
3031 if (This->isRecordingState) {
3032 TRACE("Recording... not performing anything\n");
3033 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3034 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3035 return WINED3D_OK;
3038 if(oldIdxs != pIndexData) {
3039 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3040 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3041 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3043 return WINED3D_OK;
3046 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3049 *ppIndexData = This->stateBlock->pIndexData;
3051 /* up ref count on ppindexdata */
3052 if (*ppIndexData) {
3053 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3054 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3055 }else{
3056 TRACE("(%p) No index data set\n", This);
3058 TRACE("Returning %p\n", *ppIndexData);
3060 return WINED3D_OK;
3063 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3064 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3066 TRACE("(%p)->(%d)\n", This, BaseIndex);
3068 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3069 TRACE("Application is setting the old value over, nothing to do\n");
3070 return WINED3D_OK;
3073 This->updateStateBlock->baseVertexIndex = BaseIndex;
3075 if (This->isRecordingState) {
3076 TRACE("Recording... not performing anything\n");
3077 return WINED3D_OK;
3079 /* The base vertex index affects the stream sources */
3080 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3081 return WINED3D_OK;
3084 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3086 TRACE("(%p) : base_index %p\n", This, base_index);
3088 *base_index = This->stateBlock->baseVertexIndex;
3090 TRACE("Returning %u\n", *base_index);
3092 return WINED3D_OK;
3095 /*****
3096 * Get / Set Viewports
3097 *****/
3098 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3101 TRACE("(%p)\n", This);
3102 This->updateStateBlock->changed.viewport = TRUE;
3103 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3105 /* Handle recording of state blocks */
3106 if (This->isRecordingState) {
3107 TRACE("Recording... not performing anything\n");
3108 return WINED3D_OK;
3111 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3112 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3114 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3115 return WINED3D_OK;
3119 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3121 TRACE("(%p)\n", This);
3122 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3123 return WINED3D_OK;
3126 /*****
3127 * Get / Set Render States
3128 * TODO: Verify against dx9 definitions
3129 *****/
3130 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3133 DWORD oldValue = This->stateBlock->renderState[State];
3135 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3137 This->updateStateBlock->changed.renderState[State] = TRUE;
3138 This->updateStateBlock->renderState[State] = Value;
3140 /* Handle recording of state blocks */
3141 if (This->isRecordingState) {
3142 TRACE("Recording... not performing anything\n");
3143 return WINED3D_OK;
3146 /* Compared here and not before the assignment to allow proper stateblock recording */
3147 if(Value == oldValue) {
3148 TRACE("Application is setting the old value over, nothing to do\n");
3149 } else {
3150 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3153 return WINED3D_OK;
3156 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3158 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3159 *pValue = This->stateBlock->renderState[State];
3160 return WINED3D_OK;
3163 /*****
3164 * Get / Set Sampler States
3165 * TODO: Verify against dx9 definitions
3166 *****/
3168 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3170 DWORD oldValue;
3172 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3173 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3175 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3176 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3180 * SetSampler is designed to allow for more than the standard up to 8 textures
3181 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3182 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3184 * http://developer.nvidia.com/object/General_FAQ.html#t6
3186 * There are two new settings for GForce
3187 * the sampler one:
3188 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3189 * and the texture one:
3190 * GL_MAX_TEXTURE_COORDS_ARB.
3191 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3192 ******************/
3194 oldValue = This->stateBlock->samplerState[Sampler][Type];
3195 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3196 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3198 /* Handle recording of state blocks */
3199 if (This->isRecordingState) {
3200 TRACE("Recording... not performing anything\n");
3201 return WINED3D_OK;
3204 if(oldValue == Value) {
3205 TRACE("Application is setting the old value over, nothing to do\n");
3206 return WINED3D_OK;
3209 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3211 return WINED3D_OK;
3214 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3217 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3218 This, Sampler, debug_d3dsamplerstate(Type), Type);
3220 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3221 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3224 *Value = This->stateBlock->samplerState[Sampler][Type];
3225 TRACE("(%p) : Returning %#x\n", This, *Value);
3227 return WINED3D_OK;
3230 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3233 This->updateStateBlock->changed.scissorRect = TRUE;
3234 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3235 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3236 return WINED3D_OK;
3238 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3240 if(This->isRecordingState) {
3241 TRACE("Recording... not performing anything\n");
3242 return WINED3D_OK;
3245 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3247 return WINED3D_OK;
3250 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3253 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3254 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3255 return WINED3D_OK;
3258 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3260 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3262 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3264 This->updateStateBlock->vertexDecl = pDecl;
3265 This->updateStateBlock->changed.vertexDecl = TRUE;
3267 if (This->isRecordingState) {
3268 TRACE("Recording... not performing anything\n");
3269 return WINED3D_OK;
3270 } else if(pDecl == oldDecl) {
3271 /* Checked after the assignment to allow proper stateblock recording */
3272 TRACE("Application is setting the old declaration over, nothing to do\n");
3273 return WINED3D_OK;
3276 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3277 return WINED3D_OK;
3280 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3283 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3285 *ppDecl = This->stateBlock->vertexDecl;
3286 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3287 return WINED3D_OK;
3290 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3292 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3294 This->updateStateBlock->vertexShader = pShader;
3295 This->updateStateBlock->changed.vertexShader = TRUE;
3297 if (This->isRecordingState) {
3298 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3299 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3300 TRACE("Recording... not performing anything\n");
3301 return WINED3D_OK;
3302 } else if(oldShader == pShader) {
3303 /* Checked here to allow proper stateblock recording */
3304 TRACE("App is setting the old shader over, nothing to do\n");
3305 return WINED3D_OK;
3308 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3309 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3310 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3312 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3314 return WINED3D_OK;
3317 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3320 if (NULL == ppShader) {
3321 return WINED3DERR_INVALIDCALL;
3323 *ppShader = This->stateBlock->vertexShader;
3324 if( NULL != *ppShader)
3325 IWineD3DVertexShader_AddRef(*ppShader);
3327 TRACE("(%p) : returning %p\n", This, *ppShader);
3328 return WINED3D_OK;
3331 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3332 IWineD3DDevice *iface,
3333 UINT start,
3334 CONST BOOL *srcData,
3335 UINT count) {
3337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3338 int i, cnt = min(count, MAX_CONST_B - start);
3340 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3341 iface, srcData, start, count);
3343 if (srcData == NULL || cnt < 0)
3344 return WINED3DERR_INVALIDCALL;
3346 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3347 for (i = 0; i < cnt; i++)
3348 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3350 for (i = start; i < cnt + start; ++i) {
3351 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3354 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3356 return WINED3D_OK;
3359 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3360 IWineD3DDevice *iface,
3361 UINT start,
3362 BOOL *dstData,
3363 UINT count) {
3365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3366 int cnt = min(count, MAX_CONST_B - start);
3368 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3369 iface, dstData, start, count);
3371 if (dstData == NULL || cnt < 0)
3372 return WINED3DERR_INVALIDCALL;
3374 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3375 return WINED3D_OK;
3378 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3379 IWineD3DDevice *iface,
3380 UINT start,
3381 CONST int *srcData,
3382 UINT count) {
3384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3385 int i, cnt = min(count, MAX_CONST_I - start);
3387 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3388 iface, srcData, start, count);
3390 if (srcData == NULL || cnt < 0)
3391 return WINED3DERR_INVALIDCALL;
3393 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3394 for (i = 0; i < cnt; i++)
3395 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3396 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3398 for (i = start; i < cnt + start; ++i) {
3399 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3402 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3404 return WINED3D_OK;
3407 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3408 IWineD3DDevice *iface,
3409 UINT start,
3410 int *dstData,
3411 UINT count) {
3413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3414 int cnt = min(count, MAX_CONST_I - start);
3416 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3417 iface, dstData, start, count);
3419 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3420 return WINED3DERR_INVALIDCALL;
3422 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3423 return WINED3D_OK;
3426 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3427 IWineD3DDevice *iface,
3428 UINT start,
3429 CONST float *srcData,
3430 UINT count) {
3432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3433 int i;
3435 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3436 iface, srcData, start, count);
3438 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3439 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3440 return WINED3DERR_INVALIDCALL;
3442 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3443 if(TRACE_ON(d3d)) {
3444 for (i = 0; i < count; i++)
3445 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3446 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3449 for (i = start; i < count + start; ++i) {
3450 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3451 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3452 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3453 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3454 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3456 ptr->idx[ptr->count++] = i;
3457 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3461 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3463 return WINED3D_OK;
3466 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3467 IWineD3DDevice *iface,
3468 UINT start,
3469 float *dstData,
3470 UINT count) {
3472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3473 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3475 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3476 iface, dstData, start, count);
3478 if (dstData == NULL || cnt < 0)
3479 return WINED3DERR_INVALIDCALL;
3481 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3482 return WINED3D_OK;
3485 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3486 DWORD i;
3487 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3488 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3492 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3493 int i = This->rev_tex_unit_map[unit];
3494 int j = This->texUnitMap[stage];
3496 This->texUnitMap[stage] = unit;
3497 if (i != -1 && i != stage) {
3498 This->texUnitMap[i] = -1;
3501 This->rev_tex_unit_map[unit] = stage;
3502 if (j != -1 && j != unit) {
3503 This->rev_tex_unit_map[j] = -1;
3507 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3508 int i;
3510 for (i = 0; i < MAX_TEXTURES; ++i) {
3511 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3512 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3513 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3514 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3515 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3516 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3517 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3518 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3520 if (color_op == WINED3DTOP_DISABLE) {
3521 /* Not used, and disable higher stages */
3522 while (i < MAX_TEXTURES) {
3523 This->fixed_function_usage_map[i] = FALSE;
3524 ++i;
3526 break;
3529 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3530 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3531 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3532 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3533 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3534 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3535 This->fixed_function_usage_map[i] = TRUE;
3536 } else {
3537 This->fixed_function_usage_map[i] = FALSE;
3540 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3541 This->fixed_function_usage_map[i+1] = TRUE;
3546 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3547 int i, tex;
3549 device_update_fixed_function_usage_map(This);
3551 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3552 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3553 if (!This->fixed_function_usage_map[i]) continue;
3555 if (This->texUnitMap[i] != i) {
3556 device_map_stage(This, i, i);
3557 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3558 markTextureStagesDirty(This, i);
3561 return;
3564 /* Now work out the mapping */
3565 tex = 0;
3566 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3567 if (!This->fixed_function_usage_map[i]) continue;
3569 if (This->texUnitMap[i] != tex) {
3570 device_map_stage(This, i, tex);
3571 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3572 markTextureStagesDirty(This, i);
3575 ++tex;
3579 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3580 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3581 int i;
3583 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3584 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3585 device_map_stage(This, i, i);
3586 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3587 if (i < MAX_TEXTURES) {
3588 markTextureStagesDirty(This, i);
3594 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3595 int current_mapping = This->rev_tex_unit_map[unit];
3597 if (current_mapping == -1) {
3598 /* Not currently used */
3599 return TRUE;
3602 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3603 /* Used by a fragment sampler */
3605 if (!pshader_sampler_tokens) {
3606 /* No pixel shader, check fixed function */
3607 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3610 /* Pixel shader, check the shader's sampler map */
3611 return !pshader_sampler_tokens[current_mapping];
3614 /* Used by a vertex sampler */
3615 return !vshader_sampler_tokens[current_mapping];
3618 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3619 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3620 DWORD *pshader_sampler_tokens = NULL;
3621 int start = GL_LIMITS(combined_samplers) - 1;
3622 int i;
3624 if (ps) {
3625 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3627 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3628 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3629 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3632 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3633 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3634 if (vshader_sampler_tokens[i]) {
3635 if (This->texUnitMap[vsampler_idx] != -1) {
3636 /* Already mapped somewhere */
3637 continue;
3640 while (start >= 0) {
3641 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3642 device_map_stage(This, vsampler_idx, start);
3643 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3645 --start;
3646 break;
3649 --start;
3655 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3656 BOOL vs = use_vs(This);
3657 BOOL ps = use_ps(This);
3659 * Rules are:
3660 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3661 * that would be really messy and require shader recompilation
3662 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3663 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3665 if (ps) {
3666 device_map_psamplers(This);
3667 } else {
3668 device_map_fixed_function_samplers(This);
3671 if (vs) {
3672 device_map_vsamplers(This, ps);
3676 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3678 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3679 This->updateStateBlock->pixelShader = pShader;
3680 This->updateStateBlock->changed.pixelShader = TRUE;
3682 /* Handle recording of state blocks */
3683 if (This->isRecordingState) {
3684 TRACE("Recording... not performing anything\n");
3687 if (This->isRecordingState) {
3688 TRACE("Recording... not performing anything\n");
3689 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3690 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3691 return WINED3D_OK;
3694 if(pShader == oldShader) {
3695 TRACE("App is setting the old pixel shader over, nothing to do\n");
3696 return WINED3D_OK;
3699 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3700 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3702 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3703 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3705 return WINED3D_OK;
3708 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3711 if (NULL == ppShader) {
3712 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3713 return WINED3DERR_INVALIDCALL;
3716 *ppShader = This->stateBlock->pixelShader;
3717 if (NULL != *ppShader) {
3718 IWineD3DPixelShader_AddRef(*ppShader);
3720 TRACE("(%p) : returning %p\n", This, *ppShader);
3721 return WINED3D_OK;
3724 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3725 IWineD3DDevice *iface,
3726 UINT start,
3727 CONST BOOL *srcData,
3728 UINT count) {
3730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3731 int i, cnt = min(count, MAX_CONST_B - start);
3733 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3734 iface, srcData, start, count);
3736 if (srcData == NULL || cnt < 0)
3737 return WINED3DERR_INVALIDCALL;
3739 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3740 for (i = 0; i < cnt; i++)
3741 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3743 for (i = start; i < cnt + start; ++i) {
3744 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3747 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3749 return WINED3D_OK;
3752 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3753 IWineD3DDevice *iface,
3754 UINT start,
3755 BOOL *dstData,
3756 UINT count) {
3758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3759 int cnt = min(count, MAX_CONST_B - start);
3761 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3762 iface, dstData, start, count);
3764 if (dstData == NULL || cnt < 0)
3765 return WINED3DERR_INVALIDCALL;
3767 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3768 return WINED3D_OK;
3771 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3772 IWineD3DDevice *iface,
3773 UINT start,
3774 CONST int *srcData,
3775 UINT count) {
3777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3778 int i, cnt = min(count, MAX_CONST_I - start);
3780 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3781 iface, srcData, start, count);
3783 if (srcData == NULL || cnt < 0)
3784 return WINED3DERR_INVALIDCALL;
3786 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3787 for (i = 0; i < cnt; i++)
3788 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3789 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3791 for (i = start; i < cnt + start; ++i) {
3792 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3795 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3797 return WINED3D_OK;
3800 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3801 IWineD3DDevice *iface,
3802 UINT start,
3803 int *dstData,
3804 UINT count) {
3806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3807 int cnt = min(count, MAX_CONST_I - start);
3809 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3810 iface, dstData, start, count);
3812 if (dstData == NULL || cnt < 0)
3813 return WINED3DERR_INVALIDCALL;
3815 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3816 return WINED3D_OK;
3819 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3820 IWineD3DDevice *iface,
3821 UINT start,
3822 CONST float *srcData,
3823 UINT count) {
3825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3826 int i;
3828 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3829 iface, srcData, start, count);
3831 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3832 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3833 return WINED3DERR_INVALIDCALL;
3835 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3836 if(TRACE_ON(d3d)) {
3837 for (i = 0; i < count; i++)
3838 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3839 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3842 for (i = start; i < count + start; ++i) {
3843 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3844 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3845 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3846 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3847 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3849 ptr->idx[ptr->count++] = i;
3850 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3854 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3856 return WINED3D_OK;
3859 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3860 IWineD3DDevice *iface,
3861 UINT start,
3862 float *dstData,
3863 UINT count) {
3865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3866 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3868 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3869 iface, dstData, start, count);
3871 if (dstData == NULL || cnt < 0)
3872 return WINED3DERR_INVALIDCALL;
3874 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3875 return WINED3D_OK;
3878 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3879 static HRESULT
3880 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3881 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3882 unsigned int i;
3883 DWORD DestFVF = dest->fvf;
3884 WINED3DVIEWPORT vp;
3885 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3886 BOOL doClip;
3887 int numTextures;
3889 if (lpStrideData->u.s.normal.lpData) {
3890 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3893 if (lpStrideData->u.s.position.lpData == NULL) {
3894 ERR("Source has no position mask\n");
3895 return WINED3DERR_INVALIDCALL;
3898 /* We might access VBOs from this code, so hold the lock */
3899 ENTER_GL();
3901 if (dest->resource.allocatedMemory == NULL) {
3902 /* This may happen if we do direct locking into a vbo. Unlikely,
3903 * but theoretically possible(ddraw processvertices test)
3905 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3906 if(!dest->resource.allocatedMemory) {
3907 LEAVE_GL();
3908 ERR("Out of memory\n");
3909 return E_OUTOFMEMORY;
3911 if(dest->vbo) {
3912 void *src;
3913 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3914 checkGLcall("glBindBufferARB");
3915 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3916 if(src) {
3917 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3919 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3920 checkGLcall("glUnmapBufferARB");
3924 /* Get a pointer into the destination vbo(create one if none exists) and
3925 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3927 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3928 CreateVBO(dest);
3931 if(dest->vbo) {
3932 unsigned char extrabytes = 0;
3933 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3934 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3935 * this may write 4 extra bytes beyond the area that should be written
3937 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3938 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3939 if(!dest_conv_addr) {
3940 ERR("Out of memory\n");
3941 /* Continue without storing converted vertices */
3943 dest_conv = dest_conv_addr;
3946 /* Should I clip?
3947 * a) WINED3DRS_CLIPPING is enabled
3948 * b) WINED3DVOP_CLIP is passed
3950 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3951 static BOOL warned = FALSE;
3953 * The clipping code is not quite correct. Some things need
3954 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3955 * so disable clipping for now.
3956 * (The graphics in Half-Life are broken, and my processvertices
3957 * test crashes with IDirect3DDevice3)
3958 doClip = TRUE;
3960 doClip = FALSE;
3961 if(!warned) {
3962 warned = TRUE;
3963 FIXME("Clipping is broken and disabled for now\n");
3965 } else doClip = FALSE;
3966 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3968 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3969 WINED3DTS_VIEW,
3970 &view_mat);
3971 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3972 WINED3DTS_PROJECTION,
3973 &proj_mat);
3974 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3975 WINED3DTS_WORLDMATRIX(0),
3976 &world_mat);
3978 TRACE("View mat:\n");
3979 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);
3980 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);
3981 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);
3982 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);
3984 TRACE("Proj mat:\n");
3985 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);
3986 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);
3987 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);
3988 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);
3990 TRACE("World mat:\n");
3991 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);
3992 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);
3993 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);
3994 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);
3996 /* Get the viewport */
3997 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3998 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3999 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4001 multiply_matrix(&mat,&view_mat,&world_mat);
4002 multiply_matrix(&mat,&proj_mat,&mat);
4004 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4006 for (i = 0; i < dwCount; i+= 1) {
4007 unsigned int tex_index;
4009 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4010 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4011 /* The position first */
4012 float *p =
4013 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4014 float x, y, z, rhw;
4015 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4017 /* Multiplication with world, view and projection matrix */
4018 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);
4019 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);
4020 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);
4021 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);
4023 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4025 /* WARNING: The following things are taken from d3d7 and were not yet checked
4026 * against d3d8 or d3d9!
4029 /* Clipping conditions: From
4030 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
4032 * A vertex is clipped if it does not match the following requirements
4033 * -rhw < x <= rhw
4034 * -rhw < y <= rhw
4035 * 0 < z <= rhw
4036 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4038 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4039 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4043 if( !doClip ||
4044 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4045 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4046 ( rhw > eps ) ) ) {
4048 /* "Normal" viewport transformation (not clipped)
4049 * 1) The values are divided by rhw
4050 * 2) The y axis is negative, so multiply it with -1
4051 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4052 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4053 * 4) Multiply x with Width/2 and add Width/2
4054 * 5) The same for the height
4055 * 6) Add the viewpoint X and Y to the 2D coordinates and
4056 * The minimum Z value to z
4057 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4059 * Well, basically it's simply a linear transformation into viewport
4060 * coordinates
4063 x /= rhw;
4064 y /= rhw;
4065 z /= rhw;
4067 y *= -1;
4069 x *= vp.Width / 2;
4070 y *= vp.Height / 2;
4071 z *= vp.MaxZ - vp.MinZ;
4073 x += vp.Width / 2 + vp.X;
4074 y += vp.Height / 2 + vp.Y;
4075 z += vp.MinZ;
4077 rhw = 1 / rhw;
4078 } else {
4079 /* That vertex got clipped
4080 * Contrary to OpenGL it is not dropped completely, it just
4081 * undergoes a different calculation.
4083 TRACE("Vertex got clipped\n");
4084 x += rhw;
4085 y += rhw;
4087 x /= 2;
4088 y /= 2;
4090 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4091 * outside of the main vertex buffer memory. That needs some more
4092 * investigation...
4096 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4099 ( (float *) dest_ptr)[0] = x;
4100 ( (float *) dest_ptr)[1] = y;
4101 ( (float *) dest_ptr)[2] = z;
4102 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4104 dest_ptr += 3 * sizeof(float);
4106 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4107 dest_ptr += sizeof(float);
4110 if(dest_conv) {
4111 float w = 1 / rhw;
4112 ( (float *) dest_conv)[0] = x * w;
4113 ( (float *) dest_conv)[1] = y * w;
4114 ( (float *) dest_conv)[2] = z * w;
4115 ( (float *) dest_conv)[3] = w;
4117 dest_conv += 3 * sizeof(float);
4119 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4120 dest_conv += sizeof(float);
4124 if (DestFVF & WINED3DFVF_PSIZE) {
4125 dest_ptr += sizeof(DWORD);
4126 if(dest_conv) dest_conv += sizeof(DWORD);
4128 if (DestFVF & WINED3DFVF_NORMAL) {
4129 float *normal =
4130 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4131 /* AFAIK this should go into the lighting information */
4132 FIXME("Didn't expect the destination to have a normal\n");
4133 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4134 if(dest_conv) {
4135 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4139 if (DestFVF & WINED3DFVF_DIFFUSE) {
4140 DWORD *color_d =
4141 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4142 if(!color_d) {
4143 static BOOL warned = FALSE;
4145 if(!warned) {
4146 ERR("No diffuse color in source, but destination has one\n");
4147 warned = TRUE;
4150 *( (DWORD *) dest_ptr) = 0xffffffff;
4151 dest_ptr += sizeof(DWORD);
4153 if(dest_conv) {
4154 *( (DWORD *) dest_conv) = 0xffffffff;
4155 dest_conv += sizeof(DWORD);
4158 else {
4159 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4160 if(dest_conv) {
4161 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4162 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4163 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4164 dest_conv += sizeof(DWORD);
4169 if (DestFVF & WINED3DFVF_SPECULAR) {
4170 /* What's the color value in the feedback buffer? */
4171 DWORD *color_s =
4172 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4173 if(!color_s) {
4174 static BOOL warned = FALSE;
4176 if(!warned) {
4177 ERR("No specular color in source, but destination has one\n");
4178 warned = TRUE;
4181 *( (DWORD *) dest_ptr) = 0xFF000000;
4182 dest_ptr += sizeof(DWORD);
4184 if(dest_conv) {
4185 *( (DWORD *) dest_conv) = 0xFF000000;
4186 dest_conv += sizeof(DWORD);
4189 else {
4190 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4191 if(dest_conv) {
4192 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4193 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4194 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4195 dest_conv += sizeof(DWORD);
4200 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4201 float *tex_coord =
4202 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4203 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4204 if(!tex_coord) {
4205 ERR("No source texture, but destination requests one\n");
4206 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4207 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4209 else {
4210 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4211 if(dest_conv) {
4212 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4218 if(dest_conv) {
4219 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4220 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4221 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4222 dwCount * get_flexible_vertex_size(DestFVF),
4223 dest_conv_addr));
4224 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4225 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4228 LEAVE_GL();
4230 return WINED3D_OK;
4232 #undef copy_and_next
4234 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4236 WineDirect3DVertexStridedData strided;
4237 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4238 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4240 if(pVertexDecl) {
4241 ERR("Output vertex declaration not implemented yet\n");
4244 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
4245 * and this call is quite performance critical, so don't call needlessly
4247 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4248 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4251 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4252 * control the streamIsUP flag, thus restore it afterwards.
4254 This->stateBlock->streamIsUP = FALSE;
4255 memset(&strided, 0, sizeof(strided));
4256 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4257 This->stateBlock->streamIsUP = streamWasUP;
4259 if(vbo || SrcStartIndex) {
4260 unsigned int i;
4261 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4262 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4264 * Also get the start index in, but only loop over all elements if there's something to add at all.
4266 #define FIXSRC(type) \
4267 if(strided.u.s.type.VBO) { \
4268 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4269 strided.u.s.type.VBO = 0; \
4270 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4271 ENTER_GL(); \
4272 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4273 vb->vbo = 0; \
4274 LEAVE_GL(); \
4276 if(strided.u.s.type.lpData) { \
4277 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4279 FIXSRC(position);
4280 FIXSRC(blendWeights);
4281 FIXSRC(blendMatrixIndices);
4282 FIXSRC(normal);
4283 FIXSRC(pSize);
4284 FIXSRC(diffuse);
4285 FIXSRC(specular);
4286 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4287 FIXSRC(texCoords[i]);
4289 FIXSRC(position2);
4290 FIXSRC(normal2);
4291 FIXSRC(tangent);
4292 FIXSRC(binormal);
4293 FIXSRC(tessFactor);
4294 FIXSRC(fog);
4295 FIXSRC(depth);
4296 FIXSRC(sample);
4297 #undef FIXSRC
4300 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4303 /*****
4304 * Get / Set Texture Stage States
4305 * TODO: Verify against dx9 definitions
4306 *****/
4307 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4309 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4311 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4313 if (Stage >= MAX_TEXTURES) {
4314 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4315 return WINED3D_OK;
4318 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4319 This->updateStateBlock->textureState[Stage][Type] = Value;
4321 if (This->isRecordingState) {
4322 TRACE("Recording... not performing anything\n");
4323 return WINED3D_OK;
4326 /* Checked after the assignments to allow proper stateblock recording */
4327 if(oldValue == Value) {
4328 TRACE("App is setting the old value over, nothing to do\n");
4329 return WINED3D_OK;
4332 if(Stage > This->stateBlock->lowest_disabled_stage &&
4333 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4334 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4335 * Changes in other states are important on disabled stages too
4337 return WINED3D_OK;
4340 if(Type == WINED3DTSS_COLOROP) {
4341 int i;
4343 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4344 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4345 * they have to be disabled
4347 * The current stage is dirtified below.
4349 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4350 TRACE("Additionally dirtifying stage %d\n", i);
4351 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4353 This->stateBlock->lowest_disabled_stage = Stage;
4354 TRACE("New lowest disabled: %d\n", Stage);
4355 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4356 /* Previously disabled stage enabled. Stages above it may need enabling
4357 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4358 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4360 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4363 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4364 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4365 break;
4367 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4368 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4370 This->stateBlock->lowest_disabled_stage = i;
4371 TRACE("New lowest disabled: %d\n", i);
4373 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4374 /* TODO: Built a stage -> texture unit mapping for register combiners */
4378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4380 return WINED3D_OK;
4383 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4385 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4386 *pValue = This->updateStateBlock->textureState[Stage][Type];
4387 return WINED3D_OK;
4390 /*****
4391 * Get / Set Texture
4392 *****/
4393 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4395 IWineD3DBaseTexture *oldTexture;
4397 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4399 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4400 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4403 oldTexture = This->updateStateBlock->textures[Stage];
4405 if(pTexture != NULL) {
4406 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4408 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4409 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4410 return WINED3DERR_INVALIDCALL;
4412 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4415 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4416 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4418 This->updateStateBlock->changed.textures[Stage] = TRUE;
4419 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4420 This->updateStateBlock->textures[Stage] = pTexture;
4422 /* Handle recording of state blocks */
4423 if (This->isRecordingState) {
4424 TRACE("Recording... not performing anything\n");
4425 return WINED3D_OK;
4428 if(oldTexture == pTexture) {
4429 TRACE("App is setting the same texture again, nothing to do\n");
4430 return WINED3D_OK;
4433 /** NOTE: MSDN says that setTexture increases the reference count,
4434 * and that the application must set the texture back to null (or have a leaky application),
4435 * This means we should pass the refcount up to the parent
4436 *******************************/
4437 if (NULL != This->updateStateBlock->textures[Stage]) {
4438 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4439 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4441 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4442 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4443 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4444 * so the COLOROP and ALPHAOP have to be dirtified.
4446 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4447 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4449 if(bindCount == 1) {
4450 new->baseTexture.sampler = Stage;
4452 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4456 if (NULL != oldTexture) {
4457 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4458 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4460 IWineD3DBaseTexture_Release(oldTexture);
4461 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4462 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4463 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4466 if(bindCount && old->baseTexture.sampler == Stage) {
4467 int i;
4468 /* Have to do a search for the other sampler(s) where the texture is bound to
4469 * Shouldn't happen as long as apps bind a texture only to one stage
4471 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4472 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4473 if(This->updateStateBlock->textures[i] == oldTexture) {
4474 old->baseTexture.sampler = i;
4475 break;
4481 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4483 return WINED3D_OK;
4486 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4489 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4491 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4492 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4495 *ppTexture=This->stateBlock->textures[Stage];
4496 if (*ppTexture)
4497 IWineD3DBaseTexture_AddRef(*ppTexture);
4499 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4501 return WINED3D_OK;
4504 /*****
4505 * Get Back Buffer
4506 *****/
4507 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4508 IWineD3DSurface **ppBackBuffer) {
4509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4510 IWineD3DSwapChain *swapChain;
4511 HRESULT hr;
4513 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4515 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4516 if (hr == WINED3D_OK) {
4517 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4518 IWineD3DSwapChain_Release(swapChain);
4519 } else {
4520 *ppBackBuffer = NULL;
4522 return hr;
4525 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4527 WARN("(%p) : stub, calling idirect3d for now\n", This);
4528 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4531 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4533 IWineD3DSwapChain *swapChain;
4534 HRESULT hr;
4536 if(iSwapChain > 0) {
4537 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4538 if (hr == WINED3D_OK) {
4539 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4540 IWineD3DSwapChain_Release(swapChain);
4541 } else {
4542 FIXME("(%p) Error getting display mode\n", This);
4544 } else {
4545 /* Don't read the real display mode,
4546 but return the stored mode instead. X11 can't change the color
4547 depth, and some apps are pretty angry if they SetDisplayMode from
4548 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4550 Also don't relay to the swapchain because with ddraw it's possible
4551 that there isn't a swapchain at all */
4552 pMode->Width = This->ddraw_width;
4553 pMode->Height = This->ddraw_height;
4554 pMode->Format = This->ddraw_format;
4555 pMode->RefreshRate = 0;
4556 hr = WINED3D_OK;
4559 return hr;
4562 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4564 TRACE("(%p)->(%p)\n", This, hWnd);
4566 if(This->ddraw_fullscreen) {
4567 if(This->ddraw_window && This->ddraw_window != hWnd) {
4568 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4570 if(hWnd && This->ddraw_window != hWnd) {
4571 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4575 This->ddraw_window = hWnd;
4576 return WINED3D_OK;
4579 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4581 TRACE("(%p)->(%p)\n", This, hWnd);
4583 *hWnd = This->ddraw_window;
4584 return WINED3D_OK;
4587 /*****
4588 * Stateblock related functions
4589 *****/
4591 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4593 IWineD3DStateBlockImpl *object;
4594 HRESULT temp_result;
4595 int i;
4597 TRACE("(%p)\n", This);
4599 if (This->isRecordingState) {
4600 return WINED3DERR_INVALIDCALL;
4603 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4604 if (NULL == object ) {
4605 FIXME("(%p)Error allocating memory for stateblock\n", This);
4606 return E_OUTOFMEMORY;
4608 TRACE("(%p) created object %p\n", This, object);
4609 object->wineD3DDevice= This;
4610 /** FIXME: object->parent = parent; **/
4611 object->parent = NULL;
4612 object->blockType = WINED3DSBT_RECORDED;
4613 object->ref = 1;
4614 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4616 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4617 list_init(&object->lightMap[i]);
4620 temp_result = allocate_shader_constants(object);
4621 if (WINED3D_OK != temp_result)
4622 return temp_result;
4624 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4625 This->updateStateBlock = object;
4626 This->isRecordingState = TRUE;
4628 TRACE("(%p) recording stateblock %p\n",This , object);
4629 return WINED3D_OK;
4632 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4634 unsigned int i, j;
4635 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4637 if (!This->isRecordingState) {
4638 FIXME("(%p) not recording! returning error\n", This);
4639 *ppStateBlock = NULL;
4640 return WINED3DERR_INVALIDCALL;
4643 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4644 if(object->changed.renderState[i]) {
4645 object->contained_render_states[object->num_contained_render_states] = i;
4646 object->num_contained_render_states++;
4649 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4650 if(object->changed.transform[i]) {
4651 object->contained_transform_states[object->num_contained_transform_states] = i;
4652 object->num_contained_transform_states++;
4655 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4656 if(object->changed.vertexShaderConstantsF[i]) {
4657 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4658 object->num_contained_vs_consts_f++;
4661 for(i = 0; i < MAX_CONST_I; i++) {
4662 if(object->changed.vertexShaderConstantsI[i]) {
4663 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4664 object->num_contained_vs_consts_i++;
4667 for(i = 0; i < MAX_CONST_B; i++) {
4668 if(object->changed.vertexShaderConstantsB[i]) {
4669 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4670 object->num_contained_vs_consts_b++;
4673 for(i = 0; i < MAX_CONST_I; i++) {
4674 if(object->changed.pixelShaderConstantsI[i]) {
4675 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4676 object->num_contained_ps_consts_i++;
4679 for(i = 0; i < MAX_CONST_B; i++) {
4680 if(object->changed.pixelShaderConstantsB[i]) {
4681 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4682 object->num_contained_ps_consts_b++;
4685 for(i = 0; i < MAX_TEXTURES; i++) {
4686 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4687 if(object->changed.textureState[i][j]) {
4688 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4689 object->contained_tss_states[object->num_contained_tss_states].state = j;
4690 object->num_contained_tss_states++;
4694 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4695 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4696 if(object->changed.samplerState[i][j]) {
4697 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4698 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4699 object->num_contained_sampler_states++;
4704 *ppStateBlock = (IWineD3DStateBlock*) object;
4705 This->isRecordingState = FALSE;
4706 This->updateStateBlock = This->stateBlock;
4707 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4708 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4709 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4710 return WINED3D_OK;
4713 /*****
4714 * Scene related functions
4715 *****/
4716 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4717 /* At the moment we have no need for any functionality at the beginning
4718 of a scene */
4719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4720 TRACE("(%p)\n", This);
4722 if(This->inScene) {
4723 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4724 return WINED3DERR_INVALIDCALL;
4726 This->inScene = TRUE;
4727 return WINED3D_OK;
4730 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4732 TRACE("(%p)\n", This);
4734 if(!This->inScene) {
4735 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4736 return WINED3DERR_INVALIDCALL;
4739 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4740 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4742 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4743 ENTER_GL();
4744 glFlush();
4745 checkGLcall("glFlush");
4746 LEAVE_GL();
4748 This->inScene = FALSE;
4749 return WINED3D_OK;
4752 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4753 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4754 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4756 IWineD3DSwapChain *swapChain = NULL;
4757 int i;
4758 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4760 TRACE("(%p) Presenting the frame\n", This);
4762 for(i = 0 ; i < swapchains ; i ++) {
4764 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4765 TRACE("presentinng chain %d, %p\n", i, swapChain);
4766 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4767 IWineD3DSwapChain_Release(swapChain);
4770 return WINED3D_OK;
4773 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4774 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4776 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4778 GLbitfield glMask = 0;
4779 unsigned int i;
4780 CONST WINED3DRECT* curRect;
4782 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4783 Count, pRects, Flags, Color, Z, Stencil);
4785 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4786 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4787 /* TODO: What about depth stencil buffers without stencil bits? */
4788 return WINED3DERR_INVALIDCALL;
4791 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4792 * and not the last active one.
4794 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4795 ENTER_GL();
4797 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4798 apply_fbo_state(iface);
4801 if (Count > 0 && pRects) {
4802 curRect = pRects;
4803 } else {
4804 curRect = NULL;
4807 /* Only set the values up once, as they are not changing */
4808 if (Flags & WINED3DCLEAR_STENCIL) {
4809 glClearStencil(Stencil);
4810 checkGLcall("glClearStencil");
4811 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4812 glStencilMask(0xFFFFFFFF);
4815 if (Flags & WINED3DCLEAR_ZBUFFER) {
4816 glDepthMask(GL_TRUE);
4817 glClearDepth(Z);
4818 checkGLcall("glClearDepth");
4819 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4820 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4823 if (Flags & WINED3DCLEAR_TARGET) {
4824 TRACE("Clearing screen with glClear to color %x\n", Color);
4825 glClearColor(D3DCOLOR_R(Color),
4826 D3DCOLOR_G(Color),
4827 D3DCOLOR_B(Color),
4828 D3DCOLOR_A(Color));
4829 checkGLcall("glClearColor");
4831 /* Clear ALL colors! */
4832 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4833 glMask = glMask | GL_COLOR_BUFFER_BIT;
4836 if (!curRect) {
4837 /* In drawable flag is set below */
4839 if (This->render_offscreen) {
4840 glScissor(This->stateBlock->viewport.X,
4841 This->stateBlock->viewport.Y,
4842 This->stateBlock->viewport.Width,
4843 This->stateBlock->viewport.Height);
4844 } else {
4845 glScissor(This->stateBlock->viewport.X,
4846 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4847 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4848 This->stateBlock->viewport.Width,
4849 This->stateBlock->viewport.Height);
4851 checkGLcall("glScissor");
4852 glClear(glMask);
4853 checkGLcall("glClear");
4854 } else {
4855 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4856 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4858 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4859 curRect[0].x2 < target->currentDesc.Width ||
4860 curRect[0].y2 < target->currentDesc.Height) {
4861 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4862 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4866 /* Now process each rect in turn */
4867 for (i = 0; i < Count; i++) {
4868 /* Note gl uses lower left, width/height */
4869 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4870 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4871 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4872 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4874 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4875 * The rectangle is not cleared, no error is returned, but further rectanlges are
4876 * still cleared if they are valid
4878 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4879 TRACE("Rectangle with negative dimensions, ignoring\n");
4880 continue;
4883 if(This->render_offscreen) {
4884 glScissor(curRect[i].x1, curRect[i].y1,
4885 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4886 } else {
4887 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4888 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4890 checkGLcall("glScissor");
4892 glClear(glMask);
4893 checkGLcall("glClear");
4897 /* Restore the old values (why..?) */
4898 if (Flags & WINED3DCLEAR_STENCIL) {
4899 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4901 if (Flags & WINED3DCLEAR_TARGET) {
4902 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4903 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4904 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4905 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4906 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4909 LEAVE_GL();
4911 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4912 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4914 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
4915 /* TODO: Move the fbo logic into ModifyLocation() */
4916 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4917 target->Flags |= SFLAG_INTEXTURE;
4919 return WINED3D_OK;
4922 /*****
4923 * Drawing functions
4924 *****/
4925 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4926 UINT PrimitiveCount) {
4928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4930 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4931 debug_d3dprimitivetype(PrimitiveType),
4932 StartVertex, PrimitiveCount);
4934 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4935 if(This->stateBlock->streamIsUP) {
4936 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4937 This->stateBlock->streamIsUP = FALSE;
4940 if(This->stateBlock->loadBaseVertexIndex != 0) {
4941 This->stateBlock->loadBaseVertexIndex = 0;
4942 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4944 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4945 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4946 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4947 return WINED3D_OK;
4950 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4951 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4952 WINED3DPRIMITIVETYPE PrimitiveType,
4953 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4956 UINT idxStride = 2;
4957 IWineD3DIndexBuffer *pIB;
4958 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4959 GLuint vbo;
4961 pIB = This->stateBlock->pIndexData;
4962 if (!pIB) {
4963 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4964 * without an index buffer set. (The first time at least...)
4965 * D3D8 simply dies, but I doubt it can do much harm to return
4966 * D3DERR_INVALIDCALL there as well. */
4967 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4968 return WINED3DERR_INVALIDCALL;
4971 if(This->stateBlock->streamIsUP) {
4972 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4973 This->stateBlock->streamIsUP = FALSE;
4975 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4977 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4978 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4979 minIndex, NumVertices, startIndex, primCount);
4981 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4982 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4983 idxStride = 2;
4984 } else {
4985 idxStride = 4;
4988 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4989 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4990 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4993 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4994 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4996 return WINED3D_OK;
4999 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5000 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5001 UINT VertexStreamZeroStride) {
5002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5003 IWineD3DVertexBuffer *vb;
5005 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5006 debug_d3dprimitivetype(PrimitiveType),
5007 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5009 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5010 vb = This->stateBlock->streamSource[0];
5011 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5012 if(vb) IWineD3DVertexBuffer_Release(vb);
5013 This->stateBlock->streamOffset[0] = 0;
5014 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5015 This->stateBlock->streamIsUP = TRUE;
5016 This->stateBlock->loadBaseVertexIndex = 0;
5018 /* TODO: Only mark dirty if drawing from a different UP address */
5019 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5021 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5022 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5024 /* MSDN specifies stream zero settings must be set to NULL */
5025 This->stateBlock->streamStride[0] = 0;
5026 This->stateBlock->streamSource[0] = NULL;
5028 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5029 * the new stream sources or use UP drawing again
5031 return WINED3D_OK;
5034 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5035 UINT MinVertexIndex, UINT NumVertices,
5036 UINT PrimitiveCount, CONST void* pIndexData,
5037 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5038 UINT VertexStreamZeroStride) {
5039 int idxStride;
5040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5041 IWineD3DVertexBuffer *vb;
5042 IWineD3DIndexBuffer *ib;
5044 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5045 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5046 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5047 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5049 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5050 idxStride = 2;
5051 } else {
5052 idxStride = 4;
5055 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5056 vb = This->stateBlock->streamSource[0];
5057 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5058 if(vb) IWineD3DVertexBuffer_Release(vb);
5059 This->stateBlock->streamIsUP = TRUE;
5060 This->stateBlock->streamOffset[0] = 0;
5061 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5063 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5064 This->stateBlock->baseVertexIndex = 0;
5065 This->stateBlock->loadBaseVertexIndex = 0;
5066 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5067 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5068 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5070 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5072 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5073 This->stateBlock->streamSource[0] = NULL;
5074 This->stateBlock->streamStride[0] = 0;
5075 ib = This->stateBlock->pIndexData;
5076 if(ib) {
5077 IWineD3DIndexBuffer_Release(ib);
5078 This->stateBlock->pIndexData = NULL;
5080 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5081 * SetStreamSource to specify a vertex buffer
5084 return WINED3D_OK;
5087 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5090 /* Mark the state dirty until we have nicer tracking
5091 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5092 * that value.
5094 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5095 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5096 This->stateBlock->baseVertexIndex = 0;
5097 This->up_strided = DrawPrimStrideData;
5098 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5099 This->up_strided = NULL;
5100 return WINED3D_OK;
5103 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5105 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5107 /* Mark the state dirty until we have nicer tracking
5108 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5109 * that value.
5111 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5112 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5113 This->stateBlock->streamIsUP = TRUE;
5114 This->stateBlock->baseVertexIndex = 0;
5115 This->up_strided = DrawPrimStrideData;
5116 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5117 This->up_strided = NULL;
5118 return WINED3D_OK;
5121 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5122 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5123 * not callable by the app directly no parameter validation checks are needed here.
5125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5126 WINED3DLOCKED_BOX src;
5127 WINED3DLOCKED_BOX dst;
5128 HRESULT hr;
5129 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5131 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5132 * dirtification to improve loading performance.
5134 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5135 if(FAILED(hr)) return hr;
5136 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5137 if(FAILED(hr)) {
5138 IWineD3DVolume_UnlockBox(pSourceVolume);
5139 return hr;
5142 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5144 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5145 if(FAILED(hr)) {
5146 IWineD3DVolume_UnlockBox(pSourceVolume);
5147 } else {
5148 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5150 return hr;
5153 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5154 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5156 HRESULT hr = WINED3D_OK;
5157 WINED3DRESOURCETYPE sourceType;
5158 WINED3DRESOURCETYPE destinationType;
5159 int i ,levels;
5161 /* TODO: think about moving the code into IWineD3DBaseTexture */
5163 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5165 /* verify that the source and destination textures aren't NULL */
5166 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5167 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5168 This, pSourceTexture, pDestinationTexture);
5169 hr = WINED3DERR_INVALIDCALL;
5172 if (pSourceTexture == pDestinationTexture) {
5173 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5174 This, pSourceTexture, pDestinationTexture);
5175 hr = WINED3DERR_INVALIDCALL;
5177 /* Verify that the source and destination textures are the same type */
5178 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5179 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5181 if (sourceType != destinationType) {
5182 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5183 This);
5184 hr = WINED3DERR_INVALIDCALL;
5187 /* check that both textures have the identical numbers of levels */
5188 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5189 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5190 hr = WINED3DERR_INVALIDCALL;
5193 if (WINED3D_OK == hr) {
5195 /* Make sure that the destination texture is loaded */
5196 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5198 /* Update every surface level of the texture */
5199 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5201 switch (sourceType) {
5202 case WINED3DRTYPE_TEXTURE:
5204 IWineD3DSurface *srcSurface;
5205 IWineD3DSurface *destSurface;
5207 for (i = 0 ; i < levels ; ++i) {
5208 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5209 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5210 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5211 IWineD3DSurface_Release(srcSurface);
5212 IWineD3DSurface_Release(destSurface);
5213 if (WINED3D_OK != hr) {
5214 WARN("(%p) : Call to update surface failed\n", This);
5215 return hr;
5219 break;
5220 case WINED3DRTYPE_CUBETEXTURE:
5222 IWineD3DSurface *srcSurface;
5223 IWineD3DSurface *destSurface;
5224 WINED3DCUBEMAP_FACES faceType;
5226 for (i = 0 ; i < levels ; ++i) {
5227 /* Update each cube face */
5228 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5229 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5230 if (WINED3D_OK != hr) {
5231 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5232 } else {
5233 TRACE("Got srcSurface %p\n", srcSurface);
5235 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5236 if (WINED3D_OK != hr) {
5237 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5238 } else {
5239 TRACE("Got desrSurface %p\n", destSurface);
5241 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5242 IWineD3DSurface_Release(srcSurface);
5243 IWineD3DSurface_Release(destSurface);
5244 if (WINED3D_OK != hr) {
5245 WARN("(%p) : Call to update surface failed\n", This);
5246 return hr;
5251 break;
5253 case WINED3DRTYPE_VOLUMETEXTURE:
5255 IWineD3DVolume *srcVolume = NULL;
5256 IWineD3DVolume *destVolume = NULL;
5258 for (i = 0 ; i < levels ; ++i) {
5259 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5260 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5261 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5262 IWineD3DVolume_Release(srcVolume);
5263 IWineD3DVolume_Release(destVolume);
5264 if (WINED3D_OK != hr) {
5265 WARN("(%p) : Call to update volume failed\n", This);
5266 return hr;
5270 break;
5272 default:
5273 FIXME("(%p) : Unsupported source and destination type\n", This);
5274 hr = WINED3DERR_INVALIDCALL;
5278 return hr;
5281 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5282 IWineD3DSwapChain *swapChain;
5283 HRESULT hr;
5284 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5285 if(hr == WINED3D_OK) {
5286 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5287 IWineD3DSwapChain_Release(swapChain);
5289 return hr;
5292 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5294 /* return a sensible default */
5295 *pNumPasses = 1;
5296 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5297 FIXME("(%p) : stub\n", This);
5298 return WINED3D_OK;
5301 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5303 int j;
5304 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5305 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5306 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5307 return WINED3DERR_INVALIDCALL;
5309 for (j = 0; j < 256; ++j) {
5310 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5311 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5312 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5313 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5315 TRACE("(%p) : returning\n", This);
5316 return WINED3D_OK;
5319 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5321 int j;
5322 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5323 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5324 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5325 return WINED3DERR_INVALIDCALL;
5327 for (j = 0; j < 256; ++j) {
5328 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5329 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5330 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5331 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5333 TRACE("(%p) : returning\n", This);
5334 return WINED3D_OK;
5337 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5339 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5340 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5341 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5342 return WINED3DERR_INVALIDCALL;
5344 /*TODO: stateblocks */
5345 This->currentPalette = PaletteNumber;
5346 TRACE("(%p) : returning\n", This);
5347 return WINED3D_OK;
5350 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5352 if (PaletteNumber == NULL) {
5353 WARN("(%p) : returning Invalid Call\n", This);
5354 return WINED3DERR_INVALIDCALL;
5356 /*TODO: stateblocks */
5357 *PaletteNumber = This->currentPalette;
5358 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5359 return WINED3D_OK;
5362 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5364 static BOOL showFixmes = TRUE;
5365 if (showFixmes) {
5366 FIXME("(%p) : stub\n", This);
5367 showFixmes = FALSE;
5370 This->softwareVertexProcessing = bSoftware;
5371 return WINED3D_OK;
5375 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5377 static BOOL showFixmes = TRUE;
5378 if (showFixmes) {
5379 FIXME("(%p) : stub\n", This);
5380 showFixmes = FALSE;
5382 return This->softwareVertexProcessing;
5386 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5388 IWineD3DSwapChain *swapChain;
5389 HRESULT hr;
5391 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5393 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5394 if(hr == WINED3D_OK){
5395 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5396 IWineD3DSwapChain_Release(swapChain);
5397 }else{
5398 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5400 return hr;
5404 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5406 static BOOL showfixmes = TRUE;
5407 if(nSegments != 0.0f) {
5408 if( showfixmes) {
5409 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5410 showfixmes = FALSE;
5413 return WINED3D_OK;
5416 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5418 static BOOL showfixmes = TRUE;
5419 if( showfixmes) {
5420 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5421 showfixmes = FALSE;
5423 return 0.0f;
5426 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5428 /** TODO: remove casts to IWineD3DSurfaceImpl
5429 * NOTE: move code to surface to accomplish this
5430 ****************************************/
5431 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5432 int srcWidth, srcHeight;
5433 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5434 WINED3DFORMAT destFormat, srcFormat;
5435 UINT destSize;
5436 int srcLeft, destLeft, destTop;
5437 WINED3DPOOL srcPool, destPool;
5438 int offset = 0;
5439 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5440 glDescriptor *glDescription = NULL;
5441 GLenum dummy;
5442 int bpp;
5443 CONVERT_TYPES convert = NO_CONVERSION;
5445 WINED3DSURFACE_DESC winedesc;
5447 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5448 memset(&winedesc, 0, sizeof(winedesc));
5449 winedesc.Width = &srcSurfaceWidth;
5450 winedesc.Height = &srcSurfaceHeight;
5451 winedesc.Pool = &srcPool;
5452 winedesc.Format = &srcFormat;
5454 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5456 winedesc.Width = &destSurfaceWidth;
5457 winedesc.Height = &destSurfaceHeight;
5458 winedesc.Pool = &destPool;
5459 winedesc.Format = &destFormat;
5460 winedesc.Size = &destSize;
5462 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5464 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5465 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5466 return WINED3DERR_INVALIDCALL;
5469 /* This call loads the opengl surface directly, instead of copying the surface to the
5470 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5471 * copy in sysmem and use regular surface loading.
5473 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5474 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5475 if(convert != NO_CONVERSION) {
5476 return IWineD3DSurface_BltFast(pDestinationSurface,
5477 pDestPoint ? pDestPoint->x : 0,
5478 pDestPoint ? pDestPoint->y : 0,
5479 pSourceSurface, (RECT *) pSourceRect, 0);
5482 if (destFormat == WINED3DFMT_UNKNOWN) {
5483 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5484 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5486 /* Get the update surface description */
5487 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5490 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5492 ENTER_GL();
5494 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5495 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5496 checkGLcall("glActiveTextureARB");
5499 /* Make sure the surface is loaded and up to date */
5500 IWineD3DSurface_PreLoad(pDestinationSurface);
5502 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5504 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5505 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5506 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5507 srcLeft = pSourceRect ? pSourceRect->left : 0;
5508 destLeft = pDestPoint ? pDestPoint->x : 0;
5509 destTop = pDestPoint ? pDestPoint->y : 0;
5512 /* This function doesn't support compressed textures
5513 the pitch is just bytesPerPixel * width */
5514 if(srcWidth != srcSurfaceWidth || srcLeft ){
5515 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5516 offset += srcLeft * pSrcSurface->bytesPerPixel;
5517 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5519 /* TODO DXT formats */
5521 if(pSourceRect != NULL && pSourceRect->top != 0){
5522 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5524 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5525 ,This
5526 ,glDescription->level
5527 ,destLeft
5528 ,destTop
5529 ,srcWidth
5530 ,srcHeight
5531 ,glDescription->glFormat
5532 ,glDescription->glType
5533 ,IWineD3DSurface_GetData(pSourceSurface)
5536 /* Sanity check */
5537 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5539 /* need to lock the surface to get the data */
5540 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5543 /* TODO: Cube and volume support */
5544 if(rowoffset != 0){
5545 /* not a whole row so we have to do it a line at a time */
5546 int j;
5548 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5549 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5551 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5553 glTexSubImage2D(glDescription->target
5554 ,glDescription->level
5555 ,destLeft
5557 ,srcWidth
5559 ,glDescription->glFormat
5560 ,glDescription->glType
5561 ,data /* could be quicker using */
5563 data += rowoffset;
5566 } else { /* Full width, so just write out the whole texture */
5568 if (WINED3DFMT_DXT1 == destFormat ||
5569 WINED3DFMT_DXT2 == destFormat ||
5570 WINED3DFMT_DXT3 == destFormat ||
5571 WINED3DFMT_DXT4 == destFormat ||
5572 WINED3DFMT_DXT5 == destFormat) {
5573 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5574 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5575 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5576 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5577 } if (destFormat != srcFormat) {
5578 FIXME("Updating mixed format compressed texture is not curretly support\n");
5579 } else {
5580 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5581 glDescription->level,
5582 glDescription->glFormatInternal,
5583 srcWidth,
5584 srcHeight,
5586 destSize,
5587 IWineD3DSurface_GetData(pSourceSurface));
5589 } else {
5590 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5594 } else {
5595 glTexSubImage2D(glDescription->target
5596 ,glDescription->level
5597 ,destLeft
5598 ,destTop
5599 ,srcWidth
5600 ,srcHeight
5601 ,glDescription->glFormat
5602 ,glDescription->glType
5603 ,IWineD3DSurface_GetData(pSourceSurface)
5607 checkGLcall("glTexSubImage2D");
5609 LEAVE_GL();
5611 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5612 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5614 return WINED3D_OK;
5617 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5619 struct WineD3DRectPatch *patch;
5620 unsigned int i;
5621 struct list *e;
5622 BOOL found;
5623 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5625 if(!(Handle || pRectPatchInfo)) {
5626 /* TODO: Write a test for the return value, thus the FIXME */
5627 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5628 return WINED3DERR_INVALIDCALL;
5631 if(Handle) {
5632 i = PATCHMAP_HASHFUNC(Handle);
5633 found = FALSE;
5634 LIST_FOR_EACH(e, &This->patches[i]) {
5635 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5636 if(patch->Handle == Handle) {
5637 found = TRUE;
5638 break;
5642 if(!found) {
5643 TRACE("Patch does not exist. Creating a new one\n");
5644 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5645 patch->Handle = Handle;
5646 list_add_head(&This->patches[i], &patch->entry);
5647 } else {
5648 TRACE("Found existing patch %p\n", patch);
5650 } else {
5651 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5652 * attributes we have to tesselate, read back, and draw. This needs a patch
5653 * management structure instance. Create one.
5655 * A possible improvement is to check if a vertex shader is used, and if not directly
5656 * draw the patch.
5658 FIXME("Drawing an uncached patch. This is slow\n");
5659 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5662 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5663 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5664 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5665 HRESULT hr;
5666 TRACE("Tesselation density or patch info changed, retesselating\n");
5668 if(pRectPatchInfo) {
5669 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5671 patch->numSegs[0] = pNumSegs[0];
5672 patch->numSegs[1] = pNumSegs[1];
5673 patch->numSegs[2] = pNumSegs[2];
5674 patch->numSegs[3] = pNumSegs[3];
5676 hr = tesselate_rectpatch(This, patch);
5677 if(FAILED(hr)) {
5678 WARN("Patch tesselation failed\n");
5680 /* Do not release the handle to store the params of the patch */
5681 if(!Handle) {
5682 HeapFree(GetProcessHeap(), 0, patch);
5684 return hr;
5688 This->currentPatch = patch;
5689 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5690 This->currentPatch = NULL;
5692 /* Destroy uncached patches */
5693 if(!Handle) {
5694 HeapFree(GetProcessHeap(), 0, patch->mem);
5695 HeapFree(GetProcessHeap(), 0, patch);
5697 return WINED3D_OK;
5700 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5701 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5703 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5704 FIXME("(%p) : Stub\n", This);
5705 return WINED3D_OK;
5708 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5710 int i;
5711 struct WineD3DRectPatch *patch;
5712 struct list *e;
5713 TRACE("(%p) Handle(%d)\n", This, Handle);
5715 i = PATCHMAP_HASHFUNC(Handle);
5716 LIST_FOR_EACH(e, &This->patches[i]) {
5717 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5718 if(patch->Handle == Handle) {
5719 TRACE("Deleting patch %p\n", patch);
5720 list_remove(&patch->entry);
5721 HeapFree(GetProcessHeap(), 0, patch->mem);
5722 HeapFree(GetProcessHeap(), 0, patch);
5723 return WINED3D_OK;
5727 /* TODO: Write a test for the return value */
5728 FIXME("Attempt to destroy nonexistant patch\n");
5729 return WINED3DERR_INVALIDCALL;
5732 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5733 HRESULT hr;
5734 IWineD3DSwapChain *swapchain;
5736 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5737 if (SUCCEEDED(hr)) {
5738 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5739 return swapchain;
5742 return NULL;
5745 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5748 if (!*fbo) {
5749 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5750 checkGLcall("glGenFramebuffersEXT()");
5752 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5753 checkGLcall("glBindFramebuffer()");
5756 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5757 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5758 IWineD3DBaseTextureImpl *texture_impl;
5759 GLenum texttarget, target;
5760 GLint old_binding;
5762 texttarget = surface_impl->glDescription.target;
5763 if(texttarget == GL_TEXTURE_2D) {
5764 target = GL_TEXTURE_2D;
5765 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5766 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
5767 target = GL_TEXTURE_RECTANGLE_ARB;
5768 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5769 } else {
5770 target = GL_TEXTURE_CUBE_MAP_ARB;
5771 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5774 IWineD3DSurface_PreLoad(surface);
5776 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5777 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5778 glBindTexture(target, old_binding);
5780 /* Update base texture states array */
5781 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5782 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5783 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5784 if (texture_impl->baseTexture.bindCount) {
5785 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5788 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5791 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5792 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5794 checkGLcall("attach_surface_fbo");
5797 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5799 IWineD3DSwapChain *swapchain;
5801 swapchain = get_swapchain(surface);
5802 if (swapchain) {
5803 GLenum buffer;
5805 TRACE("Surface %p is onscreen\n", surface);
5807 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5808 buffer = surface_get_gl_buffer(surface, swapchain);
5809 glDrawBuffer(buffer);
5810 checkGLcall("glDrawBuffer()");
5811 } else {
5812 TRACE("Surface %p is offscreen\n", surface);
5813 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5814 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5817 if (rect) {
5818 glEnable(GL_SCISSOR_TEST);
5819 if(!swapchain) {
5820 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5821 } else {
5822 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5823 rect->x2 - rect->x1, rect->y2 - rect->y1);
5825 checkGLcall("glScissor");
5826 } else {
5827 glDisable(GL_SCISSOR_TEST);
5829 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5831 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5832 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5834 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5835 glClear(GL_COLOR_BUFFER_BIT);
5836 checkGLcall("glClear");
5838 if (This->render_offscreen) {
5839 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5840 } else {
5841 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5842 checkGLcall("glBindFramebuffer()");
5845 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5846 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5847 glDrawBuffer(GL_BACK);
5848 checkGLcall("glDrawBuffer()");
5852 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5853 unsigned int r, g, b, a;
5854 DWORD ret;
5856 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
5857 destfmt == WINED3DFMT_R8G8B8)
5858 return color;
5860 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5862 a = (color & 0xff000000) >> 24;
5863 r = (color & 0x00ff0000) >> 16;
5864 g = (color & 0x0000ff00) >> 8;
5865 b = (color & 0x000000ff) >> 0;
5867 switch(destfmt)
5869 case WINED3DFMT_R5G6B5:
5870 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5871 r = (r * 32) / 256;
5872 g = (g * 64) / 256;
5873 b = (b * 32) / 256;
5874 ret = r << 11;
5875 ret |= g << 5;
5876 ret |= b;
5877 TRACE("Returning %08x\n", ret);
5878 return ret;
5880 case WINED3DFMT_X1R5G5B5:
5881 case WINED3DFMT_A1R5G5B5:
5882 a = (a * 2) / 256;
5883 r = (r * 32) / 256;
5884 g = (g * 32) / 256;
5885 b = (b * 32) / 256;
5886 ret = a << 15;
5887 ret |= r << 10;
5888 ret |= g << 5;
5889 ret |= b << 0;
5890 TRACE("Returning %08x\n", ret);
5891 return ret;
5893 case WINED3DFMT_A8:
5894 TRACE("Returning %08x\n", a);
5895 return a;
5897 case WINED3DFMT_X4R4G4B4:
5898 case WINED3DFMT_A4R4G4B4:
5899 a = (a * 16) / 256;
5900 r = (r * 16) / 256;
5901 g = (g * 16) / 256;
5902 b = (b * 16) / 256;
5903 ret = a << 12;
5904 ret |= r << 8;
5905 ret |= g << 4;
5906 ret |= b << 0;
5907 TRACE("Returning %08x\n", ret);
5908 return ret;
5910 case WINED3DFMT_R3G3B2:
5911 r = (r * 8) / 256;
5912 g = (g * 8) / 256;
5913 b = (b * 4) / 256;
5914 ret = r << 5;
5915 ret |= g << 2;
5916 ret |= b << 0;
5917 TRACE("Returning %08x\n", ret);
5918 return ret;
5920 case WINED3DFMT_X8B8G8R8:
5921 case WINED3DFMT_A8B8G8R8:
5922 ret = a << 24;
5923 ret |= b << 16;
5924 ret |= g << 8;
5925 ret |= r << 0;
5926 TRACE("Returning %08x\n", ret);
5927 return ret;
5929 case WINED3DFMT_A2R10G10B10:
5930 a = (a * 4) / 256;
5931 r = (r * 1024) / 256;
5932 g = (g * 1024) / 256;
5933 b = (b * 1024) / 256;
5934 ret = a << 30;
5935 ret |= r << 20;
5936 ret |= g << 10;
5937 ret |= b << 0;
5938 TRACE("Returning %08x\n", ret);
5939 return ret;
5941 case WINED3DFMT_A2B10G10R10:
5942 a = (a * 4) / 256;
5943 r = (r * 1024) / 256;
5944 g = (g * 1024) / 256;
5945 b = (b * 1024) / 256;
5946 ret = a << 30;
5947 ret |= b << 20;
5948 ret |= g << 10;
5949 ret |= r << 0;
5950 TRACE("Returning %08x\n", ret);
5951 return ret;
5953 default:
5954 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5955 return 0;
5959 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5961 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5962 WINEDDBLTFX BltFx;
5963 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5965 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5966 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5967 return WINED3DERR_INVALIDCALL;
5970 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5971 color_fill_fbo(iface, pSurface, pRect, color);
5972 return WINED3D_OK;
5973 } else {
5974 /* Just forward this to the DirectDraw blitting engine */
5975 memset(&BltFx, 0, sizeof(BltFx));
5976 BltFx.dwSize = sizeof(BltFx);
5977 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
5978 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5982 /* rendertarget and deptth stencil functions */
5983 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5986 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5987 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5988 return WINED3DERR_INVALIDCALL;
5991 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5992 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5993 /* Note inc ref on returned surface */
5994 if(*ppRenderTarget != NULL)
5995 IWineD3DSurface_AddRef(*ppRenderTarget);
5996 return WINED3D_OK;
5999 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6001 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6002 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6003 IWineD3DSwapChainImpl *Swapchain;
6004 HRESULT hr;
6006 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6008 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6009 if(hr != WINED3D_OK) {
6010 ERR("Can't get the swapchain\n");
6011 return hr;
6014 /* Make sure to release the swapchain */
6015 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6017 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6018 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6019 return WINED3DERR_INVALIDCALL;
6021 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6022 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6023 return WINED3DERR_INVALIDCALL;
6026 if(Swapchain->frontBuffer != Front) {
6027 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6029 if(Swapchain->frontBuffer)
6030 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6031 Swapchain->frontBuffer = Front;
6033 if(Swapchain->frontBuffer) {
6034 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6038 if(Back && !Swapchain->backBuffer) {
6039 /* We need memory for the back buffer array - only one back buffer this way */
6040 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6041 if(!Swapchain->backBuffer) {
6042 ERR("Out of memory\n");
6043 return E_OUTOFMEMORY;
6047 if(Swapchain->backBuffer[0] != Back) {
6048 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6050 /* What to do about the context here in the case of multithreading? Not sure.
6051 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6053 ENTER_GL();
6054 if(!Swapchain->backBuffer[0]) {
6055 /* GL was told to draw to the front buffer at creation,
6056 * undo that
6058 glDrawBuffer(GL_BACK);
6059 checkGLcall("glDrawBuffer(GL_BACK)");
6060 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6061 Swapchain->presentParms.BackBufferCount = 1;
6062 } else if (!Back) {
6063 /* That makes problems - disable for now */
6064 /* glDrawBuffer(GL_FRONT); */
6065 checkGLcall("glDrawBuffer(GL_FRONT)");
6066 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6067 Swapchain->presentParms.BackBufferCount = 0;
6069 LEAVE_GL();
6071 if(Swapchain->backBuffer[0])
6072 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6073 Swapchain->backBuffer[0] = Back;
6075 if(Swapchain->backBuffer[0]) {
6076 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6077 } else {
6078 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6079 Swapchain->backBuffer = NULL;
6084 return WINED3D_OK;
6087 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6089 *ppZStencilSurface = This->stencilBufferTarget;
6090 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6092 if(*ppZStencilSurface != NULL) {
6093 /* Note inc ref on returned surface */
6094 IWineD3DSurface_AddRef(*ppZStencilSurface);
6095 return WINED3D_OK;
6096 } else {
6097 return WINED3DERR_NOTFOUND;
6101 /* TODO: Handle stencil attachments */
6102 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6104 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6106 TRACE("Set depth stencil to %p\n", depth_stencil);
6108 if (depth_stencil_impl) {
6109 if (depth_stencil_impl->current_renderbuffer) {
6110 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6111 checkGLcall("glFramebufferRenderbufferEXT()");
6112 } else {
6113 IWineD3DBaseTextureImpl *texture_impl;
6114 GLenum texttarget, target;
6115 GLint old_binding = 0;
6117 texttarget = depth_stencil_impl->glDescription.target;
6118 if(texttarget == GL_TEXTURE_2D) {
6119 target = GL_TEXTURE_2D;
6120 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6121 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6122 target = GL_TEXTURE_RECTANGLE_ARB;
6123 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6124 } else {
6125 target = GL_TEXTURE_CUBE_MAP_ARB;
6126 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6129 IWineD3DSurface_PreLoad(depth_stencil);
6131 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6132 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6133 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6134 glBindTexture(target, old_binding);
6136 /* Update base texture states array */
6137 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6138 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6139 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6140 if (texture_impl->baseTexture.bindCount) {
6141 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6144 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6147 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6148 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6149 checkGLcall("glFramebufferTexture2DEXT()");
6151 } else {
6152 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6153 checkGLcall("glFramebufferTexture2DEXT()");
6157 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6159 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6161 TRACE("Set render target %u to %p\n", idx, render_target);
6163 if (rtimpl) {
6164 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6165 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6166 } else {
6167 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6168 checkGLcall("glFramebufferTexture2DEXT()");
6170 This->draw_buffers[idx] = GL_NONE;
6174 static void check_fbo_status(IWineD3DDevice *iface) {
6175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6176 GLenum status;
6178 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6179 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6180 TRACE("FBO complete\n");
6181 } else {
6182 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6184 /* Dump the FBO attachments */
6185 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
6186 IWineD3DSurfaceImpl *attachment;
6187 int i;
6189 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6190 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6191 if (attachment) {
6192 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6193 attachment->pow2Width, attachment->pow2Height);
6196 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6197 if (attachment) {
6198 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6199 attachment->pow2Width, attachment->pow2Height);
6205 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6207 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6208 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6210 if (!ds_impl) return FALSE;
6212 if (ds_impl->current_renderbuffer) {
6213 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6214 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6217 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6218 rt_impl->pow2Height != ds_impl->pow2Height);
6221 void apply_fbo_state(IWineD3DDevice *iface) {
6222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6223 unsigned int i;
6225 if (This->render_offscreen) {
6226 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6228 /* Apply render targets */
6229 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6230 IWineD3DSurface *render_target = This->render_targets[i];
6231 if (This->fbo_color_attachments[i] != render_target) {
6232 set_render_target_fbo(iface, i, render_target);
6233 This->fbo_color_attachments[i] = render_target;
6237 /* Apply depth targets */
6238 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6239 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6240 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6242 if (This->stencilBufferTarget) {
6243 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6245 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6246 This->fbo_depth_attachment = This->stencilBufferTarget;
6249 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6250 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6251 checkGLcall("glDrawBuffers()");
6252 } else {
6253 glDrawBuffer(This->draw_buffers[0]);
6254 checkGLcall("glDrawBuffer()");
6256 } else {
6257 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6260 check_fbo_status(iface);
6263 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6264 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6265 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6266 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6267 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6268 GLenum gl_filter;
6270 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6271 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6272 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6273 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6275 switch (filter) {
6276 case WINED3DTEXF_LINEAR:
6277 gl_filter = GL_LINEAR;
6278 break;
6280 default:
6281 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6282 case WINED3DTEXF_NONE:
6283 case WINED3DTEXF_POINT:
6284 gl_filter = GL_NEAREST;
6285 break;
6288 /* Attach src surface to src fbo */
6289 src_swapchain = get_swapchain(src_surface);
6290 if (src_swapchain) {
6291 GLenum buffer;
6293 TRACE("Source surface %p is onscreen\n", src_surface);
6294 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6296 ENTER_GL();
6297 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6298 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6299 glReadBuffer(buffer);
6300 checkGLcall("glReadBuffer()");
6302 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6303 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6304 } else {
6305 TRACE("Source surface %p is offscreen\n", src_surface);
6306 ENTER_GL();
6307 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6308 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6309 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6310 checkGLcall("glReadBuffer()");
6312 LEAVE_GL();
6314 /* Attach dst surface to dst fbo */
6315 dst_swapchain = get_swapchain(dst_surface);
6316 if (dst_swapchain) {
6317 GLenum buffer;
6319 TRACE("Destination surface %p is onscreen\n", dst_surface);
6320 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6322 ENTER_GL();
6323 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6324 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6325 glDrawBuffer(buffer);
6326 checkGLcall("glDrawBuffer()");
6328 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6329 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6330 } else {
6331 TRACE("Destination surface %p is offscreen\n", dst_surface);
6333 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6334 if(!src_swapchain) {
6335 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6338 ENTER_GL();
6339 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6340 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6341 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6342 checkGLcall("glDrawBuffer()");
6344 glDisable(GL_SCISSOR_TEST);
6345 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6347 if (flip) {
6348 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6349 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6350 checkGLcall("glBlitFramebuffer()");
6351 } else {
6352 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6353 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6354 checkGLcall("glBlitFramebuffer()");
6357 if (This->render_offscreen) {
6358 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6359 } else {
6360 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6361 checkGLcall("glBindFramebuffer()");
6364 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6365 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6366 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6367 glDrawBuffer(GL_BACK);
6368 checkGLcall("glDrawBuffer()");
6370 LEAVE_GL();
6373 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6375 WINED3DVIEWPORT viewport;
6377 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6379 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6380 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6381 This, RenderTargetIndex, GL_LIMITS(buffers));
6382 return WINED3DERR_INVALIDCALL;
6385 /* MSDN says that null disables the render target
6386 but a device must always be associated with a render target
6387 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6389 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6390 for more details
6392 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6393 FIXME("Trying to set render target 0 to NULL\n");
6394 return WINED3DERR_INVALIDCALL;
6396 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
6397 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);
6398 return WINED3DERR_INVALIDCALL;
6401 /* If we are trying to set what we already have, don't bother */
6402 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6403 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6404 return WINED3D_OK;
6406 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6407 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6408 This->render_targets[RenderTargetIndex] = pRenderTarget;
6410 /* Render target 0 is special */
6411 if(RenderTargetIndex == 0) {
6412 /* Finally, reset the viewport as the MSDN states. */
6413 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6414 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6415 viewport.X = 0;
6416 viewport.Y = 0;
6417 viewport.MaxZ = 1.0f;
6418 viewport.MinZ = 0.0f;
6419 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6420 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6421 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6423 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6425 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6426 * ctx properly.
6427 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6428 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6430 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6432 return WINED3D_OK;
6435 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6437 HRESULT hr = WINED3D_OK;
6438 IWineD3DSurface *tmp;
6440 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6442 if (pNewZStencil == This->stencilBufferTarget) {
6443 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6444 } else {
6445 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6446 * depending on the renter target implementation being used.
6447 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6448 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6449 * stencil buffer and incure an extra memory overhead
6450 ******************************************************/
6452 tmp = This->stencilBufferTarget;
6453 This->stencilBufferTarget = pNewZStencil;
6454 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6455 /* should we be calling the parent or the wined3d surface? */
6456 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6457 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6458 hr = WINED3D_OK;
6460 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6461 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6462 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6463 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6464 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6468 return hr;
6471 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6472 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6474 /* TODO: the use of Impl is deprecated. */
6475 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6476 WINED3DLOCKED_RECT lockedRect;
6478 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6480 /* some basic validation checks */
6481 if(This->cursorTexture) {
6482 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6483 ENTER_GL();
6484 glDeleteTextures(1, &This->cursorTexture);
6485 LEAVE_GL();
6486 This->cursorTexture = 0;
6489 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6490 This->haveHardwareCursor = TRUE;
6491 else
6492 This->haveHardwareCursor = FALSE;
6494 if(pCursorBitmap) {
6495 WINED3DLOCKED_RECT rect;
6497 /* MSDN: Cursor must be A8R8G8B8 */
6498 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6499 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6500 return WINED3DERR_INVALIDCALL;
6503 /* MSDN: Cursor must be smaller than the display mode */
6504 if(pSur->currentDesc.Width > This->ddraw_width ||
6505 pSur->currentDesc.Height > This->ddraw_height) {
6506 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);
6507 return WINED3DERR_INVALIDCALL;
6510 if (!This->haveHardwareCursor) {
6511 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6513 /* Do not store the surface's pointer because the application may
6514 * release it after setting the cursor image. Windows doesn't
6515 * addref the set surface, so we can't do this either without
6516 * creating circular refcount dependencies. Copy out the gl texture
6517 * instead.
6519 This->cursorWidth = pSur->currentDesc.Width;
6520 This->cursorHeight = pSur->currentDesc.Height;
6521 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6523 const GlPixelFormatDesc *glDesc;
6524 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6525 char *mem, *bits = (char *)rect.pBits;
6526 GLint intfmt = glDesc->glInternal;
6527 GLint format = glDesc->glFormat;
6528 GLint type = glDesc->glType;
6529 INT height = This->cursorHeight;
6530 INT width = This->cursorWidth;
6531 INT bpp = tableEntry->bpp;
6532 INT i;
6534 /* Reformat the texture memory (pitch and width can be
6535 * different) */
6536 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6537 for(i = 0; i < height; i++)
6538 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6539 IWineD3DSurface_UnlockRect(pCursorBitmap);
6540 ENTER_GL();
6542 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6543 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6544 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6547 /* Make sure that a proper texture unit is selected */
6548 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6549 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6550 checkGLcall("glActiveTextureARB");
6552 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6553 /* Create a new cursor texture */
6554 glGenTextures(1, &This->cursorTexture);
6555 checkGLcall("glGenTextures");
6556 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6557 checkGLcall("glBindTexture");
6558 /* Copy the bitmap memory into the cursor texture */
6559 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6560 HeapFree(GetProcessHeap(), 0, mem);
6561 checkGLcall("glTexImage2D");
6563 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6564 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6565 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6568 LEAVE_GL();
6570 else
6572 FIXME("A cursor texture was not returned.\n");
6573 This->cursorTexture = 0;
6576 else
6578 /* Draw a hardware cursor */
6579 ICONINFO cursorInfo;
6580 HCURSOR cursor;
6581 /* Create and clear maskBits because it is not needed for
6582 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6583 * chunks. */
6584 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6585 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6586 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6587 WINED3DLOCK_NO_DIRTY_UPDATE |
6588 WINED3DLOCK_READONLY
6590 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6591 pSur->currentDesc.Height);
6593 cursorInfo.fIcon = FALSE;
6594 cursorInfo.xHotspot = XHotSpot;
6595 cursorInfo.yHotspot = YHotSpot;
6596 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6597 pSur->currentDesc.Height, 1,
6598 1, &maskBits);
6599 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6600 pSur->currentDesc.Height, 1,
6601 32, lockedRect.pBits);
6602 IWineD3DSurface_UnlockRect(pCursorBitmap);
6603 /* Create our cursor and clean up. */
6604 cursor = CreateIconIndirect(&cursorInfo);
6605 SetCursor(cursor);
6606 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6607 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6608 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6609 This->hardwareCursor = cursor;
6610 HeapFree(GetProcessHeap(), 0, maskBits);
6614 This->xHotSpot = XHotSpot;
6615 This->yHotSpot = YHotSpot;
6616 return WINED3D_OK;
6619 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6621 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6623 This->xScreenSpace = XScreenSpace;
6624 This->yScreenSpace = YScreenSpace;
6626 return;
6630 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6632 BOOL oldVisible = This->bCursorVisible;
6633 POINT pt;
6635 TRACE("(%p) : visible(%d)\n", This, bShow);
6638 * When ShowCursor is first called it should make the cursor appear at the OS's last
6639 * known cursor position. Because of this, some applications just repetitively call
6640 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6642 GetCursorPos(&pt);
6643 This->xScreenSpace = pt.x;
6644 This->yScreenSpace = pt.y;
6646 if (This->haveHardwareCursor) {
6647 This->bCursorVisible = bShow;
6648 if (bShow)
6649 SetCursor(This->hardwareCursor);
6650 else
6651 SetCursor(NULL);
6653 else
6655 if (This->cursorTexture)
6656 This->bCursorVisible = bShow;
6659 return oldVisible;
6662 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6664 IWineD3DResourceImpl *resource;
6665 TRACE("(%p) : state (%u)\n", This, This->state);
6667 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6668 switch (This->state) {
6669 case WINED3D_OK:
6670 return WINED3D_OK;
6671 case WINED3DERR_DEVICELOST:
6673 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6674 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6675 return WINED3DERR_DEVICENOTRESET;
6677 return WINED3DERR_DEVICELOST;
6679 case WINED3DERR_DRIVERINTERNALERROR:
6680 return WINED3DERR_DRIVERINTERNALERROR;
6683 /* Unknown state */
6684 return WINED3DERR_DRIVERINTERNALERROR;
6688 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6690 /** FIXME: Resource tracking needs to be done,
6691 * The closes we can do to this is set the priorities of all managed textures low
6692 * and then reset them.
6693 ***********************************************************/
6694 FIXME("(%p) : stub\n", This);
6695 return WINED3D_OK;
6698 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6699 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6701 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6702 if(surface->Flags & SFLAG_DIBSECTION) {
6703 /* Release the DC */
6704 SelectObject(surface->hDC, surface->dib.holdbitmap);
6705 DeleteDC(surface->hDC);
6706 /* Release the DIB section */
6707 DeleteObject(surface->dib.DIBsection);
6708 surface->dib.bitmap_data = NULL;
6709 surface->resource.allocatedMemory = NULL;
6710 surface->Flags &= ~SFLAG_DIBSECTION;
6712 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6713 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6714 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6715 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6716 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6717 } else {
6718 surface->pow2Width = surface->pow2Height = 1;
6719 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6720 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6722 if(surface->glDescription.textureName) {
6723 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6724 ENTER_GL();
6725 glDeleteTextures(1, &surface->glDescription.textureName);
6726 LEAVE_GL();
6727 surface->glDescription.textureName = 0;
6728 surface->Flags &= ~SFLAG_CLIENT;
6730 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6731 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6732 surface->Flags |= SFLAG_NONPOW2;
6733 } else {
6734 surface->Flags &= ~SFLAG_NONPOW2;
6736 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6737 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6740 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6742 IWineD3DSwapChainImpl *swapchain;
6743 HRESULT hr;
6744 BOOL DisplayModeChanged = FALSE;
6745 WINED3DDISPLAYMODE mode;
6746 TRACE("(%p)\n", This);
6748 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6749 if(FAILED(hr)) {
6750 ERR("Failed to get the first implicit swapchain\n");
6751 return hr;
6754 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6755 * on an existing gl context, so there's no real need for recreation.
6757 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6759 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6761 TRACE("New params:\n");
6762 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6763 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6764 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6765 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6766 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6767 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6768 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6769 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6770 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6771 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6772 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6773 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6774 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6776 /* No special treatment of these parameters. Just store them */
6777 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6778 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6779 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6780 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6782 /* What to do about these? */
6783 if(pPresentationParameters->BackBufferCount != 0 &&
6784 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6785 ERR("Cannot change the back buffer count yet\n");
6787 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6788 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6789 ERR("Cannot change the back buffer format yet\n");
6791 if(pPresentationParameters->hDeviceWindow != NULL &&
6792 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6793 ERR("Cannot change the device window yet\n");
6795 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6796 ERR("What do do about a changed auto depth stencil parameter?\n");
6799 if(pPresentationParameters->Windowed) {
6800 mode.Width = swapchain->orig_width;
6801 mode.Height = swapchain->orig_height;
6802 mode.RefreshRate = 0;
6803 mode.Format = swapchain->presentParms.BackBufferFormat;
6804 } else {
6805 mode.Width = pPresentationParameters->BackBufferWidth;
6806 mode.Height = pPresentationParameters->BackBufferHeight;
6807 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6808 mode.Format = swapchain->presentParms.BackBufferFormat;
6810 SetWindowLongA(swapchain->win_handle, GWL_STYLE, WS_POPUP);
6811 SetWindowPos(swapchain->win_handle, HWND_TOP, 0, 0,
6812 pPresentationParameters->BackBufferWidth,
6813 pPresentationParameters->BackBufferHeight, SWP_SHOWWINDOW | SWP_FRAMECHANGED);
6816 /* Should Width == 800 && Height == 0 set 800x600? */
6817 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6818 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6819 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6821 WINED3DVIEWPORT vp;
6822 int i;
6824 vp.X = 0;
6825 vp.Y = 0;
6826 vp.Width = pPresentationParameters->BackBufferWidth;
6827 vp.Height = pPresentationParameters->BackBufferHeight;
6828 vp.MinZ = 0;
6829 vp.MaxZ = 1;
6831 if(!pPresentationParameters->Windowed) {
6832 DisplayModeChanged = TRUE;
6834 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6835 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6837 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6838 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6839 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6842 /* Now set the new viewport */
6843 IWineD3DDevice_SetViewport(iface, &vp);
6846 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6847 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6848 DisplayModeChanged) {
6850 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6851 if(!pPresentationParameters->Windowed) {
6852 IWineD3DDevice_SetFullscreen(iface, TRUE);
6855 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6857 /* Switching out of fullscreen mode? First set the original res, then change the window */
6858 if(pPresentationParameters->Windowed) {
6859 IWineD3DDevice_SetFullscreen(iface, FALSE);
6861 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6864 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6865 return WINED3D_OK;
6868 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6870 /** FIXME: always true at the moment **/
6871 if(!bEnableDialogs) {
6872 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6874 return WINED3D_OK;
6878 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6880 TRACE("(%p) : pParameters %p\n", This, pParameters);
6882 *pParameters = This->createParms;
6883 return WINED3D_OK;
6886 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6887 IWineD3DSwapChain *swapchain;
6888 HRESULT hrc = WINED3D_OK;
6890 TRACE("Relaying to swapchain\n");
6892 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6893 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6894 IWineD3DSwapChain_Release(swapchain);
6896 return;
6899 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6900 IWineD3DSwapChain *swapchain;
6901 HRESULT hrc = WINED3D_OK;
6903 TRACE("Relaying to swapchain\n");
6905 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6906 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6907 IWineD3DSwapChain_Release(swapchain);
6909 return;
6913 /** ********************************************************
6914 * Notification functions
6915 ** ********************************************************/
6916 /** This function must be called in the release of a resource when ref == 0,
6917 * the contents of resource must still be correct,
6918 * any handels to other resource held by the caller must be closed
6919 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6920 *****************************************************/
6921 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6924 TRACE("(%p) : Adding Resource %p\n", This, resource);
6925 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6928 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6931 TRACE("(%p) : Removing resource %p\n", This, resource);
6933 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6937 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6939 int counter;
6941 TRACE("(%p) : resource %p\n", This, resource);
6942 switch(IWineD3DResource_GetType(resource)){
6943 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6944 case WINED3DRTYPE_SURFACE: {
6945 unsigned int i;
6947 /* Cleanup any FBO attachments if d3d is enabled */
6948 if(This->d3d_initialized) {
6949 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
6950 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
6952 TRACE("Last active render target destroyed\n");
6953 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
6954 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
6955 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
6956 * and the lastActiveRenderTarget member shouldn't matter
6958 if(swapchain) {
6959 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
6960 TRACE("Activating primary back buffer\n");
6961 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
6962 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
6963 /* Single buffering environment */
6964 TRACE("Activating primary front buffer\n");
6965 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
6966 } else {
6967 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
6968 /* Implicit render target destroyed, that means the device is being destroyed
6969 * whatever we set here, it shouldn't matter
6971 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
6973 } else {
6974 /* May happen during ddraw uninitialization */
6975 TRACE("Render target set, but swapchain does not exist!\n");
6976 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
6980 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6981 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6982 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6983 set_render_target_fbo(iface, i, NULL);
6984 This->fbo_color_attachments[i] = NULL;
6987 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6988 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6989 set_depth_stencil_fbo(iface, NULL);
6990 This->fbo_depth_attachment = NULL;
6994 break;
6996 case WINED3DRTYPE_TEXTURE:
6997 case WINED3DRTYPE_CUBETEXTURE:
6998 case WINED3DRTYPE_VOLUMETEXTURE:
6999 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7000 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7001 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7002 This->stateBlock->textures[counter] = NULL;
7004 if (This->updateStateBlock != This->stateBlock ){
7005 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7006 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7007 This->updateStateBlock->textures[counter] = NULL;
7011 break;
7012 case WINED3DRTYPE_VOLUME:
7013 /* TODO: nothing really? */
7014 break;
7015 case WINED3DRTYPE_VERTEXBUFFER:
7016 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7018 int streamNumber;
7019 TRACE("Cleaning up stream pointers\n");
7021 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7022 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7023 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7025 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7026 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7027 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7028 This->updateStateBlock->streamSource[streamNumber] = 0;
7029 /* Set changed flag? */
7032 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) */
7033 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7034 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7035 This->stateBlock->streamSource[streamNumber] = 0;
7038 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7039 else { /* This shouldn't happen */
7040 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7042 #endif
7046 break;
7047 case WINED3DRTYPE_INDEXBUFFER:
7048 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7049 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7050 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7051 This->updateStateBlock->pIndexData = NULL;
7054 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7055 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7056 This->stateBlock->pIndexData = NULL;
7060 break;
7061 default:
7062 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7063 break;
7067 /* Remove the resoruce from the resourceStore */
7068 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7070 TRACE("Resource released\n");
7074 /**********************************************************
7075 * IWineD3DDevice VTbl follows
7076 **********************************************************/
7078 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7080 /*** IUnknown methods ***/
7081 IWineD3DDeviceImpl_QueryInterface,
7082 IWineD3DDeviceImpl_AddRef,
7083 IWineD3DDeviceImpl_Release,
7084 /*** IWineD3DDevice methods ***/
7085 IWineD3DDeviceImpl_GetParent,
7086 /*** Creation methods**/
7087 IWineD3DDeviceImpl_CreateVertexBuffer,
7088 IWineD3DDeviceImpl_CreateIndexBuffer,
7089 IWineD3DDeviceImpl_CreateStateBlock,
7090 IWineD3DDeviceImpl_CreateSurface,
7091 IWineD3DDeviceImpl_CreateTexture,
7092 IWineD3DDeviceImpl_CreateVolumeTexture,
7093 IWineD3DDeviceImpl_CreateVolume,
7094 IWineD3DDeviceImpl_CreateCubeTexture,
7095 IWineD3DDeviceImpl_CreateQuery,
7096 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7097 IWineD3DDeviceImpl_CreateVertexDeclaration,
7098 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7099 IWineD3DDeviceImpl_CreateVertexShader,
7100 IWineD3DDeviceImpl_CreatePixelShader,
7101 IWineD3DDeviceImpl_CreatePalette,
7102 /*** Odd functions **/
7103 IWineD3DDeviceImpl_Init3D,
7104 IWineD3DDeviceImpl_Uninit3D,
7105 IWineD3DDeviceImpl_SetFullscreen,
7106 IWineD3DDeviceImpl_SetMultithreaded,
7107 IWineD3DDeviceImpl_EvictManagedResources,
7108 IWineD3DDeviceImpl_GetAvailableTextureMem,
7109 IWineD3DDeviceImpl_GetBackBuffer,
7110 IWineD3DDeviceImpl_GetCreationParameters,
7111 IWineD3DDeviceImpl_GetDeviceCaps,
7112 IWineD3DDeviceImpl_GetDirect3D,
7113 IWineD3DDeviceImpl_GetDisplayMode,
7114 IWineD3DDeviceImpl_SetDisplayMode,
7115 IWineD3DDeviceImpl_GetHWND,
7116 IWineD3DDeviceImpl_SetHWND,
7117 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7118 IWineD3DDeviceImpl_GetRasterStatus,
7119 IWineD3DDeviceImpl_GetSwapChain,
7120 IWineD3DDeviceImpl_Reset,
7121 IWineD3DDeviceImpl_SetDialogBoxMode,
7122 IWineD3DDeviceImpl_SetCursorProperties,
7123 IWineD3DDeviceImpl_SetCursorPosition,
7124 IWineD3DDeviceImpl_ShowCursor,
7125 IWineD3DDeviceImpl_TestCooperativeLevel,
7126 /*** Getters and setters **/
7127 IWineD3DDeviceImpl_SetClipPlane,
7128 IWineD3DDeviceImpl_GetClipPlane,
7129 IWineD3DDeviceImpl_SetClipStatus,
7130 IWineD3DDeviceImpl_GetClipStatus,
7131 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7132 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7133 IWineD3DDeviceImpl_SetDepthStencilSurface,
7134 IWineD3DDeviceImpl_GetDepthStencilSurface,
7135 IWineD3DDeviceImpl_SetFVF,
7136 IWineD3DDeviceImpl_GetFVF,
7137 IWineD3DDeviceImpl_SetGammaRamp,
7138 IWineD3DDeviceImpl_GetGammaRamp,
7139 IWineD3DDeviceImpl_SetIndices,
7140 IWineD3DDeviceImpl_GetIndices,
7141 IWineD3DDeviceImpl_SetBaseVertexIndex,
7142 IWineD3DDeviceImpl_GetBaseVertexIndex,
7143 IWineD3DDeviceImpl_SetLight,
7144 IWineD3DDeviceImpl_GetLight,
7145 IWineD3DDeviceImpl_SetLightEnable,
7146 IWineD3DDeviceImpl_GetLightEnable,
7147 IWineD3DDeviceImpl_SetMaterial,
7148 IWineD3DDeviceImpl_GetMaterial,
7149 IWineD3DDeviceImpl_SetNPatchMode,
7150 IWineD3DDeviceImpl_GetNPatchMode,
7151 IWineD3DDeviceImpl_SetPaletteEntries,
7152 IWineD3DDeviceImpl_GetPaletteEntries,
7153 IWineD3DDeviceImpl_SetPixelShader,
7154 IWineD3DDeviceImpl_GetPixelShader,
7155 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7156 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7157 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7158 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7159 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7160 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7161 IWineD3DDeviceImpl_SetRenderState,
7162 IWineD3DDeviceImpl_GetRenderState,
7163 IWineD3DDeviceImpl_SetRenderTarget,
7164 IWineD3DDeviceImpl_GetRenderTarget,
7165 IWineD3DDeviceImpl_SetFrontBackBuffers,
7166 IWineD3DDeviceImpl_SetSamplerState,
7167 IWineD3DDeviceImpl_GetSamplerState,
7168 IWineD3DDeviceImpl_SetScissorRect,
7169 IWineD3DDeviceImpl_GetScissorRect,
7170 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7171 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7172 IWineD3DDeviceImpl_SetStreamSource,
7173 IWineD3DDeviceImpl_GetStreamSource,
7174 IWineD3DDeviceImpl_SetStreamSourceFreq,
7175 IWineD3DDeviceImpl_GetStreamSourceFreq,
7176 IWineD3DDeviceImpl_SetTexture,
7177 IWineD3DDeviceImpl_GetTexture,
7178 IWineD3DDeviceImpl_SetTextureStageState,
7179 IWineD3DDeviceImpl_GetTextureStageState,
7180 IWineD3DDeviceImpl_SetTransform,
7181 IWineD3DDeviceImpl_GetTransform,
7182 IWineD3DDeviceImpl_SetVertexDeclaration,
7183 IWineD3DDeviceImpl_GetVertexDeclaration,
7184 IWineD3DDeviceImpl_SetVertexShader,
7185 IWineD3DDeviceImpl_GetVertexShader,
7186 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7187 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7188 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7189 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7190 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7191 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7192 IWineD3DDeviceImpl_SetViewport,
7193 IWineD3DDeviceImpl_GetViewport,
7194 IWineD3DDeviceImpl_MultiplyTransform,
7195 IWineD3DDeviceImpl_ValidateDevice,
7196 IWineD3DDeviceImpl_ProcessVertices,
7197 /*** State block ***/
7198 IWineD3DDeviceImpl_BeginStateBlock,
7199 IWineD3DDeviceImpl_EndStateBlock,
7200 /*** Scene management ***/
7201 IWineD3DDeviceImpl_BeginScene,
7202 IWineD3DDeviceImpl_EndScene,
7203 IWineD3DDeviceImpl_Present,
7204 IWineD3DDeviceImpl_Clear,
7205 /*** Drawing ***/
7206 IWineD3DDeviceImpl_DrawPrimitive,
7207 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7208 IWineD3DDeviceImpl_DrawPrimitiveUP,
7209 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7210 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7211 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7212 IWineD3DDeviceImpl_DrawRectPatch,
7213 IWineD3DDeviceImpl_DrawTriPatch,
7214 IWineD3DDeviceImpl_DeletePatch,
7215 IWineD3DDeviceImpl_ColorFill,
7216 IWineD3DDeviceImpl_UpdateTexture,
7217 IWineD3DDeviceImpl_UpdateSurface,
7218 IWineD3DDeviceImpl_GetFrontBufferData,
7219 /*** object tracking ***/
7220 IWineD3DDeviceImpl_ResourceReleased
7224 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7225 WINED3DRS_ALPHABLENDENABLE ,
7226 WINED3DRS_ALPHAFUNC ,
7227 WINED3DRS_ALPHAREF ,
7228 WINED3DRS_ALPHATESTENABLE ,
7229 WINED3DRS_BLENDOP ,
7230 WINED3DRS_COLORWRITEENABLE ,
7231 WINED3DRS_DESTBLEND ,
7232 WINED3DRS_DITHERENABLE ,
7233 WINED3DRS_FILLMODE ,
7234 WINED3DRS_FOGDENSITY ,
7235 WINED3DRS_FOGEND ,
7236 WINED3DRS_FOGSTART ,
7237 WINED3DRS_LASTPIXEL ,
7238 WINED3DRS_SHADEMODE ,
7239 WINED3DRS_SRCBLEND ,
7240 WINED3DRS_STENCILENABLE ,
7241 WINED3DRS_STENCILFAIL ,
7242 WINED3DRS_STENCILFUNC ,
7243 WINED3DRS_STENCILMASK ,
7244 WINED3DRS_STENCILPASS ,
7245 WINED3DRS_STENCILREF ,
7246 WINED3DRS_STENCILWRITEMASK ,
7247 WINED3DRS_STENCILZFAIL ,
7248 WINED3DRS_TEXTUREFACTOR ,
7249 WINED3DRS_WRAP0 ,
7250 WINED3DRS_WRAP1 ,
7251 WINED3DRS_WRAP2 ,
7252 WINED3DRS_WRAP3 ,
7253 WINED3DRS_WRAP4 ,
7254 WINED3DRS_WRAP5 ,
7255 WINED3DRS_WRAP6 ,
7256 WINED3DRS_WRAP7 ,
7257 WINED3DRS_ZENABLE ,
7258 WINED3DRS_ZFUNC ,
7259 WINED3DRS_ZWRITEENABLE
7262 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7263 WINED3DTSS_ADDRESSW ,
7264 WINED3DTSS_ALPHAARG0 ,
7265 WINED3DTSS_ALPHAARG1 ,
7266 WINED3DTSS_ALPHAARG2 ,
7267 WINED3DTSS_ALPHAOP ,
7268 WINED3DTSS_BUMPENVLOFFSET ,
7269 WINED3DTSS_BUMPENVLSCALE ,
7270 WINED3DTSS_BUMPENVMAT00 ,
7271 WINED3DTSS_BUMPENVMAT01 ,
7272 WINED3DTSS_BUMPENVMAT10 ,
7273 WINED3DTSS_BUMPENVMAT11 ,
7274 WINED3DTSS_COLORARG0 ,
7275 WINED3DTSS_COLORARG1 ,
7276 WINED3DTSS_COLORARG2 ,
7277 WINED3DTSS_COLOROP ,
7278 WINED3DTSS_RESULTARG ,
7279 WINED3DTSS_TEXCOORDINDEX ,
7280 WINED3DTSS_TEXTURETRANSFORMFLAGS
7283 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7284 WINED3DSAMP_ADDRESSU ,
7285 WINED3DSAMP_ADDRESSV ,
7286 WINED3DSAMP_ADDRESSW ,
7287 WINED3DSAMP_BORDERCOLOR ,
7288 WINED3DSAMP_MAGFILTER ,
7289 WINED3DSAMP_MINFILTER ,
7290 WINED3DSAMP_MIPFILTER ,
7291 WINED3DSAMP_MIPMAPLODBIAS ,
7292 WINED3DSAMP_MAXMIPLEVEL ,
7293 WINED3DSAMP_MAXANISOTROPY ,
7294 WINED3DSAMP_SRGBTEXTURE ,
7295 WINED3DSAMP_ELEMENTINDEX
7298 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7299 WINED3DRS_AMBIENT ,
7300 WINED3DRS_AMBIENTMATERIALSOURCE ,
7301 WINED3DRS_CLIPPING ,
7302 WINED3DRS_CLIPPLANEENABLE ,
7303 WINED3DRS_COLORVERTEX ,
7304 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7305 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7306 WINED3DRS_FOGDENSITY ,
7307 WINED3DRS_FOGEND ,
7308 WINED3DRS_FOGSTART ,
7309 WINED3DRS_FOGTABLEMODE ,
7310 WINED3DRS_FOGVERTEXMODE ,
7311 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7312 WINED3DRS_LIGHTING ,
7313 WINED3DRS_LOCALVIEWER ,
7314 WINED3DRS_MULTISAMPLEANTIALIAS ,
7315 WINED3DRS_MULTISAMPLEMASK ,
7316 WINED3DRS_NORMALIZENORMALS ,
7317 WINED3DRS_PATCHEDGESTYLE ,
7318 WINED3DRS_POINTSCALE_A ,
7319 WINED3DRS_POINTSCALE_B ,
7320 WINED3DRS_POINTSCALE_C ,
7321 WINED3DRS_POINTSCALEENABLE ,
7322 WINED3DRS_POINTSIZE ,
7323 WINED3DRS_POINTSIZE_MAX ,
7324 WINED3DRS_POINTSIZE_MIN ,
7325 WINED3DRS_POINTSPRITEENABLE ,
7326 WINED3DRS_RANGEFOGENABLE ,
7327 WINED3DRS_SPECULARMATERIALSOURCE ,
7328 WINED3DRS_TWEENFACTOR ,
7329 WINED3DRS_VERTEXBLEND ,
7330 WINED3DRS_CULLMODE ,
7331 WINED3DRS_FOGCOLOR
7334 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7335 WINED3DTSS_TEXCOORDINDEX ,
7336 WINED3DTSS_TEXTURETRANSFORMFLAGS
7339 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7340 WINED3DSAMP_DMAPOFFSET
7343 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7344 DWORD rep = StateTable[state].representative;
7345 DWORD idx;
7346 BYTE shift;
7347 UINT i;
7348 WineD3DContext *context;
7350 if(!rep) return;
7351 for(i = 0; i < This->numContexts; i++) {
7352 context = This->contexts[i];
7353 if(isStateDirty(context, rep)) continue;
7355 context->dirtyArray[context->numDirtyEntries++] = rep;
7356 idx = rep >> 5;
7357 shift = rep & 0x1f;
7358 context->isStateDirty[idx] |= (1 << shift);