wined3d: Track shader constants in the shader backend.
[wine.git] / dlls / wined3d / device.c
blobdc7017b213d42797c8232bac9d15f632f2966d4a
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-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 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 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 object->resource.priority = 0; \
94 list_init(&object->resource.privateData); \
95 /* Check that we have enough video ram left */ \
96 if (Pool == WINED3DPOOL_DEFAULT) { \
97 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
98 WARN("Out of 'bogus' video memory\n"); \
99 HeapFree(GetProcessHeap(), 0, object); \
100 *pp##type = NULL; \
101 return WINED3DERR_OUTOFVIDEOMEMORY; \
103 WineD3DAdapterChangeGLRam(This, _size); \
105 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
106 if (object->resource.heapMemory == NULL && _size != 0) { \
107 FIXME("Out of memory!\n"); \
108 HeapFree(GetProcessHeap(), 0, object); \
109 *pp##type = NULL; \
110 return WINED3DERR_OUTOFVIDEOMEMORY; \
112 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
113 *pp##type = (IWineD3D##type *) object; \
114 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
115 TRACE("(%p) : Created resource %p\n", This, object); \
118 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
119 _basetexture.levels = Levels; \
120 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
121 _basetexture.LOD = 0; \
122 _basetexture.dirty = TRUE; \
123 _basetexture.is_srgb = FALSE; \
124 _basetexture.srgb_mode_change_count = 0; \
127 /**********************************************************
128 * Global variable / Constants follow
129 **********************************************************/
130 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
132 /**********************************************************
133 * IUnknown parts follows
134 **********************************************************/
136 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
140 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
141 if (IsEqualGUID(riid, &IID_IUnknown)
142 || IsEqualGUID(riid, &IID_IWineD3DBase)
143 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
144 IUnknown_AddRef(iface);
145 *ppobj = This;
146 return S_OK;
148 *ppobj = NULL;
149 return E_NOINTERFACE;
152 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
154 ULONG refCount = InterlockedIncrement(&This->ref);
156 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
157 return refCount;
160 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
162 ULONG refCount = InterlockedDecrement(&This->ref);
164 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
166 if (!refCount) {
167 /* TODO: Clean up all the surfaces and textures! */
168 /* NOTE: You must release the parent if the object was created via a callback
169 ** ***************************/
171 if (!list_empty(&This->resources)) {
172 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
173 dumpResources(&This->resources);
176 if(This->contexts) ERR("Context array not freed!\n");
177 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
178 This->haveHardwareCursor = FALSE;
180 IWineD3D_Release(This->wineD3D);
181 This->wineD3D = NULL;
182 HeapFree(GetProcessHeap(), 0, This);
183 TRACE("Freed device %p\n", This);
184 This = NULL;
186 return refCount;
189 /**********************************************************
190 * IWineD3DDevice implementation follows
191 **********************************************************/
192 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
194 *pParent = This->parent;
195 IUnknown_AddRef(This->parent);
196 return WINED3D_OK;
199 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
200 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
201 IUnknown *parent) {
202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
203 IWineD3DVertexBufferImpl *object;
204 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
205 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
206 BOOL conv;
208 if(Size == 0) {
209 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
210 *ppVertexBuffer = NULL;
211 return WINED3DERR_INVALIDCALL;
212 } else if(Pool == WINED3DPOOL_SCRATCH) {
213 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
214 * anyway, SCRATCH vertex buffers aren't usable anywhere
216 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
217 *ppVertexBuffer = NULL;
218 return WINED3DERR_INVALIDCALL;
221 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
223 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
224 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
226 object->fvf = FVF;
228 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
229 * drawStridedFast (half-life 2).
231 * Basically converting the vertices in the buffer is quite expensive, and observations
232 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
233 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
235 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
236 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
237 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
238 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
239 * dx7 apps.
240 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
241 * more. In this call we can convert dx7 buffers too.
243 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
244 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
245 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
246 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
247 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
248 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
249 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
250 } else if(dxVersion <= 7 && conv) {
251 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
252 } else {
253 object->Flags |= VBFLAG_CREATEVBO;
255 return WINED3D_OK;
258 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
259 GLenum error, glUsage;
260 TRACE("Creating VBO for Index Buffer %p\n", object);
262 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
263 * restored on the next draw
265 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
267 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
268 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
269 ENTER_GL();
271 while(glGetError());
273 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
274 error = glGetError();
275 if(error != GL_NO_ERROR || object->vbo == 0) {
276 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
277 goto out;
280 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
281 error = glGetError();
282 if(error != GL_NO_ERROR) {
283 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
284 goto out;
287 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
288 * copy no readback will be needed
290 glUsage = GL_STATIC_DRAW_ARB;
291 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
292 error = glGetError();
293 if(error != GL_NO_ERROR) {
294 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
295 goto out;
297 LEAVE_GL();
298 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
299 return;
301 out:
302 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
303 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
304 LEAVE_GL();
305 object->vbo = 0;
308 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
309 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
310 HANDLE *sharedHandle, IUnknown *parent) {
311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
312 IWineD3DIndexBufferImpl *object;
313 TRACE("(%p) Creating index buffer\n", This);
315 /* Allocate the storage for the device */
316 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
318 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
319 CreateIndexBufferVBO(This, object);
322 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
323 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
324 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
326 return WINED3D_OK;
329 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
332 IWineD3DStateBlockImpl *object;
333 int i, j;
334 HRESULT temp_result;
336 D3DCREATEOBJECTINSTANCE(object, StateBlock)
337 object->blockType = Type;
339 for(i = 0; i < LIGHTMAP_SIZE; i++) {
340 list_init(&object->lightMap[i]);
343 /* Special case - Used during initialization to produce a placeholder stateblock
344 so other functions called can update a state block */
345 if (Type == WINED3DSBT_INIT) {
346 /* Don't bother increasing the reference count otherwise a device will never
347 be freed due to circular dependencies */
348 return WINED3D_OK;
351 temp_result = allocate_shader_constants(object);
352 if (WINED3D_OK != temp_result)
353 return temp_result;
355 /* Otherwise, might as well set the whole state block to the appropriate values */
356 if (This->stateBlock != NULL)
357 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
358 else
359 memset(object->streamFreq, 1, sizeof(object->streamFreq));
361 /* Reset the ref and type after kludging it */
362 object->wineD3DDevice = This;
363 object->ref = 1;
364 object->blockType = Type;
366 TRACE("Updating changed flags appropriate for type %d\n", Type);
368 if (Type == WINED3DSBT_ALL) {
370 TRACE("ALL => Pretend everything has changed\n");
371 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
373 /* Lights are not part of the changed / set structure */
374 for(j = 0; j < LIGHTMAP_SIZE; j++) {
375 struct list *e;
376 LIST_FOR_EACH(e, &object->lightMap[j]) {
377 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
378 light->changed = TRUE;
379 light->enabledChanged = TRUE;
382 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
383 object->contained_render_states[j - 1] = j;
385 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
386 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
387 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
388 object->contained_transform_states[j - 1] = j;
390 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
391 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
392 object->contained_vs_consts_f[j] = j;
394 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
395 for(j = 0; j < MAX_CONST_I; j++) {
396 object->contained_vs_consts_i[j] = j;
398 object->num_contained_vs_consts_i = MAX_CONST_I;
399 for(j = 0; j < MAX_CONST_B; j++) {
400 object->contained_vs_consts_b[j] = j;
402 object->num_contained_vs_consts_b = MAX_CONST_B;
403 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
404 object->contained_ps_consts_f[j] = j;
406 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
407 for(j = 0; j < MAX_CONST_I; j++) {
408 object->contained_ps_consts_i[j] = j;
410 object->num_contained_ps_consts_i = MAX_CONST_I;
411 for(j = 0; j < MAX_CONST_B; j++) {
412 object->contained_ps_consts_b[j] = j;
414 object->num_contained_ps_consts_b = MAX_CONST_B;
415 for(i = 0; i < MAX_TEXTURES; i++) {
416 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
417 object->contained_tss_states[object->num_contained_tss_states].stage = i;
418 object->contained_tss_states[object->num_contained_tss_states].state = j;
419 object->num_contained_tss_states++;
422 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
423 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
424 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
425 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
426 object->num_contained_sampler_states++;
430 for(i = 0; i < MAX_STREAMS; i++) {
431 if(object->streamSource[i]) {
432 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
435 if(object->pIndexData) {
436 IWineD3DIndexBuffer_AddRef(object->pIndexData);
438 if(object->vertexShader) {
439 IWineD3DVertexShader_AddRef(object->vertexShader);
441 if(object->pixelShader) {
442 IWineD3DPixelShader_AddRef(object->pixelShader);
445 } else if (Type == WINED3DSBT_PIXELSTATE) {
447 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
448 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
450 object->changed.pixelShader = TRUE;
452 /* Pixel Shader Constants */
453 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
454 object->contained_ps_consts_f[i] = i;
455 object->changed.pixelShaderConstantsF[i] = TRUE;
457 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
458 for (i = 0; i < MAX_CONST_B; ++i) {
459 object->contained_ps_consts_b[i] = i;
460 object->changed.pixelShaderConstantsB |= (1 << i);
462 object->num_contained_ps_consts_b = MAX_CONST_B;
463 for (i = 0; i < MAX_CONST_I; ++i) {
464 object->contained_ps_consts_i[i] = i;
465 object->changed.pixelShaderConstantsI |= (1 << i);
467 object->num_contained_ps_consts_i = MAX_CONST_I;
469 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
470 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
471 object->contained_render_states[i] = SavedPixelStates_R[i];
473 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
474 for (j = 0; j < MAX_TEXTURES; j++) {
475 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
476 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
477 object->contained_tss_states[object->num_contained_tss_states].stage = j;
478 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
479 object->num_contained_tss_states++;
482 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
483 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
484 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
485 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
486 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
487 object->num_contained_sampler_states++;
490 if(object->pixelShader) {
491 IWineD3DPixelShader_AddRef(object->pixelShader);
494 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
495 * on them. This makes releasing the buffer easier
497 for(i = 0; i < MAX_STREAMS; i++) {
498 object->streamSource[i] = NULL;
500 object->pIndexData = NULL;
501 object->vertexShader = NULL;
503 } else if (Type == WINED3DSBT_VERTEXSTATE) {
505 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
506 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
508 object->changed.vertexShader = TRUE;
510 /* Vertex Shader Constants */
511 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
512 object->changed.vertexShaderConstantsF[i] = TRUE;
513 object->contained_vs_consts_f[i] = i;
515 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
516 for (i = 0; i < MAX_CONST_B; ++i) {
517 object->contained_vs_consts_b[i] = i;
518 object->changed.vertexShaderConstantsB |= (1 << i);
520 object->num_contained_vs_consts_b = MAX_CONST_B;
521 for (i = 0; i < MAX_CONST_I; ++i) {
522 object->contained_vs_consts_i[i] = i;
523 object->changed.vertexShaderConstantsI |= (1 << i);
525 object->num_contained_vs_consts_i = MAX_CONST_I;
526 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
527 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
528 object->contained_render_states[i] = SavedVertexStates_R[i];
530 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
531 for (j = 0; j < MAX_TEXTURES; j++) {
532 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
533 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
534 object->contained_tss_states[object->num_contained_tss_states].stage = j;
535 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
536 object->num_contained_tss_states++;
539 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
540 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
541 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
542 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
543 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
544 object->num_contained_sampler_states++;
548 for(j = 0; j < LIGHTMAP_SIZE; j++) {
549 struct list *e;
550 LIST_FOR_EACH(e, &object->lightMap[j]) {
551 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
552 light->changed = TRUE;
553 light->enabledChanged = TRUE;
557 for(i = 0; i < MAX_STREAMS; i++) {
558 if(object->streamSource[i]) {
559 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
562 if(object->vertexShader) {
563 IWineD3DVertexShader_AddRef(object->vertexShader);
565 object->pIndexData = NULL;
566 object->pixelShader = NULL;
567 } else {
568 FIXME("Unrecognized state block type %d\n", Type);
571 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
572 return WINED3D_OK;
575 /* ************************************
576 MSDN:
577 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
579 Discard
580 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
582 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
584 ******************************** */
586 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
588 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
589 unsigned int Size = 1;
590 const struct GlPixelFormatDesc *glDesc;
591 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
592 UINT mul_4w, mul_4h;
593 TRACE("(%p) Create surface\n",This);
595 /** FIXME: Check ranges on the inputs are valid
596 * MSDN
597 * MultisampleQuality
598 * [in] Quality level. The valid range is between zero and one less than the level
599 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
600 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
601 * values of paired render targets, depth stencil surfaces, and the MultiSample type
602 * must all match.
603 *******************************/
607 * TODO: Discard MSDN
608 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
610 * If this flag is set, the contents of the depth stencil buffer will be
611 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
612 * with a different depth surface.
614 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
615 ***************************/
617 if(MultisampleQuality > 0) {
618 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
619 MultisampleQuality=0;
622 /** FIXME: Check that the format is supported
623 * by the device.
624 *******************************/
626 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
627 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
628 * space!
629 *********************************/
630 mul_4w = (Width + 3) & ~3;
631 mul_4h = (Height + 3) & ~3;
632 if (WINED3DFMT_UNKNOWN == Format) {
633 Size = 0;
634 } else if (Format == WINED3DFMT_DXT1) {
635 /* DXT1 is half byte per pixel */
636 Size = (mul_4w * tableEntry->bpp * mul_4h) >> 1;
638 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
639 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
640 Format == WINED3DFMT_ATI2N) {
641 Size = (mul_4w * tableEntry->bpp * mul_4h);
642 } else {
643 /* The pitch is a multiple of 4 bytes */
644 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
645 Size *= Height;
648 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
650 /** Create and initialise the surface resource **/
651 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
652 /* "Standalone" surface */
653 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
655 object->currentDesc.Width = Width;
656 object->currentDesc.Height = Height;
657 object->currentDesc.MultiSampleType = MultiSample;
658 object->currentDesc.MultiSampleQuality = MultisampleQuality;
659 object->glDescription.level = Level;
660 object->heightscale = glDesc->heightscale != 0.0 ? glDesc->heightscale : 1.0;
661 list_init(&object->overlays);
663 /* Flags */
664 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
665 object->Flags |= Discard ? SFLAG_DISCARD : 0;
666 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
667 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
670 if (WINED3DFMT_UNKNOWN != Format) {
671 object->bytesPerPixel = tableEntry->bpp;
672 } else {
673 object->bytesPerPixel = 0;
676 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
678 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
680 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
681 * this function is too deep to need to care about things like this.
682 * Levels need to be checked too, and possibly Type since they all affect what can be done.
683 * ****************************************/
684 switch(Pool) {
685 case WINED3DPOOL_SCRATCH:
686 if(!Lockable)
687 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
688 "which are mutually exclusive, setting lockable to TRUE\n");
689 Lockable = TRUE;
690 break;
691 case WINED3DPOOL_SYSTEMMEM:
692 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
693 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
694 case WINED3DPOOL_MANAGED:
695 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
696 "Usage of DYNAMIC which are mutually exclusive, not doing "
697 "anything just telling you.\n");
698 break;
699 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
700 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
701 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
702 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
703 break;
704 default:
705 FIXME("(%p) Unknown pool %d\n", This, Pool);
706 break;
709 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
710 FIXME("Trying to create a render target that isn't in the default pool\n");
713 /* mark the texture as dirty so that it gets loaded first time around*/
714 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
715 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
716 This, Width, Height, Format, debug_d3dformat(Format),
717 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
719 /* Look at the implementation and set the correct Vtable */
720 switch(Impl) {
721 case SURFACE_OPENGL:
722 /* Check if a 3D adapter is available when creating gl surfaces */
723 if(!This->adapter) {
724 ERR("OpenGL surfaces are not available without opengl\n");
725 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
726 HeapFree(GetProcessHeap(), 0, object);
727 return WINED3DERR_NOTAVAILABLE;
729 break;
731 case SURFACE_GDI:
732 object->lpVtbl = &IWineGDISurface_Vtbl;
733 break;
735 default:
736 /* To be sure to catch this */
737 ERR("Unknown requested surface implementation %d!\n", Impl);
738 IWineD3DSurface_Release((IWineD3DSurface *) object);
739 return WINED3DERR_INVALIDCALL;
742 list_init(&object->renderbuffers);
744 /* Call the private setup routine */
745 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
749 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
750 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
751 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
752 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
755 IWineD3DTextureImpl *object;
756 unsigned int i;
757 UINT tmpW;
758 UINT tmpH;
759 HRESULT hr;
760 unsigned int pow2Width;
761 unsigned int pow2Height;
762 const struct GlPixelFormatDesc *glDesc;
763 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
765 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
766 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
767 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
769 /* TODO: It should only be possible to create textures for formats
770 that are reported as supported */
771 if (WINED3DFMT_UNKNOWN >= Format) {
772 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
773 return WINED3DERR_INVALIDCALL;
776 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
777 D3DINITIALIZEBASETEXTURE(object->baseTexture);
778 object->width = Width;
779 object->height = Height;
781 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
782 object->baseTexture.minMipLookup = minMipLookup;
783 object->baseTexture.magLookup = magLookup;
784 } else {
785 object->baseTexture.minMipLookup = minMipLookup_noFilter;
786 object->baseTexture.magLookup = magLookup_noFilter;
789 /** Non-power2 support **/
790 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
791 pow2Width = Width;
792 pow2Height = Height;
793 } else {
794 /* Find the nearest pow2 match */
795 pow2Width = pow2Height = 1;
796 while (pow2Width < Width) pow2Width <<= 1;
797 while (pow2Height < Height) pow2Height <<= 1;
799 if(pow2Width != Width || pow2Height != Height) {
800 if(Levels > 1) {
801 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
802 HeapFree(GetProcessHeap(), 0, object);
803 *ppTexture = NULL;
804 return WINED3DERR_INVALIDCALL;
805 } else {
806 Levels = 1;
811 /** FIXME: add support for real non-power-two if it's provided by the video card **/
812 /* Precalculated scaling for 'faked' non power of two texture coords.
813 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
814 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
815 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
817 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
818 object->baseTexture.pow2Matrix[0] = 1.0;
819 object->baseTexture.pow2Matrix[5] = 1.0;
820 object->baseTexture.pow2Matrix[10] = 1.0;
821 object->baseTexture.pow2Matrix[15] = 1.0;
822 object->target = GL_TEXTURE_2D;
823 object->cond_np2 = TRUE;
824 object->baseTexture.minMipLookup = minMipLookup_noFilter;
825 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
826 (Width != pow2Width || Height != pow2Height) &&
827 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
829 object->baseTexture.pow2Matrix[0] = (float)Width;
830 object->baseTexture.pow2Matrix[5] = (float)Height;
831 object->baseTexture.pow2Matrix[10] = 1.0;
832 object->baseTexture.pow2Matrix[15] = 1.0;
833 object->target = GL_TEXTURE_RECTANGLE_ARB;
834 object->cond_np2 = TRUE;
835 object->baseTexture.minMipLookup = minMipLookup_noFilter;
836 } else {
837 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
838 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
839 object->baseTexture.pow2Matrix[10] = 1.0;
840 object->baseTexture.pow2Matrix[15] = 1.0;
841 object->target = GL_TEXTURE_2D;
842 object->cond_np2 = FALSE;
844 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
846 /* Calculate levels for mip mapping */
847 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
848 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
849 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
850 return WINED3DERR_INVALIDCALL;
852 if(Levels > 1) {
853 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
854 return WINED3DERR_INVALIDCALL;
856 object->baseTexture.levels = 1;
857 } else if (Levels == 0) {
858 object->baseTexture.levels = wined3d_log2i(max(Width, Height)) + 1;
859 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
862 /* Generate all the surfaces */
863 tmpW = Width;
864 tmpH = Height;
865 for (i = 0; i < object->baseTexture.levels; i++)
867 /* use the callback to create the texture surface */
868 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
869 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
870 FIXME("Failed to create surface %p\n", object);
871 /* clean up */
872 object->surfaces[i] = NULL;
873 IWineD3DTexture_Release((IWineD3DTexture *)object);
875 *ppTexture = NULL;
876 return hr;
879 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
880 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
881 surface_set_texture_target(object->surfaces[i], object->target);
882 /* calculate the next mipmap level */
883 tmpW = max(1, tmpW >> 1);
884 tmpH = max(1, tmpH >> 1);
886 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
888 TRACE("(%p) : Created texture %p\n", This, object);
889 return WINED3D_OK;
892 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
893 UINT Width, UINT Height, UINT Depth,
894 UINT Levels, DWORD Usage,
895 WINED3DFORMAT Format, WINED3DPOOL Pool,
896 IWineD3DVolumeTexture **ppVolumeTexture,
897 HANDLE *pSharedHandle, IUnknown *parent,
898 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
901 IWineD3DVolumeTextureImpl *object;
902 unsigned int i;
903 UINT tmpW;
904 UINT tmpH;
905 UINT tmpD;
906 const struct GlPixelFormatDesc *glDesc;
908 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
910 /* TODO: It should only be possible to create textures for formats
911 that are reported as supported */
912 if (WINED3DFMT_UNKNOWN >= Format) {
913 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
914 return WINED3DERR_INVALIDCALL;
916 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
917 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
918 return WINED3DERR_INVALIDCALL;
921 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
922 D3DINITIALIZEBASETEXTURE(object->baseTexture);
924 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
925 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
927 /* Is NP2 support for volumes needed? */
928 object->baseTexture.pow2Matrix[ 0] = 1.0;
929 object->baseTexture.pow2Matrix[ 5] = 1.0;
930 object->baseTexture.pow2Matrix[10] = 1.0;
931 object->baseTexture.pow2Matrix[15] = 1.0;
933 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
934 object->baseTexture.minMipLookup = minMipLookup;
935 object->baseTexture.magLookup = magLookup;
936 } else {
937 object->baseTexture.minMipLookup = minMipLookup_noFilter;
938 object->baseTexture.magLookup = magLookup_noFilter;
941 /* Calculate levels for mip mapping */
942 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
943 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
944 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
945 return WINED3DERR_INVALIDCALL;
947 if(Levels > 1) {
948 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
949 return WINED3DERR_INVALIDCALL;
951 object->baseTexture.levels = 1;
952 } else if (Levels == 0) {
953 object->baseTexture.levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
954 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
957 /* Generate all the surfaces */
958 tmpW = Width;
959 tmpH = Height;
960 tmpD = Depth;
962 for (i = 0; i < object->baseTexture.levels; i++)
964 HRESULT hr;
965 /* Create the volume */
966 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
967 &object->volumes[i], pSharedHandle);
969 if(FAILED(hr)) {
970 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
971 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
972 *ppVolumeTexture = NULL;
973 return hr;
976 /* Set its container to this object */
977 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
979 /* calculate the next mipmap level */
980 tmpW = max(1, tmpW >> 1);
981 tmpH = max(1, tmpH >> 1);
982 tmpD = max(1, tmpD >> 1);
984 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
986 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
987 TRACE("(%p) : Created volume texture %p\n", This, object);
988 return WINED3D_OK;
991 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
992 UINT Width, UINT Height, UINT Depth,
993 DWORD Usage,
994 WINED3DFORMAT Format, WINED3DPOOL Pool,
995 IWineD3DVolume** ppVolume,
996 HANDLE* pSharedHandle, IUnknown *parent) {
998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
999 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1000 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1002 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1003 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1004 return WINED3DERR_INVALIDCALL;
1007 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1009 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1010 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1012 object->currentDesc.Width = Width;
1013 object->currentDesc.Height = Height;
1014 object->currentDesc.Depth = Depth;
1015 object->bytesPerPixel = formatDesc->bpp;
1017 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1018 object->lockable = TRUE;
1019 object->locked = FALSE;
1020 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1021 object->dirty = TRUE;
1023 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1026 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1027 UINT Levels, DWORD Usage,
1028 WINED3DFORMAT Format, WINED3DPOOL Pool,
1029 IWineD3DCubeTexture **ppCubeTexture,
1030 HANDLE *pSharedHandle, IUnknown *parent,
1031 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1034 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1035 unsigned int i, j;
1036 UINT tmpW;
1037 HRESULT hr;
1038 unsigned int pow2EdgeLength;
1039 const struct GlPixelFormatDesc *glDesc;
1040 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1042 /* TODO: It should only be possible to create textures for formats
1043 that are reported as supported */
1044 if (WINED3DFMT_UNKNOWN >= Format) {
1045 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1046 return WINED3DERR_INVALIDCALL;
1049 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1050 WARN("(%p) : Tried to create not supported cube texture\n", This);
1051 return WINED3DERR_INVALIDCALL;
1054 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1055 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1057 TRACE("(%p) Create Cube Texture\n", This);
1059 /* Find the nearest pow2 match */
1060 pow2EdgeLength = 1;
1061 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1063 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
1064 /* Precalculated scaling for 'faked' non power of two texture coords */
1065 object->baseTexture.pow2Matrix[ 0] = 1.0;
1066 object->baseTexture.pow2Matrix[ 5] = 1.0;
1067 object->baseTexture.pow2Matrix[10] = 1.0;
1068 object->baseTexture.pow2Matrix[15] = 1.0;
1069 } else {
1070 /* Precalculated scaling for 'faked' non power of two texture coords */
1071 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1072 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1073 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1074 object->baseTexture.pow2Matrix[15] = 1.0;
1077 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1078 object->baseTexture.minMipLookup = minMipLookup;
1079 object->baseTexture.magLookup = magLookup;
1080 } else {
1081 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1082 object->baseTexture.magLookup = magLookup_noFilter;
1085 /* Calculate levels for mip mapping */
1086 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1087 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1088 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1089 HeapFree(GetProcessHeap(), 0, object);
1090 *ppCubeTexture = NULL;
1092 return WINED3DERR_INVALIDCALL;
1094 if(Levels > 1) {
1095 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1096 HeapFree(GetProcessHeap(), 0, object);
1097 *ppCubeTexture = NULL;
1099 return WINED3DERR_INVALIDCALL;
1101 object->baseTexture.levels = 1;
1102 } else if (Levels == 0) {
1103 object->baseTexture.levels = wined3d_log2i(EdgeLength) + 1;
1104 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1107 /* Generate all the surfaces */
1108 tmpW = EdgeLength;
1109 for (i = 0; i < object->baseTexture.levels; i++) {
1111 /* Create the 6 faces */
1112 for (j = 0; j < 6; j++) {
1113 static const GLenum cube_targets[6] = {
1114 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1115 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1116 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1117 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1118 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1119 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1122 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1123 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1125 if(hr!= WINED3D_OK) {
1126 /* clean up */
1127 unsigned int k;
1128 unsigned int l;
1129 for (l = 0; l < j; l++) {
1130 IWineD3DSurface_Release(object->surfaces[l][i]);
1132 for (k = 0; k < i; k++) {
1133 for (l = 0; l < 6; l++) {
1134 IWineD3DSurface_Release(object->surfaces[l][k]);
1138 FIXME("(%p) Failed to create surface\n",object);
1139 HeapFree(GetProcessHeap(),0,object);
1140 *ppCubeTexture = NULL;
1141 return hr;
1143 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1144 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1145 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1147 tmpW = max(1, tmpW >> 1);
1149 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
1151 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1152 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1153 return WINED3D_OK;
1156 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1158 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1159 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1160 const IWineD3DQueryVtbl *vtable;
1162 /* Just a check to see if we support this type of query */
1163 switch(Type) {
1164 case WINED3DQUERYTYPE_OCCLUSION:
1165 TRACE("(%p) occlusion query\n", This);
1166 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1167 hr = WINED3D_OK;
1168 else
1169 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1171 vtable = &IWineD3DOcclusionQuery_Vtbl;
1172 break;
1174 case WINED3DQUERYTYPE_EVENT:
1175 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1176 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1177 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1179 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1181 vtable = &IWineD3DEventQuery_Vtbl;
1182 hr = WINED3D_OK;
1183 break;
1185 case WINED3DQUERYTYPE_VCACHE:
1186 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1187 case WINED3DQUERYTYPE_VERTEXSTATS:
1188 case WINED3DQUERYTYPE_TIMESTAMP:
1189 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1190 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1191 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1192 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1193 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1194 case WINED3DQUERYTYPE_PIXELTIMINGS:
1195 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1196 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1197 default:
1198 /* Use the base Query vtable until we have a special one for each query */
1199 vtable = &IWineD3DQuery_Vtbl;
1200 FIXME("(%p) Unhandled query type %d\n", This, Type);
1202 if(NULL == ppQuery || hr != WINED3D_OK) {
1203 return hr;
1206 D3DCREATEOBJECTINSTANCE(object, Query)
1207 object->lpVtbl = vtable;
1208 object->type = Type;
1209 object->state = QUERY_CREATED;
1210 /* allocated the 'extended' data based on the type of query requested */
1211 switch(Type){
1212 case WINED3DQUERYTYPE_OCCLUSION:
1213 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1214 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1216 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1217 TRACE("(%p) Allocating data for an occlusion query\n", This);
1219 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1220 ENTER_GL();
1221 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1222 LEAVE_GL();
1223 break;
1225 case WINED3DQUERYTYPE_EVENT:
1226 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1227 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1229 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1230 ENTER_GL();
1231 if(GL_SUPPORT(APPLE_FENCE)) {
1232 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1233 checkGLcall("glGenFencesAPPLE");
1234 } else if(GL_SUPPORT(NV_FENCE)) {
1235 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1236 checkGLcall("glGenFencesNV");
1238 LEAVE_GL();
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 object->extendedData = 0;
1255 FIXME("(%p) Unhandled query type %d\n",This , Type);
1257 TRACE("(%p) : Created Query %p\n", This, object);
1258 return WINED3D_OK;
1261 /*****************************************************************************
1262 * IWineD3DDeviceImpl_SetupFullscreenWindow
1264 * Helper function that modifies a HWND's Style and ExStyle for proper
1265 * fullscreen use.
1267 * Params:
1268 * iface: Pointer to the IWineD3DDevice interface
1269 * window: Window to setup
1271 *****************************************************************************/
1272 static LONG fullscreen_style(LONG orig_style) {
1273 LONG style = orig_style;
1274 style &= ~WS_CAPTION;
1275 style &= ~WS_THICKFRAME;
1277 /* Make sure the window is managed, otherwise we won't get keyboard input */
1278 style |= WS_POPUP | WS_SYSMENU;
1280 return style;
1283 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1284 LONG exStyle = orig_exStyle;
1286 /* Filter out window decorations */
1287 exStyle &= ~WS_EX_WINDOWEDGE;
1288 exStyle &= ~WS_EX_CLIENTEDGE;
1290 return exStyle;
1293 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1296 LONG style, exStyle;
1297 /* Don't do anything if an original style is stored.
1298 * That shouldn't happen
1300 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1301 if (This->style || This->exStyle) {
1302 ERR("(%p): Want to change the window parameters of HWND %p, but "
1303 "another style is stored for restoration afterwards\n", This, window);
1306 /* Get the parameters and save them */
1307 style = GetWindowLongW(window, GWL_STYLE);
1308 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1309 This->style = style;
1310 This->exStyle = exStyle;
1312 style = fullscreen_style(style);
1313 exStyle = fullscreen_exStyle(exStyle);
1315 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1316 This->style, This->exStyle, style, exStyle);
1318 SetWindowLongW(window, GWL_STYLE, style);
1319 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1321 /* Inform the window about the update. */
1322 SetWindowPos(window, HWND_TOP, 0, 0,
1323 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1326 /*****************************************************************************
1327 * IWineD3DDeviceImpl_RestoreWindow
1329 * Helper function that restores a windows' properties when taking it out
1330 * of fullscreen mode
1332 * Params:
1333 * iface: Pointer to the IWineD3DDevice interface
1334 * window: Window to setup
1336 *****************************************************************************/
1337 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1339 LONG style, exStyle;
1341 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1342 * switch, do nothing
1344 if (!This->style && !This->exStyle) return;
1346 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1347 This, window, This->style, This->exStyle);
1349 style = GetWindowLongW(window, GWL_STYLE);
1350 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1352 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1353 * Some applications change it before calling Reset() when switching between windowed and
1354 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1356 if(style == fullscreen_style(This->style) &&
1357 exStyle == fullscreen_style(This->exStyle)) {
1358 SetWindowLongW(window, GWL_STYLE, This->style);
1359 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1362 /* Delete the old values */
1363 This->style = 0;
1364 This->exStyle = 0;
1366 /* Inform the window about the update */
1367 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1368 0, 0, 0, 0, /* Pos, Size, ignored */
1369 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1372 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1373 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice* iface,
1374 WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1375 IUnknown* parent, D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1376 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil, WINED3DSURFTYPE surface_type)
1378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1380 HDC hDc;
1381 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1382 HRESULT hr;
1383 IUnknown *bufferParent;
1384 BOOL displaymode_set = FALSE;
1385 WINED3DDISPLAYMODE Mode;
1386 const StaticPixelFormatDesc *formatDesc;
1388 TRACE("(%p) : Created Additional Swap Chain\n", This);
1390 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1391 * does a device hold a reference to a swap chain giving them a lifetime of the device
1392 * or does the swap chain notify the device of its destruction.
1393 *******************************/
1395 /* Check the params */
1396 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1397 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1398 return WINED3DERR_INVALIDCALL;
1399 } else if (pPresentationParameters->BackBufferCount > 1) {
1400 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");
1403 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1404 switch(surface_type) {
1405 case SURFACE_GDI:
1406 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1407 break;
1408 case SURFACE_OPENGL:
1409 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1410 break;
1411 case SURFACE_UNKNOWN:
1412 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1413 return WINED3DERR_INVALIDCALL;
1416 /*********************
1417 * Lookup the window Handle and the relating X window handle
1418 ********************/
1420 /* Setup hwnd we are using, plus which display this equates to */
1421 object->win_handle = pPresentationParameters->hDeviceWindow;
1422 if (!object->win_handle) {
1423 object->win_handle = This->createParms.hFocusWindow;
1425 if(!pPresentationParameters->Windowed && object->win_handle) {
1426 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1427 pPresentationParameters->BackBufferWidth,
1428 pPresentationParameters->BackBufferHeight);
1431 hDc = GetDC(object->win_handle);
1432 TRACE("Using hDc %p\n", hDc);
1434 if (NULL == hDc) {
1435 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1436 return WINED3DERR_NOTAVAILABLE;
1439 /* Get info on the current display setup */
1440 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1441 object->orig_width = Mode.Width;
1442 object->orig_height = Mode.Height;
1443 object->orig_fmt = Mode.Format;
1444 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
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(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 (SUCCEEDED(hr)) {
1489 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1490 if(surface_type == SURFACE_OPENGL) {
1491 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1493 } else {
1494 ERR("Failed to create the front buffer\n");
1495 goto error;
1498 /*********************
1499 * Windowed / Fullscreen
1500 *******************/
1503 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1504 * so we should really check to see if there is a fullscreen swapchain already
1505 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1506 **************************************/
1508 if (!pPresentationParameters->Windowed) {
1509 WINED3DDISPLAYMODE mode;
1512 /* Change the display settings */
1513 mode.Width = pPresentationParameters->BackBufferWidth;
1514 mode.Height = pPresentationParameters->BackBufferHeight;
1515 mode.Format = pPresentationParameters->BackBufferFormat;
1516 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1518 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1519 displaymode_set = TRUE;
1523 * Create an opengl context for the display visual
1524 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1525 * use different properties after that point in time. FIXME: How to handle when requested format
1526 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1527 * it chooses is identical to the one already being used!
1528 **********************************/
1529 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1531 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1532 if(!object->context) {
1533 ERR("Failed to create the context array\n");
1534 hr = E_OUTOFMEMORY;
1535 goto error;
1537 object->num_contexts = 1;
1539 if(surface_type == SURFACE_OPENGL) {
1540 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1541 if (!object->context[0]) {
1542 ERR("Failed to create a new context\n");
1543 hr = WINED3DERR_NOTAVAILABLE;
1544 goto error;
1545 } else {
1546 TRACE("Context created (HWND=%p, glContext=%p)\n",
1547 object->win_handle, object->context[0]->glCtx);
1551 /*********************
1552 * Create the back, front and stencil buffers
1553 *******************/
1554 if(object->presentParms.BackBufferCount > 0) {
1555 UINT i;
1557 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1558 if(!object->backBuffer) {
1559 ERR("Out of memory\n");
1560 hr = E_OUTOFMEMORY;
1561 goto error;
1564 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1565 TRACE("calling rendertarget CB\n");
1566 hr = D3DCB_CreateRenderTarget(This->parent,
1567 parent,
1568 object->presentParms.BackBufferWidth,
1569 object->presentParms.BackBufferHeight,
1570 object->presentParms.BackBufferFormat,
1571 object->presentParms.MultiSampleType,
1572 object->presentParms.MultiSampleQuality,
1573 TRUE /* Lockable */,
1574 &object->backBuffer[i],
1575 NULL /* pShared (always null)*/);
1576 if(SUCCEEDED(hr)) {
1577 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1578 } else {
1579 ERR("Cannot create new back buffer\n");
1580 goto error;
1582 if(surface_type == SURFACE_OPENGL) {
1583 ENTER_GL();
1584 glDrawBuffer(GL_BACK);
1585 checkGLcall("glDrawBuffer(GL_BACK)");
1586 LEAVE_GL();
1589 } else {
1590 object->backBuffer = NULL;
1592 /* Single buffering - draw to front buffer */
1593 if(surface_type == SURFACE_OPENGL) {
1594 ENTER_GL();
1595 glDrawBuffer(GL_FRONT);
1596 checkGLcall("glDrawBuffer(GL_FRONT)");
1597 LEAVE_GL();
1601 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1602 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1603 TRACE("Creating depth stencil buffer\n");
1604 if (This->auto_depth_stencil_buffer == NULL ) {
1605 hr = D3DCB_CreateDepthStencil(This->parent,
1606 parent,
1607 object->presentParms.BackBufferWidth,
1608 object->presentParms.BackBufferHeight,
1609 object->presentParms.AutoDepthStencilFormat,
1610 object->presentParms.MultiSampleType,
1611 object->presentParms.MultiSampleQuality,
1612 FALSE /* FIXME: Discard */,
1613 &This->auto_depth_stencil_buffer,
1614 NULL /* pShared (always null)*/ );
1615 if (SUCCEEDED(hr)) {
1616 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1617 } else {
1618 ERR("Failed to create the auto depth stencil\n");
1619 goto error;
1624 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1626 TRACE("Created swapchain %p\n", object);
1627 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1628 return WINED3D_OK;
1630 error:
1631 if (displaymode_set) {
1632 DEVMODEW devmode;
1633 RECT clip_rc;
1635 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1636 ClipCursor(NULL);
1638 /* Change the display settings */
1639 memset(&devmode, 0, sizeof(devmode));
1640 devmode.dmSize = sizeof(devmode);
1641 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1642 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1643 devmode.dmPelsWidth = object->orig_width;
1644 devmode.dmPelsHeight = object->orig_height;
1645 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1648 if (object->backBuffer) {
1649 UINT i;
1650 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1651 if(object->backBuffer[i]) {
1652 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1653 IUnknown_Release(bufferParent); /* once for the get parent */
1654 if (IUnknown_Release(bufferParent) > 0) {
1655 FIXME("(%p) Something's still holding the back buffer\n",This);
1659 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1660 object->backBuffer = NULL;
1662 if(object->context && object->context[0])
1663 DestroyContext(This, object->context[0]);
1664 if(object->frontBuffer) {
1665 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1666 IUnknown_Release(bufferParent); /* once for the get parent */
1667 if (IUnknown_Release(bufferParent) > 0) {
1668 FIXME("(%p) Something's still holding the front buffer\n",This);
1671 HeapFree(GetProcessHeap(), 0, object);
1672 return hr;
1675 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1676 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1678 TRACE("(%p)\n", This);
1680 return This->NumberOfSwapChains;
1683 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1685 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1687 if(iSwapChain < This->NumberOfSwapChains) {
1688 *pSwapChain = This->swapchains[iSwapChain];
1689 IWineD3DSwapChain_AddRef(*pSwapChain);
1690 TRACE("(%p) returning %p\n", This, *pSwapChain);
1691 return WINED3D_OK;
1692 } else {
1693 TRACE("Swapchain out of range\n");
1694 *pSwapChain = NULL;
1695 return WINED3DERR_INVALIDCALL;
1699 /*****
1700 * Vertex Declaration
1701 *****/
1702 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1703 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1705 IWineD3DVertexDeclarationImpl *object = NULL;
1706 HRESULT hr = WINED3D_OK;
1708 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1709 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1711 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1713 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1714 if(FAILED(hr)) {
1715 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1716 *ppVertexDeclaration = NULL;
1719 return hr;
1722 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1723 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1725 unsigned int idx, idx2;
1726 unsigned int offset;
1727 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1728 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1729 BOOL has_blend_idx = has_blend &&
1730 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1731 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1732 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1733 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1734 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1735 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1736 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1738 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1739 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1741 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1742 WINED3DVERTEXELEMENT *elements = NULL;
1744 unsigned int size;
1745 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1746 if (has_blend_idx) num_blends--;
1748 /* Compute declaration size */
1749 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1750 has_psize + has_diffuse + has_specular + num_textures + 1;
1752 /* convert the declaration */
1753 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1754 if (!elements)
1755 return 0;
1757 elements[size-1] = end_element;
1758 idx = 0;
1759 if (has_pos) {
1760 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1761 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1762 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1764 else {
1765 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1766 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1768 elements[idx].UsageIndex = 0;
1769 idx++;
1771 if (has_blend && (num_blends > 0)) {
1772 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1773 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1774 else {
1775 switch(num_blends) {
1776 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
1777 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
1778 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
1779 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
1780 default:
1781 ERR("Unexpected amount of blend values: %u\n", num_blends);
1784 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1785 elements[idx].UsageIndex = 0;
1786 idx++;
1788 if (has_blend_idx) {
1789 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1790 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1791 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1792 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1793 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1794 else
1795 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1796 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1797 elements[idx].UsageIndex = 0;
1798 idx++;
1800 if (has_normal) {
1801 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1802 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1803 elements[idx].UsageIndex = 0;
1804 idx++;
1806 if (has_psize) {
1807 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1808 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1809 elements[idx].UsageIndex = 0;
1810 idx++;
1812 if (has_diffuse) {
1813 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1814 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1815 elements[idx].UsageIndex = 0;
1816 idx++;
1818 if (has_specular) {
1819 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1820 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1821 elements[idx].UsageIndex = 1;
1822 idx++;
1824 for (idx2 = 0; idx2 < num_textures; idx2++) {
1825 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1826 switch (numcoords) {
1827 case WINED3DFVF_TEXTUREFORMAT1:
1828 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1829 break;
1830 case WINED3DFVF_TEXTUREFORMAT2:
1831 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1832 break;
1833 case WINED3DFVF_TEXTUREFORMAT3:
1834 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1835 break;
1836 case WINED3DFVF_TEXTUREFORMAT4:
1837 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1838 break;
1840 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1841 elements[idx].UsageIndex = idx2;
1842 idx++;
1845 /* Now compute offsets, and initialize the rest of the fields */
1846 for (idx = 0, offset = 0; idx < size-1; idx++) {
1847 elements[idx].Stream = 0;
1848 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1849 elements[idx].Offset = offset;
1850 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1853 *ppVertexElements = elements;
1854 return size;
1857 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1858 WINED3DVERTEXELEMENT* elements = NULL;
1859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1860 unsigned int size;
1861 DWORD hr;
1863 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1864 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1866 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1867 HeapFree(GetProcessHeap(), 0, elements);
1868 if (hr != S_OK) return hr;
1870 return WINED3D_OK;
1873 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1875 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1876 HRESULT hr = WINED3D_OK;
1878 if (!pFunction) return WINED3DERR_INVALIDCALL;
1880 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1881 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1883 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1885 if (vertex_declaration) {
1886 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1889 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1891 if (WINED3D_OK != hr) {
1892 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1893 IWineD3DVertexShader_Release(*ppVertexShader);
1894 return WINED3DERR_INVALIDCALL;
1896 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
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 if (!pFunction) return WINED3DERR_INVALIDCALL;
1908 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1909 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1910 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1911 if (WINED3D_OK == hr) {
1912 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1913 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1914 } else {
1915 WARN("(%p) : Failed to create pixel shader\n", This);
1918 return hr;
1921 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1922 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1925 IWineD3DPaletteImpl *object;
1926 HRESULT hr;
1927 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1929 /* Create the new object */
1930 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1931 if(!object) {
1932 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1933 return E_OUTOFMEMORY;
1936 object->lpVtbl = &IWineD3DPalette_Vtbl;
1937 object->ref = 1;
1938 object->Flags = Flags;
1939 object->parent = Parent;
1940 object->wineD3DDevice = This;
1941 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1943 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1945 if(!object->hpal) {
1946 HeapFree( GetProcessHeap(), 0, object);
1947 return E_OUTOFMEMORY;
1950 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1951 if(FAILED(hr)) {
1952 IWineD3DPalette_Release((IWineD3DPalette *) object);
1953 return hr;
1956 *Palette = (IWineD3DPalette *) object;
1958 return WINED3D_OK;
1961 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1962 HBITMAP hbm;
1963 BITMAP bm;
1964 HRESULT hr;
1965 HDC dcb = NULL, dcs = NULL;
1966 WINEDDCOLORKEY colorkey;
1968 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1969 if(hbm)
1971 GetObjectA(hbm, sizeof(BITMAP), &bm);
1972 dcb = CreateCompatibleDC(NULL);
1973 if(!dcb) goto out;
1974 SelectObject(dcb, hbm);
1976 else
1978 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1979 * couldn't be loaded
1981 memset(&bm, 0, sizeof(bm));
1982 bm.bmWidth = 32;
1983 bm.bmHeight = 32;
1986 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1987 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1988 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1989 if(FAILED(hr)) {
1990 ERR("Wine logo requested, but failed to create surface\n");
1991 goto out;
1994 if(dcb) {
1995 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1996 if(FAILED(hr)) goto out;
1997 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1998 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2000 colorkey.dwColorSpaceLowValue = 0;
2001 colorkey.dwColorSpaceHighValue = 0;
2002 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2003 } else {
2004 /* Fill the surface with a white color to show that wined3d is there */
2005 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2008 out:
2009 if(dcb) {
2010 DeleteDC(dcb);
2012 if(hbm) {
2013 DeleteObject(hbm);
2015 return;
2018 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2019 unsigned int i;
2020 /* Under DirectX you can have texture stage operations even if no texture is
2021 bound, whereas opengl will only do texture operations when a valid texture is
2022 bound. We emulate this by creating dummy textures and binding them to each
2023 texture stage, but disable all stages by default. Hence if a stage is enabled
2024 then the default texture will kick in until replaced by a SetTexture call */
2025 ENTER_GL();
2027 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2028 /* The dummy texture does not have client storage backing */
2029 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2030 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2032 for (i = 0; i < GL_LIMITS(textures); i++) {
2033 GLubyte white = 255;
2035 /* Make appropriate texture active */
2036 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2037 checkGLcall("glActiveTextureARB");
2039 /* Generate an opengl texture name */
2040 glGenTextures(1, &This->dummyTextureName[i]);
2041 checkGLcall("glGenTextures");
2042 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2044 /* Generate a dummy 2d texture (not using 1d because they cause many
2045 * DRI drivers fall back to sw) */
2046 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2047 checkGLcall("glBindTexture");
2049 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2050 checkGLcall("glTexImage2D");
2052 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2053 /* Reenable because if supported it is enabled by default */
2054 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2055 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2058 LEAVE_GL();
2061 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2063 IWineD3DSwapChainImpl *swapchain = NULL;
2064 HRESULT hr;
2065 DWORD state;
2066 unsigned int i;
2068 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateSwapChain);
2069 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2070 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2072 /* TODO: Test if OpenGL is compiled in and loaded */
2074 TRACE("(%p) : Creating stateblock\n", This);
2075 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2076 hr = IWineD3DDevice_CreateStateBlock(iface,
2077 WINED3DSBT_INIT,
2078 (IWineD3DStateBlock **)&This->stateBlock,
2079 NULL);
2080 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2081 WARN("Failed to create stateblock\n");
2082 goto err_out;
2084 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2085 This->updateStateBlock = This->stateBlock;
2086 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2088 hr = allocate_shader_constants(This->updateStateBlock);
2089 if (WINED3D_OK != hr) {
2090 goto err_out;
2093 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2094 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2096 This->NumberOfPalettes = 1;
2097 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2098 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2099 ERR("Out of memory!\n");
2100 goto err_out;
2102 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2103 if(!This->palettes[0]) {
2104 ERR("Out of memory!\n");
2105 goto err_out;
2107 for (i = 0; i < 256; ++i) {
2108 This->palettes[0][i].peRed = 0xFF;
2109 This->palettes[0][i].peGreen = 0xFF;
2110 This->palettes[0][i].peBlue = 0xFF;
2111 This->palettes[0][i].peFlags = 0xFF;
2113 This->currentPalette = 0;
2115 /* Initialize the texture unit mapping to a 1:1 mapping */
2116 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2117 if (state < GL_LIMITS(fragment_samplers)) {
2118 This->texUnitMap[state] = state;
2119 This->rev_tex_unit_map[state] = state;
2120 } else {
2121 This->texUnitMap[state] = -1;
2122 This->rev_tex_unit_map[state] = -1;
2126 /* Setup the implicit swapchain */
2127 TRACE("Creating implicit swapchain\n");
2128 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2129 if (FAILED(hr) || !swapchain) {
2130 WARN("Failed to create implicit swapchain\n");
2131 goto err_out;
2134 This->NumberOfSwapChains = 1;
2135 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2136 if(!This->swapchains) {
2137 ERR("Out of memory!\n");
2138 goto err_out;
2140 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2142 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2143 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2144 This->render_targets[0] = swapchain->backBuffer[0];
2145 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2147 else {
2148 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2149 This->render_targets[0] = swapchain->frontBuffer;
2150 This->lastActiveRenderTarget = swapchain->frontBuffer;
2152 IWineD3DSurface_AddRef(This->render_targets[0]);
2153 This->activeContext = swapchain->context[0];
2154 This->lastThread = GetCurrentThreadId();
2156 /* Depth Stencil support */
2157 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2158 if (NULL != This->stencilBufferTarget) {
2159 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2162 hr = This->shader_backend->shader_alloc_private(iface);
2163 if(FAILED(hr)) {
2164 TRACE("Shader private data couldn't be allocated\n");
2165 goto err_out;
2167 hr = This->frag_pipe->alloc_private(iface);
2168 if(FAILED(hr)) {
2169 TRACE("Fragment pipeline private data couldn't be allocated\n");
2170 goto err_out;
2172 hr = This->blitter->alloc_private(iface);
2173 if(FAILED(hr)) {
2174 TRACE("Blitter private data couldn't be allocated\n");
2175 goto err_out;
2178 /* Set up some starting GL setup */
2180 /* Setup all the devices defaults */
2181 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2182 create_dummy_textures(This);
2184 ENTER_GL();
2186 { /* Set a default viewport */
2187 WINED3DVIEWPORT vp;
2188 vp.X = 0;
2189 vp.Y = 0;
2190 vp.Width = pPresentationParameters->BackBufferWidth;
2191 vp.Height = pPresentationParameters->BackBufferHeight;
2192 vp.MinZ = 0.0f;
2193 vp.MaxZ = 1.0f;
2194 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2197 /* Initialize the current view state */
2198 This->view_ident = 1;
2199 This->contexts[0]->last_was_rhw = 0;
2200 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2201 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2203 switch(wined3d_settings.offscreen_rendering_mode) {
2204 case ORM_FBO:
2205 case ORM_PBUFFER:
2206 This->offscreenBuffer = GL_BACK;
2207 break;
2209 case ORM_BACKBUFFER:
2211 if(This->activeContext->aux_buffers > 0) {
2212 TRACE("Using auxilliary buffer for offscreen rendering\n");
2213 This->offscreenBuffer = GL_AUX0;
2214 } else {
2215 TRACE("Using back buffer for offscreen rendering\n");
2216 This->offscreenBuffer = GL_BACK;
2221 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2222 LEAVE_GL();
2224 /* Clear the screen */
2225 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2226 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2227 0x00, 1.0, 0);
2229 This->d3d_initialized = TRUE;
2231 if(wined3d_settings.logo) {
2232 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2234 This->highest_dirty_ps_const = 0;
2235 This->highest_dirty_vs_const = 0;
2236 return WINED3D_OK;
2238 err_out:
2239 HeapFree(GetProcessHeap(), 0, This->render_targets);
2240 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2241 HeapFree(GetProcessHeap(), 0, This->swapchains);
2242 This->NumberOfSwapChains = 0;
2243 if(This->palettes) {
2244 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2245 HeapFree(GetProcessHeap(), 0, This->palettes);
2247 This->NumberOfPalettes = 0;
2248 if(swapchain) {
2249 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2251 if(This->stateBlock) {
2252 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2253 This->stateBlock = NULL;
2255 if (This->blit_priv) {
2256 This->blitter->free_private(iface);
2258 if (This->fragment_priv) {
2259 This->frag_pipe->free_private(iface);
2261 if (This->shader_priv) {
2262 This->shader_backend->shader_free_private(iface);
2264 return hr;
2267 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2269 IWineD3DSwapChainImpl *swapchain = NULL;
2270 HRESULT hr;
2272 /* Setup the implicit swapchain */
2273 TRACE("Creating implicit swapchain\n");
2274 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2275 if (FAILED(hr) || !swapchain) {
2276 WARN("Failed to create implicit swapchain\n");
2277 goto err_out;
2280 This->NumberOfSwapChains = 1;
2281 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2282 if(!This->swapchains) {
2283 ERR("Out of memory!\n");
2284 goto err_out;
2286 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2287 return WINED3D_OK;
2289 err_out:
2290 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2291 return hr;
2294 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2296 int sampler;
2297 UINT i;
2298 TRACE("(%p)\n", This);
2300 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2302 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2303 * it was created. Thus make sure a context is active for the glDelete* calls
2305 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2307 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2309 TRACE("Deleting high order patches\n");
2310 for(i = 0; i < PATCHMAP_SIZE; i++) {
2311 struct list *e1, *e2;
2312 struct WineD3DRectPatch *patch;
2313 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2314 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2315 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2319 /* Delete the palette conversion shader if it is around */
2320 if(This->paletteConversionShader) {
2321 ENTER_GL();
2322 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2323 LEAVE_GL();
2324 This->paletteConversionShader = 0;
2327 /* Delete the pbuffer context if there is any */
2328 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2330 /* Delete the mouse cursor texture */
2331 if(This->cursorTexture) {
2332 ENTER_GL();
2333 glDeleteTextures(1, &This->cursorTexture);
2334 LEAVE_GL();
2335 This->cursorTexture = 0;
2338 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2339 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2341 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2342 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2345 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2346 * private data, it might contain opengl pointers
2348 if(This->depth_blt_texture) {
2349 glDeleteTextures(1, &This->depth_blt_texture);
2350 This->depth_blt_texture = 0;
2352 if (This->depth_blt_rb) {
2353 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2354 This->depth_blt_rb = 0;
2355 This->depth_blt_rb_w = 0;
2356 This->depth_blt_rb_h = 0;
2359 /* Release the update stateblock */
2360 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2361 if(This->updateStateBlock != This->stateBlock)
2362 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2364 This->updateStateBlock = NULL;
2366 { /* because were not doing proper internal refcounts releasing the primary state block
2367 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2368 to set this->stateBlock = NULL; first */
2369 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2370 This->stateBlock = NULL;
2372 /* Release the stateblock */
2373 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2374 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2378 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2379 This->blitter->free_private(iface);
2380 This->frag_pipe->free_private(iface);
2381 This->shader_backend->shader_free_private(iface);
2383 /* Release the buffers (with sanity checks)*/
2384 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2385 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2386 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2387 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2389 This->stencilBufferTarget = NULL;
2391 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2392 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2393 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2395 TRACE("Setting rendertarget to NULL\n");
2396 This->render_targets[0] = NULL;
2398 if (This->auto_depth_stencil_buffer) {
2399 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2400 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2402 This->auto_depth_stencil_buffer = NULL;
2405 for(i=0; i < This->NumberOfSwapChains; i++) {
2406 TRACE("Releasing the implicit swapchain %d\n", i);
2407 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2408 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2412 HeapFree(GetProcessHeap(), 0, This->swapchains);
2413 This->swapchains = NULL;
2414 This->NumberOfSwapChains = 0;
2416 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2417 HeapFree(GetProcessHeap(), 0, This->palettes);
2418 This->palettes = NULL;
2419 This->NumberOfPalettes = 0;
2421 HeapFree(GetProcessHeap(), 0, This->render_targets);
2422 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2423 This->render_targets = NULL;
2424 This->draw_buffers = NULL;
2426 This->d3d_initialized = FALSE;
2427 return WINED3D_OK;
2430 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2432 unsigned int i;
2434 for(i=0; i < This->NumberOfSwapChains; i++) {
2435 TRACE("Releasing the implicit swapchain %d\n", i);
2436 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2437 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2441 HeapFree(GetProcessHeap(), 0, This->swapchains);
2442 This->swapchains = NULL;
2443 This->NumberOfSwapChains = 0;
2444 return WINED3D_OK;
2447 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2448 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2449 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2451 * There is no way to deactivate thread safety once it is enabled.
2453 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2456 /*For now just store the flag(needed in case of ddraw) */
2457 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2459 return;
2462 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2463 const WINED3DDISPLAYMODE* pMode) {
2464 DEVMODEW devmode;
2465 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2466 LONG ret;
2467 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2468 RECT clip_rc;
2470 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2472 /* Resize the screen even without a window:
2473 * The app could have unset it with SetCooperativeLevel, but not called
2474 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2475 * but we don't have any hwnd
2478 memset(&devmode, 0, sizeof(devmode));
2479 devmode.dmSize = sizeof(devmode);
2480 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2481 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2482 devmode.dmPelsWidth = pMode->Width;
2483 devmode.dmPelsHeight = pMode->Height;
2485 devmode.dmDisplayFrequency = pMode->RefreshRate;
2486 if (pMode->RefreshRate != 0) {
2487 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2490 /* Only change the mode if necessary */
2491 if( (This->ddraw_width == pMode->Width) &&
2492 (This->ddraw_height == pMode->Height) &&
2493 (This->ddraw_format == pMode->Format) &&
2494 (pMode->RefreshRate == 0) ) {
2495 return WINED3D_OK;
2498 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2499 if (ret != DISP_CHANGE_SUCCESSFUL) {
2500 if(devmode.dmDisplayFrequency != 0) {
2501 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2502 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2503 devmode.dmDisplayFrequency = 0;
2504 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2506 if(ret != DISP_CHANGE_SUCCESSFUL) {
2507 return WINED3DERR_NOTAVAILABLE;
2511 /* Store the new values */
2512 This->ddraw_width = pMode->Width;
2513 This->ddraw_height = pMode->Height;
2514 This->ddraw_format = pMode->Format;
2516 /* And finally clip mouse to our screen */
2517 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2518 ClipCursor(&clip_rc);
2520 return WINED3D_OK;
2523 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2525 *ppD3D= This->wineD3D;
2526 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2527 IWineD3D_AddRef(*ppD3D);
2528 return WINED3D_OK;
2531 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2534 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2535 (This->adapter->TextureRam/(1024*1024)),
2536 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2537 /* return simulated texture memory left */
2538 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2541 /*****
2542 * Get / Set Stream Source
2543 *****/
2544 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2546 IWineD3DVertexBuffer *oldSrc;
2548 if (StreamNumber >= MAX_STREAMS) {
2549 WARN("Stream out of range %d\n", StreamNumber);
2550 return WINED3DERR_INVALIDCALL;
2551 } else if(OffsetInBytes & 0x3) {
2552 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2553 return WINED3DERR_INVALIDCALL;
2556 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2557 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2559 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2561 if(oldSrc == pStreamData &&
2562 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2563 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2564 TRACE("Application is setting the old values over, nothing to do\n");
2565 return WINED3D_OK;
2568 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2569 if (pStreamData) {
2570 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2571 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2574 /* Handle recording of state blocks */
2575 if (This->isRecordingState) {
2576 TRACE("Recording... not performing anything\n");
2577 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2578 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2579 return WINED3D_OK;
2582 /* Need to do a getParent and pass the references up */
2583 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2584 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2585 so for now, just count internally */
2586 if (pStreamData != NULL) {
2587 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2588 InterlockedIncrement(&vbImpl->bindCount);
2589 IWineD3DVertexBuffer_AddRef(pStreamData);
2591 if (oldSrc != NULL) {
2592 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2593 IWineD3DVertexBuffer_Release(oldSrc);
2596 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2598 return WINED3D_OK;
2601 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2604 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2605 This->stateBlock->streamSource[StreamNumber],
2606 This->stateBlock->streamOffset[StreamNumber],
2607 This->stateBlock->streamStride[StreamNumber]);
2609 if (StreamNumber >= MAX_STREAMS) {
2610 WARN("Stream out of range %d\n", StreamNumber);
2611 return WINED3DERR_INVALIDCALL;
2613 *pStream = This->stateBlock->streamSource[StreamNumber];
2614 *pStride = This->stateBlock->streamStride[StreamNumber];
2615 if (pOffset) {
2616 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2619 if (*pStream != NULL) {
2620 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2622 return WINED3D_OK;
2625 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2627 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2628 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2630 /* Verify input at least in d3d9 this is invalid*/
2631 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2632 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2633 return WINED3DERR_INVALIDCALL;
2635 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2636 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2637 return WINED3DERR_INVALIDCALL;
2639 if( Divider == 0 ){
2640 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2641 return WINED3DERR_INVALIDCALL;
2644 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2645 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2647 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2648 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2650 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2651 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2652 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2655 return WINED3D_OK;
2658 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2661 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2662 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2664 TRACE("(%p) : returning %d\n", This, *Divider);
2666 return WINED3D_OK;
2669 /*****
2670 * Get / Set & Multiply Transform
2671 *****/
2672 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2675 /* Most of this routine, comments included copied from ddraw tree initially: */
2676 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2678 /* Handle recording of state blocks */
2679 if (This->isRecordingState) {
2680 TRACE("Recording... not performing anything\n");
2681 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2682 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2683 return WINED3D_OK;
2687 * If the new matrix is the same as the current one,
2688 * we cut off any further processing. this seems to be a reasonable
2689 * optimization because as was noticed, some apps (warcraft3 for example)
2690 * tend towards setting the same matrix repeatedly for some reason.
2692 * From here on we assume that the new matrix is different, wherever it matters.
2694 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2695 TRACE("The app is setting the same matrix over again\n");
2696 return WINED3D_OK;
2697 } else {
2698 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2702 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2703 where ViewMat = Camera space, WorldMat = world space.
2705 In OpenGL, camera and world space is combined into GL_MODELVIEW
2706 matrix. The Projection matrix stay projection matrix.
2709 /* Capture the times we can just ignore the change for now */
2710 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2711 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2712 /* Handled by the state manager */
2715 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2716 return WINED3D_OK;
2719 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2721 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2722 *pMatrix = This->stateBlock->transforms[State];
2723 return WINED3D_OK;
2726 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2727 const WINED3DMATRIX *mat = NULL;
2728 WINED3DMATRIX temp;
2730 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2731 * below means it will be recorded in a state block change, but it
2732 * works regardless where it is recorded.
2733 * If this is found to be wrong, change to StateBlock.
2735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2736 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2738 if (State < HIGHEST_TRANSFORMSTATE)
2740 mat = &This->updateStateBlock->transforms[State];
2741 } else {
2742 FIXME("Unhandled transform state!!\n");
2745 multiply_matrix(&temp, mat, pMatrix);
2747 /* Apply change via set transform - will reapply to eg. lights this way */
2748 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2751 /*****
2752 * Get / Set Light
2753 *****/
2754 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2755 you can reference any indexes you want as long as that number max are enabled at any
2756 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2757 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2758 but when recording, just build a chain pretty much of commands to be replayed. */
2760 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2761 float rho;
2762 PLIGHTINFOEL *object = NULL;
2763 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2764 struct list *e;
2766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2767 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2769 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2770 * the gl driver.
2772 if(!pLight) {
2773 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2774 return WINED3DERR_INVALIDCALL;
2777 switch(pLight->Type) {
2778 case WINED3DLIGHT_POINT:
2779 case WINED3DLIGHT_SPOT:
2780 case WINED3DLIGHT_PARALLELPOINT:
2781 case WINED3DLIGHT_GLSPOT:
2782 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2783 * most wanted
2785 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2786 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2787 return WINED3DERR_INVALIDCALL;
2789 break;
2791 case WINED3DLIGHT_DIRECTIONAL:
2792 /* Ignores attenuation */
2793 break;
2795 default:
2796 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2797 return WINED3DERR_INVALIDCALL;
2800 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2801 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2802 if(object->OriginalIndex == Index) break;
2803 object = NULL;
2806 if(!object) {
2807 TRACE("Adding new light\n");
2808 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2809 if(!object) {
2810 ERR("Out of memory error when allocating a light\n");
2811 return E_OUTOFMEMORY;
2813 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2814 object->glIndex = -1;
2815 object->OriginalIndex = Index;
2816 object->changed = TRUE;
2819 /* Initialize the object */
2820 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,
2821 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2822 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2823 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2824 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2825 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2826 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2828 /* Save away the information */
2829 object->OriginalParms = *pLight;
2831 switch (pLight->Type) {
2832 case WINED3DLIGHT_POINT:
2833 /* Position */
2834 object->lightPosn[0] = pLight->Position.x;
2835 object->lightPosn[1] = pLight->Position.y;
2836 object->lightPosn[2] = pLight->Position.z;
2837 object->lightPosn[3] = 1.0f;
2838 object->cutoff = 180.0f;
2839 /* FIXME: Range */
2840 break;
2842 case WINED3DLIGHT_DIRECTIONAL:
2843 /* Direction */
2844 object->lightPosn[0] = -pLight->Direction.x;
2845 object->lightPosn[1] = -pLight->Direction.y;
2846 object->lightPosn[2] = -pLight->Direction.z;
2847 object->lightPosn[3] = 0.0;
2848 object->exponent = 0.0f;
2849 object->cutoff = 180.0f;
2850 break;
2852 case WINED3DLIGHT_SPOT:
2853 /* Position */
2854 object->lightPosn[0] = pLight->Position.x;
2855 object->lightPosn[1] = pLight->Position.y;
2856 object->lightPosn[2] = pLight->Position.z;
2857 object->lightPosn[3] = 1.0;
2859 /* Direction */
2860 object->lightDirn[0] = pLight->Direction.x;
2861 object->lightDirn[1] = pLight->Direction.y;
2862 object->lightDirn[2] = pLight->Direction.z;
2863 object->lightDirn[3] = 1.0;
2866 * opengl-ish and d3d-ish spot lights use too different models for the
2867 * light "intensity" as a function of the angle towards the main light direction,
2868 * so we only can approximate very roughly.
2869 * however spot lights are rather rarely used in games (if ever used at all).
2870 * furthermore if still used, probably nobody pays attention to such details.
2872 if (pLight->Falloff == 0) {
2873 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2874 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2875 * will always be 1.0 for both of them, and we don't have to care for the
2876 * rest of the rather complex calculation
2878 object->exponent = 0;
2879 } else {
2880 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2881 if (rho < 0.0001) rho = 0.0001f;
2882 object->exponent = -0.3/log(cos(rho/2));
2884 if (object->exponent > 128.0) {
2885 object->exponent = 128.0;
2887 object->cutoff = pLight->Phi*90/M_PI;
2889 /* FIXME: Range */
2890 break;
2892 default:
2893 FIXME("Unrecognized light type %d\n", pLight->Type);
2896 /* Update the live definitions if the light is currently assigned a glIndex */
2897 if (object->glIndex != -1 && !This->isRecordingState) {
2898 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2900 return WINED3D_OK;
2903 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2904 PLIGHTINFOEL *lightInfo = NULL;
2905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2906 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2907 struct list *e;
2908 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2910 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2911 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2912 if(lightInfo->OriginalIndex == Index) break;
2913 lightInfo = NULL;
2916 if (lightInfo == NULL) {
2917 TRACE("Light information requested but light not defined\n");
2918 return WINED3DERR_INVALIDCALL;
2921 *pLight = lightInfo->OriginalParms;
2922 return WINED3D_OK;
2925 /*****
2926 * Get / Set Light Enable
2927 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2928 *****/
2929 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2930 PLIGHTINFOEL *lightInfo = NULL;
2931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2932 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2933 struct list *e;
2934 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2936 /* Tests show true = 128...not clear why */
2937 Enable = Enable? 128: 0;
2939 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2940 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2941 if(lightInfo->OriginalIndex == Index) break;
2942 lightInfo = NULL;
2944 TRACE("Found light: %p\n", lightInfo);
2946 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2947 if (lightInfo == NULL) {
2949 TRACE("Light enabled requested but light not defined, so defining one!\n");
2950 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2952 /* Search for it again! Should be fairly quick as near head of list */
2953 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2954 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2955 if(lightInfo->OriginalIndex == Index) break;
2956 lightInfo = NULL;
2958 if (lightInfo == NULL) {
2959 FIXME("Adding default lights has failed dismally\n");
2960 return WINED3DERR_INVALIDCALL;
2964 lightInfo->enabledChanged = TRUE;
2965 if(!Enable) {
2966 if(lightInfo->glIndex != -1) {
2967 if(!This->isRecordingState) {
2968 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2971 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2972 lightInfo->glIndex = -1;
2973 } else {
2974 TRACE("Light already disabled, nothing to do\n");
2976 lightInfo->enabled = FALSE;
2977 } else {
2978 lightInfo->enabled = TRUE;
2979 if (lightInfo->glIndex != -1) {
2980 /* nop */
2981 TRACE("Nothing to do as light was enabled\n");
2982 } else {
2983 int i;
2984 /* Find a free gl light */
2985 for(i = 0; i < This->maxConcurrentLights; i++) {
2986 if(This->updateStateBlock->activeLights[i] == NULL) {
2987 This->updateStateBlock->activeLights[i] = lightInfo;
2988 lightInfo->glIndex = i;
2989 break;
2992 if(lightInfo->glIndex == -1) {
2993 /* Our tests show that Windows returns D3D_OK in this situation, even with
2994 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2995 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2996 * as well for those lights.
2998 * TODO: Test how this affects rendering
3000 FIXME("Too many concurrently active lights\n");
3001 return WINED3D_OK;
3004 /* i == lightInfo->glIndex */
3005 if(!This->isRecordingState) {
3006 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3011 return WINED3D_OK;
3014 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3016 PLIGHTINFOEL *lightInfo = NULL;
3017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3018 struct list *e;
3019 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3020 TRACE("(%p) : for idx(%d)\n", This, Index);
3022 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3023 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3024 if(lightInfo->OriginalIndex == Index) break;
3025 lightInfo = NULL;
3028 if (lightInfo == NULL) {
3029 TRACE("Light enabled state requested but light not defined\n");
3030 return WINED3DERR_INVALIDCALL;
3032 /* true is 128 according to SetLightEnable */
3033 *pEnable = lightInfo->enabled ? 128 : 0;
3034 return WINED3D_OK;
3037 /*****
3038 * Get / Set Clip Planes
3039 *****/
3040 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3042 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3044 /* Validate Index */
3045 if (Index >= GL_LIMITS(clipplanes)) {
3046 TRACE("Application has requested clipplane this device doesn't support\n");
3047 return WINED3DERR_INVALIDCALL;
3050 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3052 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3053 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3054 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3055 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3056 TRACE("Application is setting old values over, nothing to do\n");
3057 return WINED3D_OK;
3060 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3061 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3062 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3063 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3065 /* Handle recording of state blocks */
3066 if (This->isRecordingState) {
3067 TRACE("Recording... not performing anything\n");
3068 return WINED3D_OK;
3071 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3073 return WINED3D_OK;
3076 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3078 TRACE("(%p) : for idx %d\n", This, Index);
3080 /* Validate Index */
3081 if (Index >= GL_LIMITS(clipplanes)) {
3082 TRACE("Application has requested clipplane this device doesn't support\n");
3083 return WINED3DERR_INVALIDCALL;
3086 pPlane[0] = This->stateBlock->clipplane[Index][0];
3087 pPlane[1] = This->stateBlock->clipplane[Index][1];
3088 pPlane[2] = This->stateBlock->clipplane[Index][2];
3089 pPlane[3] = This->stateBlock->clipplane[Index][3];
3090 return WINED3D_OK;
3093 /*****
3094 * Get / Set Clip Plane Status
3095 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3096 *****/
3097 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3098 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3099 FIXME("(%p) : stub\n", This);
3100 if (NULL == pClipStatus) {
3101 return WINED3DERR_INVALIDCALL;
3103 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3104 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3105 return WINED3D_OK;
3108 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3110 FIXME("(%p) : stub\n", This);
3111 if (NULL == pClipStatus) {
3112 return WINED3DERR_INVALIDCALL;
3114 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3115 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3116 return WINED3D_OK;
3119 /*****
3120 * Get / Set Material
3121 *****/
3122 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3125 This->updateStateBlock->changed.material = TRUE;
3126 This->updateStateBlock->material = *pMaterial;
3128 /* Handle recording of state blocks */
3129 if (This->isRecordingState) {
3130 TRACE("Recording... not performing anything\n");
3131 return WINED3D_OK;
3134 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3135 return WINED3D_OK;
3138 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3140 *pMaterial = This->updateStateBlock->material;
3141 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3142 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3143 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3144 pMaterial->Ambient.b, pMaterial->Ambient.a);
3145 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3146 pMaterial->Specular.b, pMaterial->Specular.a);
3147 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3148 pMaterial->Emissive.b, pMaterial->Emissive.a);
3149 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3151 return WINED3D_OK;
3154 /*****
3155 * Get / Set Indices
3156 *****/
3157 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3159 IWineD3DIndexBuffer *oldIdxs;
3161 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3162 oldIdxs = This->updateStateBlock->pIndexData;
3164 This->updateStateBlock->changed.indices = TRUE;
3165 This->updateStateBlock->pIndexData = pIndexData;
3167 /* Handle recording of state blocks */
3168 if (This->isRecordingState) {
3169 TRACE("Recording... not performing anything\n");
3170 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3171 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3172 return WINED3D_OK;
3175 if(oldIdxs != pIndexData) {
3176 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3177 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3178 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3180 return WINED3D_OK;
3183 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3186 *ppIndexData = This->stateBlock->pIndexData;
3188 /* up ref count on ppindexdata */
3189 if (*ppIndexData) {
3190 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3191 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3192 }else{
3193 TRACE("(%p) No index data set\n", This);
3195 TRACE("Returning %p\n", *ppIndexData);
3197 return WINED3D_OK;
3200 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3201 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3203 TRACE("(%p)->(%d)\n", This, BaseIndex);
3205 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3206 TRACE("Application is setting the old value over, nothing to do\n");
3207 return WINED3D_OK;
3210 This->updateStateBlock->baseVertexIndex = BaseIndex;
3212 if (This->isRecordingState) {
3213 TRACE("Recording... not performing anything\n");
3214 return WINED3D_OK;
3216 /* The base vertex index affects the stream sources */
3217 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3218 return WINED3D_OK;
3221 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3223 TRACE("(%p) : base_index %p\n", This, base_index);
3225 *base_index = This->stateBlock->baseVertexIndex;
3227 TRACE("Returning %u\n", *base_index);
3229 return WINED3D_OK;
3232 /*****
3233 * Get / Set Viewports
3234 *****/
3235 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3238 TRACE("(%p)\n", This);
3239 This->updateStateBlock->changed.viewport = TRUE;
3240 This->updateStateBlock->viewport = *pViewport;
3242 /* Handle recording of state blocks */
3243 if (This->isRecordingState) {
3244 TRACE("Recording... not performing anything\n");
3245 return WINED3D_OK;
3248 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3249 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3251 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3252 return WINED3D_OK;
3256 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3258 TRACE("(%p)\n", This);
3259 *pViewport = This->stateBlock->viewport;
3260 return WINED3D_OK;
3263 /*****
3264 * Get / Set Render States
3265 * TODO: Verify against dx9 definitions
3266 *****/
3267 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3270 DWORD oldValue = This->stateBlock->renderState[State];
3272 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3274 This->updateStateBlock->changed.renderState[State] = TRUE;
3275 This->updateStateBlock->renderState[State] = Value;
3277 /* Handle recording of state blocks */
3278 if (This->isRecordingState) {
3279 TRACE("Recording... not performing anything\n");
3280 return WINED3D_OK;
3283 /* Compared here and not before the assignment to allow proper stateblock recording */
3284 if(Value == oldValue) {
3285 TRACE("Application is setting the old value over, nothing to do\n");
3286 } else {
3287 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3290 return WINED3D_OK;
3293 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3295 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3296 *pValue = This->stateBlock->renderState[State];
3297 return WINED3D_OK;
3300 /*****
3301 * Get / Set Sampler States
3302 * TODO: Verify against dx9 definitions
3303 *****/
3305 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3307 DWORD oldValue;
3309 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3310 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3312 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3313 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3316 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3317 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3318 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3321 * SetSampler is designed to allow for more than the standard up to 8 textures
3322 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3323 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3325 * http://developer.nvidia.com/object/General_FAQ.html#t6
3327 * There are two new settings for GForce
3328 * the sampler one:
3329 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3330 * and the texture one:
3331 * GL_MAX_TEXTURE_COORDS_ARB.
3332 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3333 ******************/
3335 oldValue = This->stateBlock->samplerState[Sampler][Type];
3336 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3337 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3339 /* Handle recording of state blocks */
3340 if (This->isRecordingState) {
3341 TRACE("Recording... not performing anything\n");
3342 return WINED3D_OK;
3345 if(oldValue == Value) {
3346 TRACE("Application is setting the old value over, nothing to do\n");
3347 return WINED3D_OK;
3350 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3352 return WINED3D_OK;
3355 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3358 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3359 This, Sampler, debug_d3dsamplerstate(Type), Type);
3361 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3362 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3365 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3366 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3367 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3369 *Value = This->stateBlock->samplerState[Sampler][Type];
3370 TRACE("(%p) : Returning %#x\n", This, *Value);
3372 return WINED3D_OK;
3375 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3378 This->updateStateBlock->changed.scissorRect = TRUE;
3379 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3380 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3381 return WINED3D_OK;
3383 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3385 if(This->isRecordingState) {
3386 TRACE("Recording... not performing anything\n");
3387 return WINED3D_OK;
3390 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3392 return WINED3D_OK;
3395 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3398 *pRect = This->updateStateBlock->scissorRect;
3399 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3400 return WINED3D_OK;
3403 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3405 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3407 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3409 This->updateStateBlock->vertexDecl = pDecl;
3410 This->updateStateBlock->changed.vertexDecl = TRUE;
3412 if (This->isRecordingState) {
3413 TRACE("Recording... not performing anything\n");
3414 return WINED3D_OK;
3415 } else if(pDecl == oldDecl) {
3416 /* Checked after the assignment to allow proper stateblock recording */
3417 TRACE("Application is setting the old declaration over, nothing to do\n");
3418 return WINED3D_OK;
3421 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3422 return WINED3D_OK;
3425 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3428 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3430 *ppDecl = This->stateBlock->vertexDecl;
3431 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3432 return WINED3D_OK;
3435 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3437 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3439 This->updateStateBlock->vertexShader = pShader;
3440 This->updateStateBlock->changed.vertexShader = TRUE;
3442 if (This->isRecordingState) {
3443 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3444 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3445 TRACE("Recording... not performing anything\n");
3446 return WINED3D_OK;
3447 } else if(oldShader == pShader) {
3448 /* Checked here to allow proper stateblock recording */
3449 TRACE("App is setting the old shader over, nothing to do\n");
3450 return WINED3D_OK;
3453 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3454 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3455 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3457 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3459 return WINED3D_OK;
3462 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3465 if (NULL == ppShader) {
3466 return WINED3DERR_INVALIDCALL;
3468 *ppShader = This->stateBlock->vertexShader;
3469 if( NULL != *ppShader)
3470 IWineD3DVertexShader_AddRef(*ppShader);
3472 TRACE("(%p) : returning %p\n", This, *ppShader);
3473 return WINED3D_OK;
3476 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3477 IWineD3DDevice *iface,
3478 UINT start,
3479 CONST BOOL *srcData,
3480 UINT count) {
3482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3483 int i, cnt = min(count, MAX_CONST_B - start);
3485 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3486 iface, srcData, start, count);
3488 if (srcData == NULL || cnt < 0)
3489 return WINED3DERR_INVALIDCALL;
3491 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3492 for (i = 0; i < cnt; i++)
3493 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3495 for (i = start; i < cnt + start; ++i) {
3496 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3499 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3501 return WINED3D_OK;
3504 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3505 IWineD3DDevice *iface,
3506 UINT start,
3507 BOOL *dstData,
3508 UINT count) {
3510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3511 int cnt = min(count, MAX_CONST_B - start);
3513 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3514 iface, dstData, start, count);
3516 if (dstData == NULL || cnt < 0)
3517 return WINED3DERR_INVALIDCALL;
3519 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3520 return WINED3D_OK;
3523 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3524 IWineD3DDevice *iface,
3525 UINT start,
3526 CONST int *srcData,
3527 UINT count) {
3529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3530 int i, cnt = min(count, MAX_CONST_I - start);
3532 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3533 iface, srcData, start, count);
3535 if (srcData == NULL || cnt < 0)
3536 return WINED3DERR_INVALIDCALL;
3538 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3539 for (i = 0; i < cnt; i++)
3540 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3541 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3543 for (i = start; i < cnt + start; ++i) {
3544 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3547 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3549 return WINED3D_OK;
3552 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3553 IWineD3DDevice *iface,
3554 UINT start,
3555 int *dstData,
3556 UINT count) {
3558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3559 int cnt = min(count, MAX_CONST_I - start);
3561 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3562 iface, dstData, start, count);
3564 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3565 return WINED3DERR_INVALIDCALL;
3567 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3568 return WINED3D_OK;
3571 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3572 IWineD3DDevice *iface,
3573 UINT start,
3574 CONST float *srcData,
3575 UINT count) {
3577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3578 UINT i;
3580 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3581 iface, srcData, start, count);
3583 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3584 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3585 return WINED3DERR_INVALIDCALL;
3587 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3588 if(TRACE_ON(d3d)) {
3589 for (i = 0; i < count; i++)
3590 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3591 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3594 if (!This->isRecordingState)
3596 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3597 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3600 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3601 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3603 return WINED3D_OK;
3606 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3607 IWineD3DDevice *iface,
3608 UINT start,
3609 float *dstData,
3610 UINT count) {
3612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3613 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3615 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3616 iface, dstData, start, count);
3618 if (dstData == NULL || cnt < 0)
3619 return WINED3DERR_INVALIDCALL;
3621 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3622 return WINED3D_OK;
3625 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3626 DWORD i;
3627 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3628 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3632 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3633 int i = This->rev_tex_unit_map[unit];
3634 int j = This->texUnitMap[stage];
3636 This->texUnitMap[stage] = unit;
3637 if (i != -1 && i != stage) {
3638 This->texUnitMap[i] = -1;
3641 This->rev_tex_unit_map[unit] = stage;
3642 if (j != -1 && j != unit) {
3643 This->rev_tex_unit_map[j] = -1;
3647 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3648 int i;
3650 for (i = 0; i < MAX_TEXTURES; ++i) {
3651 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3652 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3653 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3654 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3655 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3656 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3657 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3658 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3660 if (color_op == WINED3DTOP_DISABLE) {
3661 /* Not used, and disable higher stages */
3662 while (i < MAX_TEXTURES) {
3663 This->fixed_function_usage_map[i] = FALSE;
3664 ++i;
3666 break;
3669 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3670 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3671 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3672 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3673 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3674 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3675 This->fixed_function_usage_map[i] = TRUE;
3676 } else {
3677 This->fixed_function_usage_map[i] = FALSE;
3680 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3681 This->fixed_function_usage_map[i+1] = TRUE;
3686 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3687 int i, tex;
3689 device_update_fixed_function_usage_map(This);
3691 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3692 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3693 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3694 if (!This->fixed_function_usage_map[i]) continue;
3696 if (This->texUnitMap[i] != i) {
3697 device_map_stage(This, i, i);
3698 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3699 markTextureStagesDirty(This, i);
3702 return;
3705 /* Now work out the mapping */
3706 tex = 0;
3707 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3708 if (!This->fixed_function_usage_map[i]) continue;
3710 if (This->texUnitMap[i] != tex) {
3711 device_map_stage(This, i, tex);
3712 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3713 markTextureStagesDirty(This, i);
3716 ++tex;
3720 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3721 const DWORD *sampler_tokens =
3722 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3723 int i;
3725 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3726 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3727 device_map_stage(This, i, i);
3728 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3729 if (i < MAX_TEXTURES) {
3730 markTextureStagesDirty(This, i);
3736 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3737 const DWORD *vshader_sampler_tokens, int unit)
3739 int current_mapping = This->rev_tex_unit_map[unit];
3741 if (current_mapping == -1) {
3742 /* Not currently used */
3743 return TRUE;
3746 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3747 /* Used by a fragment sampler */
3749 if (!pshader_sampler_tokens) {
3750 /* No pixel shader, check fixed function */
3751 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3754 /* Pixel shader, check the shader's sampler map */
3755 return !pshader_sampler_tokens[current_mapping];
3758 /* Used by a vertex sampler */
3759 return !vshader_sampler_tokens[current_mapping];
3762 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3763 const DWORD *vshader_sampler_tokens =
3764 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3765 const DWORD *pshader_sampler_tokens = NULL;
3766 int start = GL_LIMITS(combined_samplers) - 1;
3767 int i;
3769 if (ps) {
3770 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3772 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3773 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3774 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3777 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3778 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3779 if (vshader_sampler_tokens[i]) {
3780 if (This->texUnitMap[vsampler_idx] != -1) {
3781 /* Already mapped somewhere */
3782 continue;
3785 while (start >= 0) {
3786 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3787 device_map_stage(This, vsampler_idx, start);
3788 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3790 --start;
3791 break;
3794 --start;
3800 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3801 BOOL vs = use_vs(This);
3802 BOOL ps = use_ps(This);
3804 * Rules are:
3805 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3806 * that would be really messy and require shader recompilation
3807 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3808 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3810 if (ps) {
3811 device_map_psamplers(This);
3812 } else {
3813 device_map_fixed_function_samplers(This);
3816 if (vs) {
3817 device_map_vsamplers(This, ps);
3821 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3823 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3824 This->updateStateBlock->pixelShader = pShader;
3825 This->updateStateBlock->changed.pixelShader = TRUE;
3827 /* Handle recording of state blocks */
3828 if (This->isRecordingState) {
3829 TRACE("Recording... not performing anything\n");
3832 if (This->isRecordingState) {
3833 TRACE("Recording... not performing anything\n");
3834 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3835 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3836 return WINED3D_OK;
3839 if(pShader == oldShader) {
3840 TRACE("App is setting the old pixel shader over, nothing to do\n");
3841 return WINED3D_OK;
3844 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3845 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3847 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3848 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3850 return WINED3D_OK;
3853 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3854 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3856 if (NULL == ppShader) {
3857 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3858 return WINED3DERR_INVALIDCALL;
3861 *ppShader = This->stateBlock->pixelShader;
3862 if (NULL != *ppShader) {
3863 IWineD3DPixelShader_AddRef(*ppShader);
3865 TRACE("(%p) : returning %p\n", This, *ppShader);
3866 return WINED3D_OK;
3869 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3870 IWineD3DDevice *iface,
3871 UINT start,
3872 CONST BOOL *srcData,
3873 UINT count) {
3875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3876 int i, cnt = min(count, MAX_CONST_B - start);
3878 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3879 iface, srcData, start, count);
3881 if (srcData == NULL || cnt < 0)
3882 return WINED3DERR_INVALIDCALL;
3884 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3885 for (i = 0; i < cnt; i++)
3886 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3888 for (i = start; i < cnt + start; ++i) {
3889 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3892 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3894 return WINED3D_OK;
3897 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3898 IWineD3DDevice *iface,
3899 UINT start,
3900 BOOL *dstData,
3901 UINT count) {
3903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3904 int cnt = min(count, MAX_CONST_B - start);
3906 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3907 iface, dstData, start, count);
3909 if (dstData == NULL || cnt < 0)
3910 return WINED3DERR_INVALIDCALL;
3912 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3913 return WINED3D_OK;
3916 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3917 IWineD3DDevice *iface,
3918 UINT start,
3919 CONST int *srcData,
3920 UINT count) {
3922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3923 int i, cnt = min(count, MAX_CONST_I - start);
3925 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3926 iface, srcData, start, count);
3928 if (srcData == NULL || cnt < 0)
3929 return WINED3DERR_INVALIDCALL;
3931 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3932 for (i = 0; i < cnt; i++)
3933 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3934 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3936 for (i = start; i < cnt + start; ++i) {
3937 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3940 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3942 return WINED3D_OK;
3945 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3946 IWineD3DDevice *iface,
3947 UINT start,
3948 int *dstData,
3949 UINT count) {
3951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3952 int cnt = min(count, MAX_CONST_I - start);
3954 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3955 iface, dstData, start, count);
3957 if (dstData == NULL || cnt < 0)
3958 return WINED3DERR_INVALIDCALL;
3960 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3961 return WINED3D_OK;
3964 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3965 IWineD3DDevice *iface,
3966 UINT start,
3967 CONST float *srcData,
3968 UINT count) {
3970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3971 UINT i;
3973 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3974 iface, srcData, start, count);
3976 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3977 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3978 return WINED3DERR_INVALIDCALL;
3980 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3981 if(TRACE_ON(d3d)) {
3982 for (i = 0; i < count; i++)
3983 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3984 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3987 if (!This->isRecordingState)
3989 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3990 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3993 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3994 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3996 return WINED3D_OK;
3999 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4000 IWineD3DDevice *iface,
4001 UINT start,
4002 float *dstData,
4003 UINT count) {
4005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4006 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4008 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4009 iface, dstData, start, count);
4011 if (dstData == NULL || cnt < 0)
4012 return WINED3DERR_INVALIDCALL;
4014 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4015 return WINED3D_OK;
4018 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4019 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4020 const WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags)
4022 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4023 unsigned int i;
4024 DWORD DestFVF = dest->fvf;
4025 WINED3DVIEWPORT vp;
4026 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4027 BOOL doClip;
4028 DWORD numTextures;
4030 if (lpStrideData->u.s.normal.lpData) {
4031 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4034 if (lpStrideData->u.s.position.lpData == NULL) {
4035 ERR("Source has no position mask\n");
4036 return WINED3DERR_INVALIDCALL;
4039 /* We might access VBOs from this code, so hold the lock */
4040 ENTER_GL();
4042 if (dest->resource.allocatedMemory == NULL) {
4043 /* This may happen if we do direct locking into a vbo. Unlikely,
4044 * but theoretically possible(ddraw processvertices test)
4046 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4047 if(!dest->resource.allocatedMemory) {
4048 LEAVE_GL();
4049 ERR("Out of memory\n");
4050 return E_OUTOFMEMORY;
4052 if(dest->vbo) {
4053 const void *src;
4054 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4055 checkGLcall("glBindBufferARB");
4056 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4057 if(src) {
4058 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4060 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4061 checkGLcall("glUnmapBufferARB");
4065 /* Get a pointer into the destination vbo(create one if none exists) and
4066 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4068 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4069 dest->Flags |= VBFLAG_CREATEVBO;
4070 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4073 if(dest->vbo) {
4074 unsigned char extrabytes = 0;
4075 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4076 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4077 * this may write 4 extra bytes beyond the area that should be written
4079 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4080 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4081 if(!dest_conv_addr) {
4082 ERR("Out of memory\n");
4083 /* Continue without storing converted vertices */
4085 dest_conv = dest_conv_addr;
4088 /* Should I clip?
4089 * a) WINED3DRS_CLIPPING is enabled
4090 * b) WINED3DVOP_CLIP is passed
4092 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4093 static BOOL warned = FALSE;
4095 * The clipping code is not quite correct. Some things need
4096 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4097 * so disable clipping for now.
4098 * (The graphics in Half-Life are broken, and my processvertices
4099 * test crashes with IDirect3DDevice3)
4100 doClip = TRUE;
4102 doClip = FALSE;
4103 if(!warned) {
4104 warned = TRUE;
4105 FIXME("Clipping is broken and disabled for now\n");
4107 } else doClip = FALSE;
4108 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4110 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4111 WINED3DTS_VIEW,
4112 &view_mat);
4113 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4114 WINED3DTS_PROJECTION,
4115 &proj_mat);
4116 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4117 WINED3DTS_WORLDMATRIX(0),
4118 &world_mat);
4120 TRACE("View mat:\n");
4121 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);
4122 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);
4123 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);
4124 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);
4126 TRACE("Proj mat:\n");
4127 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);
4128 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);
4129 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);
4130 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);
4132 TRACE("World mat:\n");
4133 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);
4134 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);
4135 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);
4136 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);
4138 /* Get the viewport */
4139 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4140 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4141 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4143 multiply_matrix(&mat,&view_mat,&world_mat);
4144 multiply_matrix(&mat,&proj_mat,&mat);
4146 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4148 for (i = 0; i < dwCount; i+= 1) {
4149 unsigned int tex_index;
4151 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4152 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4153 /* The position first */
4154 const float *p =
4155 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4156 float x, y, z, rhw;
4157 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4159 /* Multiplication with world, view and projection matrix */
4160 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);
4161 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);
4162 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);
4163 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);
4165 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4167 /* WARNING: The following things are taken from d3d7 and were not yet checked
4168 * against d3d8 or d3d9!
4171 /* Clipping conditions: From msdn
4173 * A vertex is clipped if it does not match the following requirements
4174 * -rhw < x <= rhw
4175 * -rhw < y <= rhw
4176 * 0 < z <= rhw
4177 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4179 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4180 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4184 if( !doClip ||
4185 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4186 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4187 ( rhw > eps ) ) ) {
4189 /* "Normal" viewport transformation (not clipped)
4190 * 1) The values are divided by rhw
4191 * 2) The y axis is negative, so multiply it with -1
4192 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4193 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4194 * 4) Multiply x with Width/2 and add Width/2
4195 * 5) The same for the height
4196 * 6) Add the viewpoint X and Y to the 2D coordinates and
4197 * The minimum Z value to z
4198 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4200 * Well, basically it's simply a linear transformation into viewport
4201 * coordinates
4204 x /= rhw;
4205 y /= rhw;
4206 z /= rhw;
4208 y *= -1;
4210 x *= vp.Width / 2;
4211 y *= vp.Height / 2;
4212 z *= vp.MaxZ - vp.MinZ;
4214 x += vp.Width / 2 + vp.X;
4215 y += vp.Height / 2 + vp.Y;
4216 z += vp.MinZ;
4218 rhw = 1 / rhw;
4219 } else {
4220 /* That vertex got clipped
4221 * Contrary to OpenGL it is not dropped completely, it just
4222 * undergoes a different calculation.
4224 TRACE("Vertex got clipped\n");
4225 x += rhw;
4226 y += rhw;
4228 x /= 2;
4229 y /= 2;
4231 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4232 * outside of the main vertex buffer memory. That needs some more
4233 * investigation...
4237 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4240 ( (float *) dest_ptr)[0] = x;
4241 ( (float *) dest_ptr)[1] = y;
4242 ( (float *) dest_ptr)[2] = z;
4243 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4245 dest_ptr += 3 * sizeof(float);
4247 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4248 dest_ptr += sizeof(float);
4251 if(dest_conv) {
4252 float w = 1 / rhw;
4253 ( (float *) dest_conv)[0] = x * w;
4254 ( (float *) dest_conv)[1] = y * w;
4255 ( (float *) dest_conv)[2] = z * w;
4256 ( (float *) dest_conv)[3] = w;
4258 dest_conv += 3 * sizeof(float);
4260 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4261 dest_conv += sizeof(float);
4265 if (DestFVF & WINED3DFVF_PSIZE) {
4266 dest_ptr += sizeof(DWORD);
4267 if(dest_conv) dest_conv += sizeof(DWORD);
4269 if (DestFVF & WINED3DFVF_NORMAL) {
4270 const float *normal =
4271 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4272 /* AFAIK this should go into the lighting information */
4273 FIXME("Didn't expect the destination to have a normal\n");
4274 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4275 if(dest_conv) {
4276 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4280 if (DestFVF & WINED3DFVF_DIFFUSE) {
4281 const DWORD *color_d =
4282 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4283 if(!color_d) {
4284 static BOOL warned = FALSE;
4286 if(!warned) {
4287 ERR("No diffuse color in source, but destination has one\n");
4288 warned = TRUE;
4291 *( (DWORD *) dest_ptr) = 0xffffffff;
4292 dest_ptr += sizeof(DWORD);
4294 if(dest_conv) {
4295 *( (DWORD *) dest_conv) = 0xffffffff;
4296 dest_conv += sizeof(DWORD);
4299 else {
4300 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4301 if(dest_conv) {
4302 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4303 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4304 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4305 dest_conv += sizeof(DWORD);
4310 if (DestFVF & WINED3DFVF_SPECULAR) {
4311 /* What's the color value in the feedback buffer? */
4312 const DWORD *color_s =
4313 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4314 if(!color_s) {
4315 static BOOL warned = FALSE;
4317 if(!warned) {
4318 ERR("No specular color in source, but destination has one\n");
4319 warned = TRUE;
4322 *( (DWORD *) dest_ptr) = 0xFF000000;
4323 dest_ptr += sizeof(DWORD);
4325 if(dest_conv) {
4326 *( (DWORD *) dest_conv) = 0xFF000000;
4327 dest_conv += sizeof(DWORD);
4330 else {
4331 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4332 if(dest_conv) {
4333 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4334 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4335 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4336 dest_conv += sizeof(DWORD);
4341 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4342 const float *tex_coord =
4343 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4344 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4345 if(!tex_coord) {
4346 ERR("No source texture, but destination requests one\n");
4347 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4348 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4350 else {
4351 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4352 if(dest_conv) {
4353 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4359 if(dest_conv) {
4360 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4361 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4362 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4363 dwCount * get_flexible_vertex_size(DestFVF),
4364 dest_conv_addr));
4365 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4366 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4369 LEAVE_GL();
4371 return WINED3D_OK;
4373 #undef copy_and_next
4375 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4377 WineDirect3DVertexStridedData strided;
4378 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4379 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4381 if(pVertexDecl) {
4382 ERR("Output vertex declaration not implemented yet\n");
4385 /* Need any context to write to the vbo. */
4386 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4388 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4389 * control the streamIsUP flag, thus restore it afterwards.
4391 This->stateBlock->streamIsUP = FALSE;
4392 memset(&strided, 0, sizeof(strided));
4393 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4394 This->stateBlock->streamIsUP = streamWasUP;
4396 if(vbo || SrcStartIndex) {
4397 unsigned int i;
4398 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4399 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4401 * Also get the start index in, but only loop over all elements if there's something to add at all.
4403 #define FIXSRC(type) \
4404 if(strided.u.s.type.VBO) { \
4405 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4406 strided.u.s.type.VBO = 0; \
4407 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4408 ENTER_GL(); \
4409 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4410 vb->vbo = 0; \
4411 LEAVE_GL(); \
4413 if(strided.u.s.type.lpData) { \
4414 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4416 FIXSRC(position);
4417 FIXSRC(blendWeights);
4418 FIXSRC(blendMatrixIndices);
4419 FIXSRC(normal);
4420 FIXSRC(pSize);
4421 FIXSRC(diffuse);
4422 FIXSRC(specular);
4423 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4424 FIXSRC(texCoords[i]);
4426 FIXSRC(position2);
4427 FIXSRC(normal2);
4428 FIXSRC(tangent);
4429 FIXSRC(binormal);
4430 FIXSRC(tessFactor);
4431 FIXSRC(fog);
4432 FIXSRC(depth);
4433 FIXSRC(sample);
4434 #undef FIXSRC
4437 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4440 /*****
4441 * Get / Set Texture Stage States
4442 * TODO: Verify against dx9 definitions
4443 *****/
4444 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4446 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4448 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4450 if (Stage >= MAX_TEXTURES) {
4451 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4452 return WINED3D_OK;
4455 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4456 This->updateStateBlock->textureState[Stage][Type] = Value;
4458 if (This->isRecordingState) {
4459 TRACE("Recording... not performing anything\n");
4460 return WINED3D_OK;
4463 /* Checked after the assignments to allow proper stateblock recording */
4464 if(oldValue == Value) {
4465 TRACE("App is setting the old value over, nothing to do\n");
4466 return WINED3D_OK;
4469 if(Stage > This->stateBlock->lowest_disabled_stage &&
4470 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4471 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4472 * Changes in other states are important on disabled stages too
4474 return WINED3D_OK;
4477 if(Type == WINED3DTSS_COLOROP) {
4478 int i;
4480 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4481 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4482 * they have to be disabled
4484 * The current stage is dirtified below.
4486 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4487 TRACE("Additionally dirtifying stage %d\n", i);
4488 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4490 This->stateBlock->lowest_disabled_stage = Stage;
4491 TRACE("New lowest disabled: %d\n", Stage);
4492 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4493 /* Previously disabled stage enabled. Stages above it may need enabling
4494 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4495 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4497 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4500 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4501 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4502 break;
4504 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4505 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4507 This->stateBlock->lowest_disabled_stage = i;
4508 TRACE("New lowest disabled: %d\n", i);
4512 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4514 return WINED3D_OK;
4517 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4519 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4520 *pValue = This->updateStateBlock->textureState[Stage][Type];
4521 return WINED3D_OK;
4524 /*****
4525 * Get / Set Texture
4526 *****/
4527 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4529 IWineD3DBaseTexture *oldTexture;
4531 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4533 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4534 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4537 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4538 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4539 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4542 oldTexture = This->updateStateBlock->textures[Stage];
4544 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4545 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4547 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4548 return WINED3DERR_INVALIDCALL;
4551 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4552 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4554 This->updateStateBlock->changed.textures[Stage] = TRUE;
4555 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4556 This->updateStateBlock->textures[Stage] = pTexture;
4558 /* Handle recording of state blocks */
4559 if (This->isRecordingState) {
4560 TRACE("Recording... not performing anything\n");
4561 return WINED3D_OK;
4564 if(oldTexture == pTexture) {
4565 TRACE("App is setting the same texture again, nothing to do\n");
4566 return WINED3D_OK;
4569 /** NOTE: MSDN says that setTexture increases the reference count,
4570 * and that the application must set the texture back to null (or have a leaky application),
4571 * This means we should pass the refcount up to the parent
4572 *******************************/
4573 if (NULL != This->updateStateBlock->textures[Stage]) {
4574 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4575 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4577 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4578 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4579 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4580 * so the COLOROP and ALPHAOP have to be dirtified.
4582 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4583 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4585 if(bindCount == 1) {
4586 new->baseTexture.sampler = Stage;
4588 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4592 if (NULL != oldTexture) {
4593 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4594 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4596 IWineD3DBaseTexture_Release(oldTexture);
4597 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4598 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4599 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4602 if(bindCount && old->baseTexture.sampler == Stage) {
4603 int i;
4604 /* Have to do a search for the other sampler(s) where the texture is bound to
4605 * Shouldn't happen as long as apps bind a texture only to one stage
4607 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4608 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4609 if(This->updateStateBlock->textures[i] == oldTexture) {
4610 old->baseTexture.sampler = i;
4611 break;
4617 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4619 return WINED3D_OK;
4622 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4625 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4627 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4628 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4631 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4632 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4633 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4636 *ppTexture=This->stateBlock->textures[Stage];
4637 if (*ppTexture)
4638 IWineD3DBaseTexture_AddRef(*ppTexture);
4640 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4642 return WINED3D_OK;
4645 /*****
4646 * Get Back Buffer
4647 *****/
4648 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4649 IWineD3DSurface **ppBackBuffer) {
4650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4651 IWineD3DSwapChain *swapChain;
4652 HRESULT hr;
4654 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4656 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4657 if (hr == WINED3D_OK) {
4658 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4659 IWineD3DSwapChain_Release(swapChain);
4660 } else {
4661 *ppBackBuffer = NULL;
4663 return hr;
4666 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4668 WARN("(%p) : stub, calling idirect3d for now\n", This);
4669 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4672 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4674 IWineD3DSwapChain *swapChain;
4675 HRESULT hr;
4677 if(iSwapChain > 0) {
4678 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4679 if (hr == WINED3D_OK) {
4680 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4681 IWineD3DSwapChain_Release(swapChain);
4682 } else {
4683 FIXME("(%p) Error getting display mode\n", This);
4685 } else {
4686 /* Don't read the real display mode,
4687 but return the stored mode instead. X11 can't change the color
4688 depth, and some apps are pretty angry if they SetDisplayMode from
4689 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4691 Also don't relay to the swapchain because with ddraw it's possible
4692 that there isn't a swapchain at all */
4693 pMode->Width = This->ddraw_width;
4694 pMode->Height = This->ddraw_height;
4695 pMode->Format = This->ddraw_format;
4696 pMode->RefreshRate = 0;
4697 hr = WINED3D_OK;
4700 return hr;
4703 /*****
4704 * Stateblock related functions
4705 *****/
4707 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4709 IWineD3DStateBlockImpl *object;
4710 HRESULT temp_result;
4711 int i;
4713 TRACE("(%p)\n", This);
4715 if (This->isRecordingState) {
4716 return WINED3DERR_INVALIDCALL;
4719 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4720 if (NULL == object ) {
4721 FIXME("(%p)Error allocating memory for stateblock\n", This);
4722 return E_OUTOFMEMORY;
4724 TRACE("(%p) created object %p\n", This, object);
4725 object->wineD3DDevice= This;
4726 /** FIXME: object->parent = parent; **/
4727 object->parent = NULL;
4728 object->blockType = WINED3DSBT_RECORDED;
4729 object->ref = 1;
4730 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4732 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4733 list_init(&object->lightMap[i]);
4736 temp_result = allocate_shader_constants(object);
4737 if (WINED3D_OK != temp_result)
4738 return temp_result;
4740 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4741 This->updateStateBlock = object;
4742 This->isRecordingState = TRUE;
4744 TRACE("(%p) recording stateblock %p\n",This , object);
4745 return WINED3D_OK;
4748 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4750 unsigned int i, j;
4751 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4753 if (!This->isRecordingState) {
4754 FIXME("(%p) not recording! returning error\n", This);
4755 *ppStateBlock = NULL;
4756 return WINED3DERR_INVALIDCALL;
4759 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4760 if(object->changed.renderState[i]) {
4761 object->contained_render_states[object->num_contained_render_states] = i;
4762 object->num_contained_render_states++;
4765 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4766 if(object->changed.transform[i]) {
4767 object->contained_transform_states[object->num_contained_transform_states] = i;
4768 object->num_contained_transform_states++;
4771 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4772 if(object->changed.vertexShaderConstantsF[i]) {
4773 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4774 object->num_contained_vs_consts_f++;
4777 for(i = 0; i < MAX_CONST_I; i++) {
4778 if (object->changed.vertexShaderConstantsI & (1 << i))
4780 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4781 object->num_contained_vs_consts_i++;
4784 for(i = 0; i < MAX_CONST_B; i++) {
4785 if (object->changed.vertexShaderConstantsB & (1 << i))
4787 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4788 object->num_contained_vs_consts_b++;
4791 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4793 if (object->changed.pixelShaderConstantsF[i])
4795 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4796 ++object->num_contained_ps_consts_f;
4799 for(i = 0; i < MAX_CONST_I; i++) {
4800 if (object->changed.pixelShaderConstantsI & (1 << i))
4802 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4803 object->num_contained_ps_consts_i++;
4806 for(i = 0; i < MAX_CONST_B; i++) {
4807 if (object->changed.pixelShaderConstantsB & (1 << i))
4809 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4810 object->num_contained_ps_consts_b++;
4813 for(i = 0; i < MAX_TEXTURES; i++) {
4814 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4815 if(object->changed.textureState[i][j]) {
4816 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4817 object->contained_tss_states[object->num_contained_tss_states].state = j;
4818 object->num_contained_tss_states++;
4822 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4823 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4824 if(object->changed.samplerState[i][j]) {
4825 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4826 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4827 object->num_contained_sampler_states++;
4832 *ppStateBlock = (IWineD3DStateBlock*) object;
4833 This->isRecordingState = FALSE;
4834 This->updateStateBlock = This->stateBlock;
4835 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4836 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4837 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4838 return WINED3D_OK;
4841 /*****
4842 * Scene related functions
4843 *****/
4844 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4845 /* At the moment we have no need for any functionality at the beginning
4846 of a scene */
4847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4848 TRACE("(%p)\n", This);
4850 if(This->inScene) {
4851 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4852 return WINED3DERR_INVALIDCALL;
4854 This->inScene = TRUE;
4855 return WINED3D_OK;
4858 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4860 TRACE("(%p)\n", This);
4862 if(!This->inScene) {
4863 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4864 return WINED3DERR_INVALIDCALL;
4867 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4868 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4869 glFlush();
4870 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4871 * fails
4874 This->inScene = FALSE;
4875 return WINED3D_OK;
4878 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4879 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4880 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4882 IWineD3DSwapChain *swapChain = NULL;
4883 int i;
4884 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4886 TRACE("(%p) Presenting the frame\n", This);
4888 for(i = 0 ; i < swapchains ; i ++) {
4890 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4891 TRACE("presentinng chain %d, %p\n", i, swapChain);
4892 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4893 IWineD3DSwapChain_Release(swapChain);
4896 return WINED3D_OK;
4899 /* Not called from the VTable (internal subroutine) */
4900 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4901 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4902 float Z, DWORD Stencil) {
4903 GLbitfield glMask = 0;
4904 unsigned int i;
4905 WINED3DRECT curRect;
4906 RECT vp_rect;
4907 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4908 UINT drawable_width, drawable_height;
4909 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4910 IWineD3DSwapChainImpl *swapchain = NULL;
4912 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4913 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4914 * for the cleared parts, and the untouched parts.
4916 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4917 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4918 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4919 * checking all this if the dest surface is in the drawable anyway.
4921 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4922 while(1) {
4923 if(vp->X != 0 || vp->Y != 0 ||
4924 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4925 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4926 break;
4928 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4929 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4930 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4931 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4932 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4933 break;
4935 if(Count > 0 && pRects && (
4936 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4937 pRects[0].x2 < target->currentDesc.Width ||
4938 pRects[0].y2 < target->currentDesc.Height)) {
4939 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4940 break;
4942 break;
4946 target->get_drawable_size(target, &drawable_width, &drawable_height);
4948 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4949 ENTER_GL();
4951 /* Only set the values up once, as they are not changing */
4952 if (Flags & WINED3DCLEAR_STENCIL) {
4953 glClearStencil(Stencil);
4954 checkGLcall("glClearStencil");
4955 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4956 glStencilMask(0xFFFFFFFF);
4959 if (Flags & WINED3DCLEAR_ZBUFFER) {
4960 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4961 glDepthMask(GL_TRUE);
4962 glClearDepth(Z);
4963 checkGLcall("glClearDepth");
4964 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4965 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4967 if (vp->X != 0 || vp->Y != 0 ||
4968 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4969 surface_load_ds_location(This->stencilBufferTarget, location);
4971 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4972 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4973 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4974 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4975 surface_load_ds_location(This->stencilBufferTarget, location);
4977 else if (Count > 0 && pRects && (
4978 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4979 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4980 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4981 surface_load_ds_location(This->stencilBufferTarget, location);
4985 if (Flags & WINED3DCLEAR_TARGET) {
4986 TRACE("Clearing screen with glClear to color %x\n", Color);
4987 glClearColor(D3DCOLOR_R(Color),
4988 D3DCOLOR_G(Color),
4989 D3DCOLOR_B(Color),
4990 D3DCOLOR_A(Color));
4991 checkGLcall("glClearColor");
4993 /* Clear ALL colors! */
4994 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4995 glMask = glMask | GL_COLOR_BUFFER_BIT;
4998 vp_rect.left = vp->X;
4999 vp_rect.top = vp->Y;
5000 vp_rect.right = vp->X + vp->Width;
5001 vp_rect.bottom = vp->Y + vp->Height;
5002 if (!(Count > 0 && pRects)) {
5003 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5004 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5006 if(This->render_offscreen) {
5007 glScissor(vp_rect.left, vp_rect.top,
5008 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5009 } else {
5010 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5011 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5013 checkGLcall("glScissor");
5014 glClear(glMask);
5015 checkGLcall("glClear");
5016 } else {
5017 /* Now process each rect in turn */
5018 for (i = 0; i < Count; i++) {
5019 /* Note gl uses lower left, width/height */
5020 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5021 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5022 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5024 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5025 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5026 curRect.x1, (target->currentDesc.Height - curRect.y2),
5027 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5029 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5030 * The rectangle is not cleared, no error is returned, but further rectanlges are
5031 * still cleared if they are valid
5033 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5034 TRACE("Rectangle with negative dimensions, ignoring\n");
5035 continue;
5038 if(This->render_offscreen) {
5039 glScissor(curRect.x1, curRect.y1,
5040 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5041 } else {
5042 glScissor(curRect.x1, drawable_height - curRect.y2,
5043 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5045 checkGLcall("glScissor");
5047 glClear(glMask);
5048 checkGLcall("glClear");
5052 /* Restore the old values (why..?) */
5053 if (Flags & WINED3DCLEAR_STENCIL) {
5054 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5056 if (Flags & WINED3DCLEAR_TARGET) {
5057 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5058 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5059 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5060 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5061 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5063 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5064 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5066 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5068 if (Flags & WINED3DCLEAR_ZBUFFER) {
5069 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5070 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5071 surface_modify_ds_location(This->stencilBufferTarget, location);
5074 LEAVE_GL();
5076 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5077 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5078 glFlush();
5080 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5083 return WINED3D_OK;
5086 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5087 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5089 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5091 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5092 Count, pRects, Flags, Color, Z, Stencil);
5094 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5095 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5096 /* TODO: What about depth stencil buffers without stencil bits? */
5097 return WINED3DERR_INVALIDCALL;
5100 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5103 /*****
5104 * Drawing functions
5105 *****/
5106 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5107 UINT PrimitiveCount) {
5109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5111 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5112 debug_d3dprimitivetype(PrimitiveType),
5113 StartVertex, PrimitiveCount);
5115 if(!This->stateBlock->vertexDecl) {
5116 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5117 return WINED3DERR_INVALIDCALL;
5120 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5121 if(This->stateBlock->streamIsUP) {
5122 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5123 This->stateBlock->streamIsUP = FALSE;
5126 if(This->stateBlock->loadBaseVertexIndex != 0) {
5127 This->stateBlock->loadBaseVertexIndex = 0;
5128 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5130 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5131 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5132 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5133 return WINED3D_OK;
5136 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5137 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5138 WINED3DPRIMITIVETYPE PrimitiveType,
5139 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5142 UINT idxStride = 2;
5143 IWineD3DIndexBuffer *pIB;
5144 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5145 GLuint vbo;
5147 pIB = This->stateBlock->pIndexData;
5148 if (!pIB) {
5149 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5150 * without an index buffer set. (The first time at least...)
5151 * D3D8 simply dies, but I doubt it can do much harm to return
5152 * D3DERR_INVALIDCALL there as well. */
5153 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5154 return WINED3DERR_INVALIDCALL;
5157 if(!This->stateBlock->vertexDecl) {
5158 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5159 return WINED3DERR_INVALIDCALL;
5162 if(This->stateBlock->streamIsUP) {
5163 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5164 This->stateBlock->streamIsUP = FALSE;
5166 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5168 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5169 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5170 minIndex, NumVertices, startIndex, primCount);
5172 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5173 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5174 idxStride = 2;
5175 } else {
5176 idxStride = 4;
5179 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5180 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5181 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5184 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5185 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5187 return WINED3D_OK;
5190 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5191 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5192 UINT VertexStreamZeroStride) {
5193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5194 IWineD3DVertexBuffer *vb;
5196 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5197 debug_d3dprimitivetype(PrimitiveType),
5198 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5200 if(!This->stateBlock->vertexDecl) {
5201 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5202 return WINED3DERR_INVALIDCALL;
5205 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5206 vb = This->stateBlock->streamSource[0];
5207 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5208 if(vb) IWineD3DVertexBuffer_Release(vb);
5209 This->stateBlock->streamOffset[0] = 0;
5210 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5211 This->stateBlock->streamIsUP = TRUE;
5212 This->stateBlock->loadBaseVertexIndex = 0;
5214 /* TODO: Only mark dirty if drawing from a different UP address */
5215 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5217 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5218 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5220 /* MSDN specifies stream zero settings must be set to NULL */
5221 This->stateBlock->streamStride[0] = 0;
5222 This->stateBlock->streamSource[0] = NULL;
5224 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5225 * the new stream sources or use UP drawing again
5227 return WINED3D_OK;
5230 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5231 UINT MinVertexIndex, UINT NumVertices,
5232 UINT PrimitiveCount, CONST void* pIndexData,
5233 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5234 UINT VertexStreamZeroStride) {
5235 int idxStride;
5236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5237 IWineD3DVertexBuffer *vb;
5238 IWineD3DIndexBuffer *ib;
5240 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5241 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5242 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5243 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5245 if(!This->stateBlock->vertexDecl) {
5246 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5247 return WINED3DERR_INVALIDCALL;
5250 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5251 idxStride = 2;
5252 } else {
5253 idxStride = 4;
5256 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5257 vb = This->stateBlock->streamSource[0];
5258 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5259 if(vb) IWineD3DVertexBuffer_Release(vb);
5260 This->stateBlock->streamIsUP = TRUE;
5261 This->stateBlock->streamOffset[0] = 0;
5262 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5264 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5265 This->stateBlock->baseVertexIndex = 0;
5266 This->stateBlock->loadBaseVertexIndex = 0;
5267 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5268 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5269 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5271 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5273 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5274 This->stateBlock->streamSource[0] = NULL;
5275 This->stateBlock->streamStride[0] = 0;
5276 ib = This->stateBlock->pIndexData;
5277 if(ib) {
5278 IWineD3DIndexBuffer_Release(ib);
5279 This->stateBlock->pIndexData = NULL;
5281 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5282 * SetStreamSource to specify a vertex buffer
5285 return WINED3D_OK;
5288 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5289 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5290 const WineDirect3DVertexStridedData *DrawPrimStrideData)
5292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5294 /* Mark the state dirty until we have nicer tracking
5295 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5296 * that value.
5298 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5299 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5300 This->stateBlock->baseVertexIndex = 0;
5301 This->up_strided = DrawPrimStrideData;
5302 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5303 This->up_strided = NULL;
5304 return WINED3D_OK;
5307 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5308 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5309 const WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, const void *pIndexData,
5310 WINED3DFORMAT IndexDataFormat)
5312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5313 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5315 /* Mark the state dirty until we have nicer tracking
5316 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5317 * that value.
5319 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5320 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5321 This->stateBlock->streamIsUP = TRUE;
5322 This->stateBlock->baseVertexIndex = 0;
5323 This->up_strided = DrawPrimStrideData;
5324 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5325 This->up_strided = NULL;
5326 return WINED3D_OK;
5329 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5330 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5331 * not callable by the app directly no parameter validation checks are needed here.
5333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5334 WINED3DLOCKED_BOX src;
5335 WINED3DLOCKED_BOX dst;
5336 HRESULT hr;
5337 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5339 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5340 * dirtification to improve loading performance.
5342 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5343 if(FAILED(hr)) return hr;
5344 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5345 if(FAILED(hr)) {
5346 IWineD3DVolume_UnlockBox(pSourceVolume);
5347 return hr;
5350 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5352 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5353 if(FAILED(hr)) {
5354 IWineD3DVolume_UnlockBox(pSourceVolume);
5355 } else {
5356 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5358 return hr;
5361 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5362 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5364 HRESULT hr = WINED3D_OK;
5365 WINED3DRESOURCETYPE sourceType;
5366 WINED3DRESOURCETYPE destinationType;
5367 int i ,levels;
5369 /* TODO: think about moving the code into IWineD3DBaseTexture */
5371 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5373 /* verify that the source and destination textures aren't NULL */
5374 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5375 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5376 This, pSourceTexture, pDestinationTexture);
5377 hr = WINED3DERR_INVALIDCALL;
5380 if (pSourceTexture == pDestinationTexture) {
5381 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5382 This, pSourceTexture, pDestinationTexture);
5383 hr = WINED3DERR_INVALIDCALL;
5385 /* Verify that the source and destination textures are the same type */
5386 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5387 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5389 if (sourceType != destinationType) {
5390 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5391 This);
5392 hr = WINED3DERR_INVALIDCALL;
5395 /* check that both textures have the identical numbers of levels */
5396 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5397 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5398 hr = WINED3DERR_INVALIDCALL;
5401 if (WINED3D_OK == hr) {
5403 /* Make sure that the destination texture is loaded */
5404 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5406 /* Update every surface level of the texture */
5407 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5409 switch (sourceType) {
5410 case WINED3DRTYPE_TEXTURE:
5412 IWineD3DSurface *srcSurface;
5413 IWineD3DSurface *destSurface;
5415 for (i = 0 ; i < levels ; ++i) {
5416 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5417 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5418 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5419 IWineD3DSurface_Release(srcSurface);
5420 IWineD3DSurface_Release(destSurface);
5421 if (WINED3D_OK != hr) {
5422 WARN("(%p) : Call to update surface failed\n", This);
5423 return hr;
5427 break;
5428 case WINED3DRTYPE_CUBETEXTURE:
5430 IWineD3DSurface *srcSurface;
5431 IWineD3DSurface *destSurface;
5432 WINED3DCUBEMAP_FACES faceType;
5434 for (i = 0 ; i < levels ; ++i) {
5435 /* Update each cube face */
5436 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5437 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5438 if (WINED3D_OK != hr) {
5439 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5440 } else {
5441 TRACE("Got srcSurface %p\n", srcSurface);
5443 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5444 if (WINED3D_OK != hr) {
5445 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5446 } else {
5447 TRACE("Got desrSurface %p\n", destSurface);
5449 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5450 IWineD3DSurface_Release(srcSurface);
5451 IWineD3DSurface_Release(destSurface);
5452 if (WINED3D_OK != hr) {
5453 WARN("(%p) : Call to update surface failed\n", This);
5454 return hr;
5459 break;
5461 case WINED3DRTYPE_VOLUMETEXTURE:
5463 IWineD3DVolume *srcVolume = NULL;
5464 IWineD3DVolume *destVolume = NULL;
5466 for (i = 0 ; i < levels ; ++i) {
5467 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5468 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5469 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5470 IWineD3DVolume_Release(srcVolume);
5471 IWineD3DVolume_Release(destVolume);
5472 if (WINED3D_OK != hr) {
5473 WARN("(%p) : Call to update volume failed\n", This);
5474 return hr;
5478 break;
5480 default:
5481 FIXME("(%p) : Unsupported source and destination type\n", This);
5482 hr = WINED3DERR_INVALIDCALL;
5486 return hr;
5489 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5490 IWineD3DSwapChain *swapChain;
5491 HRESULT hr;
5492 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5493 if(hr == WINED3D_OK) {
5494 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5495 IWineD3DSwapChain_Release(swapChain);
5497 return hr;
5500 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5502 IWineD3DBaseTextureImpl *texture;
5503 const struct GlPixelFormatDesc *gl_info;
5504 DWORD i;
5506 TRACE("(%p) : %p\n", This, pNumPasses);
5508 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5509 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5510 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5511 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5513 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5514 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5515 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5518 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5519 if(!texture) continue;
5520 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5521 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5523 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5524 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5525 return E_FAIL;
5527 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5528 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5529 return E_FAIL;
5531 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5532 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5533 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5534 return E_FAIL;
5538 /* return a sensible default */
5539 *pNumPasses = 1;
5541 TRACE("returning D3D_OK\n");
5542 return WINED3D_OK;
5545 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5547 int i;
5549 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5550 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5551 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5552 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5557 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5559 int j;
5560 UINT NewSize;
5561 PALETTEENTRY **palettes;
5563 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5565 if (PaletteNumber >= MAX_PALETTES) {
5566 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5567 return WINED3DERR_INVALIDCALL;
5570 if (PaletteNumber >= This->NumberOfPalettes) {
5571 NewSize = This->NumberOfPalettes;
5572 do {
5573 NewSize *= 2;
5574 } while(PaletteNumber >= NewSize);
5575 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5576 if (!palettes) {
5577 ERR("Out of memory!\n");
5578 return E_OUTOFMEMORY;
5580 This->palettes = palettes;
5581 This->NumberOfPalettes = NewSize;
5584 if (!This->palettes[PaletteNumber]) {
5585 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5586 if (!This->palettes[PaletteNumber]) {
5587 ERR("Out of memory!\n");
5588 return E_OUTOFMEMORY;
5592 for (j = 0; j < 256; ++j) {
5593 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5594 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5595 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5596 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5598 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5599 TRACE("(%p) : returning\n", This);
5600 return WINED3D_OK;
5603 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5605 int j;
5606 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5607 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5608 /* What happens in such situation isn't documented; Native seems to silently abort
5609 on such conditions. Return Invalid Call. */
5610 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5611 return WINED3DERR_INVALIDCALL;
5613 for (j = 0; j < 256; ++j) {
5614 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5615 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5616 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5617 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5619 TRACE("(%p) : returning\n", This);
5620 return WINED3D_OK;
5623 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5625 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5626 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5627 (tested with reference rasterizer). Return Invalid Call. */
5628 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5629 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5630 return WINED3DERR_INVALIDCALL;
5632 /*TODO: stateblocks */
5633 if (This->currentPalette != PaletteNumber) {
5634 This->currentPalette = PaletteNumber;
5635 dirtify_p8_texture_samplers(This);
5637 TRACE("(%p) : returning\n", This);
5638 return WINED3D_OK;
5641 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5643 if (PaletteNumber == NULL) {
5644 WARN("(%p) : returning Invalid Call\n", This);
5645 return WINED3DERR_INVALIDCALL;
5647 /*TODO: stateblocks */
5648 *PaletteNumber = This->currentPalette;
5649 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5650 return WINED3D_OK;
5653 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5655 static BOOL warned;
5656 if (!warned)
5658 FIXME("(%p) : stub\n", This);
5659 warned = TRUE;
5662 This->softwareVertexProcessing = bSoftware;
5663 return WINED3D_OK;
5667 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5669 static BOOL warned;
5670 if (!warned)
5672 FIXME("(%p) : stub\n", This);
5673 warned = TRUE;
5675 return This->softwareVertexProcessing;
5679 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5681 IWineD3DSwapChain *swapChain;
5682 HRESULT hr;
5684 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5686 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5687 if(hr == WINED3D_OK){
5688 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5689 IWineD3DSwapChain_Release(swapChain);
5690 }else{
5691 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5693 return hr;
5697 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5699 static BOOL warned;
5700 if(nSegments != 0.0f) {
5701 if (!warned)
5703 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5704 warned = TRUE;
5707 return WINED3D_OK;
5710 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5712 static BOOL warned;
5713 if (!warned)
5715 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5716 warned = TRUE;
5718 return 0.0f;
5721 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5723 /** TODO: remove casts to IWineD3DSurfaceImpl
5724 * NOTE: move code to surface to accomplish this
5725 ****************************************/
5726 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5727 int srcWidth, srcHeight;
5728 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5729 WINED3DFORMAT destFormat, srcFormat;
5730 UINT destSize;
5731 int srcLeft, destLeft, destTop;
5732 WINED3DPOOL srcPool, destPool;
5733 int offset = 0;
5734 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5735 glDescriptor *glDescription = NULL;
5736 GLenum dummy;
5737 int sampler;
5738 int bpp;
5739 CONVERT_TYPES convert = NO_CONVERSION;
5741 WINED3DSURFACE_DESC winedesc;
5743 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5744 memset(&winedesc, 0, sizeof(winedesc));
5745 winedesc.Width = &srcSurfaceWidth;
5746 winedesc.Height = &srcSurfaceHeight;
5747 winedesc.Pool = &srcPool;
5748 winedesc.Format = &srcFormat;
5750 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5752 winedesc.Width = &destSurfaceWidth;
5753 winedesc.Height = &destSurfaceHeight;
5754 winedesc.Pool = &destPool;
5755 winedesc.Format = &destFormat;
5756 winedesc.Size = &destSize;
5758 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5760 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5761 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5762 return WINED3DERR_INVALIDCALL;
5765 /* This call loads the opengl surface directly, instead of copying the surface to the
5766 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5767 * copy in sysmem and use regular surface loading.
5769 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5770 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5771 if(convert != NO_CONVERSION) {
5772 return IWineD3DSurface_BltFast(pDestinationSurface,
5773 pDestPoint ? pDestPoint->x : 0,
5774 pDestPoint ? pDestPoint->y : 0,
5775 pSourceSurface, pSourceRect, 0);
5778 if (destFormat == WINED3DFMT_UNKNOWN) {
5779 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5780 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5782 /* Get the update surface description */
5783 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5786 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5788 ENTER_GL();
5789 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5790 checkGLcall("glActiveTextureARB");
5791 LEAVE_GL();
5793 /* Make sure the surface is loaded and up to date */
5794 IWineD3DSurface_PreLoad(pDestinationSurface);
5795 IWineD3DSurface_BindTexture(pDestinationSurface);
5797 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5799 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5800 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5801 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5802 srcLeft = pSourceRect ? pSourceRect->left : 0;
5803 destLeft = pDestPoint ? pDestPoint->x : 0;
5804 destTop = pDestPoint ? pDestPoint->y : 0;
5807 /* This function doesn't support compressed textures
5808 the pitch is just bytesPerPixel * width */
5809 if(srcWidth != srcSurfaceWidth || srcLeft ){
5810 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5811 offset += srcLeft * pSrcSurface->bytesPerPixel;
5812 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5814 /* TODO DXT formats */
5816 if(pSourceRect != NULL && pSourceRect->top != 0){
5817 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5819 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5820 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
5821 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5823 /* Sanity check */
5824 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5826 /* need to lock the surface to get the data */
5827 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5830 ENTER_GL();
5832 /* TODO: Cube and volume support */
5833 if(rowoffset != 0){
5834 /* not a whole row so we have to do it a line at a time */
5835 int j;
5837 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5838 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5840 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5842 glTexSubImage2D(glDescription->target
5843 ,glDescription->level
5844 ,destLeft
5846 ,srcWidth
5848 ,glDescription->glFormat
5849 ,glDescription->glType
5850 ,data /* could be quicker using */
5852 data += rowoffset;
5855 } else { /* Full width, so just write out the whole texture */
5856 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5858 if (WINED3DFMT_DXT1 == destFormat ||
5859 WINED3DFMT_DXT2 == destFormat ||
5860 WINED3DFMT_DXT3 == destFormat ||
5861 WINED3DFMT_DXT4 == destFormat ||
5862 WINED3DFMT_DXT5 == destFormat) {
5863 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5864 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5865 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5866 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5867 } if (destFormat != srcFormat) {
5868 FIXME("Updating mixed format compressed texture is not curretly support\n");
5869 } else {
5870 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
5871 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
5873 } else {
5874 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5878 } else {
5879 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
5880 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
5883 checkGLcall("glTexSubImage2D");
5885 LEAVE_GL();
5887 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5888 sampler = This->rev_tex_unit_map[0];
5889 if (sampler != -1) {
5890 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5893 return WINED3D_OK;
5896 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5898 struct WineD3DRectPatch *patch;
5899 unsigned int i;
5900 struct list *e;
5901 BOOL found;
5902 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5904 if(!(Handle || pRectPatchInfo)) {
5905 /* TODO: Write a test for the return value, thus the FIXME */
5906 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5907 return WINED3DERR_INVALIDCALL;
5910 if(Handle) {
5911 i = PATCHMAP_HASHFUNC(Handle);
5912 found = FALSE;
5913 LIST_FOR_EACH(e, &This->patches[i]) {
5914 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5915 if(patch->Handle == Handle) {
5916 found = TRUE;
5917 break;
5921 if(!found) {
5922 TRACE("Patch does not exist. Creating a new one\n");
5923 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5924 patch->Handle = Handle;
5925 list_add_head(&This->patches[i], &patch->entry);
5926 } else {
5927 TRACE("Found existing patch %p\n", patch);
5929 } else {
5930 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5931 * attributes we have to tesselate, read back, and draw. This needs a patch
5932 * management structure instance. Create one.
5934 * A possible improvement is to check if a vertex shader is used, and if not directly
5935 * draw the patch.
5937 FIXME("Drawing an uncached patch. This is slow\n");
5938 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5941 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5942 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5943 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5944 HRESULT hr;
5945 TRACE("Tesselation density or patch info changed, retesselating\n");
5947 if(pRectPatchInfo) {
5948 patch->RectPatchInfo = *pRectPatchInfo;
5950 patch->numSegs[0] = pNumSegs[0];
5951 patch->numSegs[1] = pNumSegs[1];
5952 patch->numSegs[2] = pNumSegs[2];
5953 patch->numSegs[3] = pNumSegs[3];
5955 hr = tesselate_rectpatch(This, patch);
5956 if(FAILED(hr)) {
5957 WARN("Patch tesselation failed\n");
5959 /* Do not release the handle to store the params of the patch */
5960 if(!Handle) {
5961 HeapFree(GetProcessHeap(), 0, patch);
5963 return hr;
5967 This->currentPatch = patch;
5968 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5969 This->currentPatch = NULL;
5971 /* Destroy uncached patches */
5972 if(!Handle) {
5973 HeapFree(GetProcessHeap(), 0, patch->mem);
5974 HeapFree(GetProcessHeap(), 0, patch);
5976 return WINED3D_OK;
5979 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5981 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5982 FIXME("(%p) : Stub\n", This);
5983 return WINED3D_OK;
5986 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5988 int i;
5989 struct WineD3DRectPatch *patch;
5990 struct list *e;
5991 TRACE("(%p) Handle(%d)\n", This, Handle);
5993 i = PATCHMAP_HASHFUNC(Handle);
5994 LIST_FOR_EACH(e, &This->patches[i]) {
5995 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5996 if(patch->Handle == Handle) {
5997 TRACE("Deleting patch %p\n", patch);
5998 list_remove(&patch->entry);
5999 HeapFree(GetProcessHeap(), 0, patch->mem);
6000 HeapFree(GetProcessHeap(), 0, patch);
6001 return WINED3D_OK;
6005 /* TODO: Write a test for the return value */
6006 FIXME("Attempt to destroy nonexistent patch\n");
6007 return WINED3DERR_INVALIDCALL;
6010 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6011 HRESULT hr;
6012 IWineD3DSwapChain *swapchain;
6014 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6015 if (SUCCEEDED(hr)) {
6016 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6017 return swapchain;
6020 return NULL;
6023 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6025 IWineD3DSwapChain *swapchain;
6027 swapchain = get_swapchain(surface);
6028 if (swapchain) {
6029 GLenum buffer;
6031 TRACE("Surface %p is onscreen\n", surface);
6033 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6034 ENTER_GL();
6035 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6036 buffer = surface_get_gl_buffer(surface, swapchain);
6037 glDrawBuffer(buffer);
6038 checkGLcall("glDrawBuffer()");
6039 } else {
6040 TRACE("Surface %p is offscreen\n", surface);
6042 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6043 ENTER_GL();
6044 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6045 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6046 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6047 checkGLcall("glFramebufferRenderbufferEXT");
6050 if (rect) {
6051 glEnable(GL_SCISSOR_TEST);
6052 if(!swapchain) {
6053 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6054 } else {
6055 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6056 rect->x2 - rect->x1, rect->y2 - rect->y1);
6058 checkGLcall("glScissor");
6059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6060 } else {
6061 glDisable(GL_SCISSOR_TEST);
6063 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6065 glDisable(GL_BLEND);
6066 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6068 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6069 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6071 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6072 glClear(GL_COLOR_BUFFER_BIT);
6073 checkGLcall("glClear");
6075 if (This->activeContext->current_fbo) {
6076 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6077 } else {
6078 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6079 checkGLcall("glBindFramebuffer()");
6082 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6083 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6084 glDrawBuffer(GL_BACK);
6085 checkGLcall("glDrawBuffer()");
6088 LEAVE_GL();
6091 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6092 unsigned int r, g, b, a;
6093 DWORD ret;
6095 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6096 destfmt == WINED3DFMT_R8G8B8)
6097 return color;
6099 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6101 a = (color & 0xff000000) >> 24;
6102 r = (color & 0x00ff0000) >> 16;
6103 g = (color & 0x0000ff00) >> 8;
6104 b = (color & 0x000000ff) >> 0;
6106 switch(destfmt)
6108 case WINED3DFMT_R5G6B5:
6109 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6110 r = (r * 32) / 256;
6111 g = (g * 64) / 256;
6112 b = (b * 32) / 256;
6113 ret = r << 11;
6114 ret |= g << 5;
6115 ret |= b;
6116 TRACE("Returning %08x\n", ret);
6117 return ret;
6119 case WINED3DFMT_X1R5G5B5:
6120 case WINED3DFMT_A1R5G5B5:
6121 a = (a * 2) / 256;
6122 r = (r * 32) / 256;
6123 g = (g * 32) / 256;
6124 b = (b * 32) / 256;
6125 ret = a << 15;
6126 ret |= r << 10;
6127 ret |= g << 5;
6128 ret |= b << 0;
6129 TRACE("Returning %08x\n", ret);
6130 return ret;
6132 case WINED3DFMT_A8:
6133 TRACE("Returning %08x\n", a);
6134 return a;
6136 case WINED3DFMT_X4R4G4B4:
6137 case WINED3DFMT_A4R4G4B4:
6138 a = (a * 16) / 256;
6139 r = (r * 16) / 256;
6140 g = (g * 16) / 256;
6141 b = (b * 16) / 256;
6142 ret = a << 12;
6143 ret |= r << 8;
6144 ret |= g << 4;
6145 ret |= b << 0;
6146 TRACE("Returning %08x\n", ret);
6147 return ret;
6149 case WINED3DFMT_R3G3B2:
6150 r = (r * 8) / 256;
6151 g = (g * 8) / 256;
6152 b = (b * 4) / 256;
6153 ret = r << 5;
6154 ret |= g << 2;
6155 ret |= b << 0;
6156 TRACE("Returning %08x\n", ret);
6157 return ret;
6159 case WINED3DFMT_X8B8G8R8:
6160 case WINED3DFMT_A8B8G8R8:
6161 ret = a << 24;
6162 ret |= b << 16;
6163 ret |= g << 8;
6164 ret |= r << 0;
6165 TRACE("Returning %08x\n", ret);
6166 return ret;
6168 case WINED3DFMT_A2R10G10B10:
6169 a = (a * 4) / 256;
6170 r = (r * 1024) / 256;
6171 g = (g * 1024) / 256;
6172 b = (b * 1024) / 256;
6173 ret = a << 30;
6174 ret |= r << 20;
6175 ret |= g << 10;
6176 ret |= b << 0;
6177 TRACE("Returning %08x\n", ret);
6178 return ret;
6180 case WINED3DFMT_A2B10G10R10:
6181 a = (a * 4) / 256;
6182 r = (r * 1024) / 256;
6183 g = (g * 1024) / 256;
6184 b = (b * 1024) / 256;
6185 ret = a << 30;
6186 ret |= b << 20;
6187 ret |= g << 10;
6188 ret |= r << 0;
6189 TRACE("Returning %08x\n", ret);
6190 return ret;
6192 default:
6193 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6194 return 0;
6198 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6200 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6201 WINEDDBLTFX BltFx;
6202 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6204 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6205 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6206 return WINED3DERR_INVALIDCALL;
6209 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6210 color_fill_fbo(iface, pSurface, pRect, color);
6211 return WINED3D_OK;
6212 } else {
6213 /* Just forward this to the DirectDraw blitting engine */
6214 memset(&BltFx, 0, sizeof(BltFx));
6215 BltFx.dwSize = sizeof(BltFx);
6216 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6217 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6218 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6222 /* rendertarget and depth stencil functions */
6223 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6226 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6227 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6228 return WINED3DERR_INVALIDCALL;
6231 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6232 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6233 /* Note inc ref on returned surface */
6234 if(*ppRenderTarget != NULL)
6235 IWineD3DSurface_AddRef(*ppRenderTarget);
6236 return WINED3D_OK;
6239 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6241 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6242 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6243 IWineD3DSwapChainImpl *Swapchain;
6244 HRESULT hr;
6246 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6248 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6249 if(hr != WINED3D_OK) {
6250 ERR("Can't get the swapchain\n");
6251 return hr;
6254 /* Make sure to release the swapchain */
6255 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6257 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6258 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6259 return WINED3DERR_INVALIDCALL;
6261 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6262 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6263 return WINED3DERR_INVALIDCALL;
6266 if(Swapchain->frontBuffer != Front) {
6267 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6269 if(Swapchain->frontBuffer)
6270 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6271 Swapchain->frontBuffer = Front;
6273 if(Swapchain->frontBuffer) {
6274 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6278 if(Back && !Swapchain->backBuffer) {
6279 /* We need memory for the back buffer array - only one back buffer this way */
6280 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6281 if(!Swapchain->backBuffer) {
6282 ERR("Out of memory\n");
6283 return E_OUTOFMEMORY;
6287 if(Swapchain->backBuffer[0] != Back) {
6288 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6290 /* What to do about the context here in the case of multithreading? Not sure.
6291 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6293 ENTER_GL();
6294 if(!Swapchain->backBuffer[0]) {
6295 /* GL was told to draw to the front buffer at creation,
6296 * undo that
6298 glDrawBuffer(GL_BACK);
6299 checkGLcall("glDrawBuffer(GL_BACK)");
6300 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6301 Swapchain->presentParms.BackBufferCount = 1;
6302 } else if (!Back) {
6303 /* That makes problems - disable for now */
6304 /* glDrawBuffer(GL_FRONT); */
6305 checkGLcall("glDrawBuffer(GL_FRONT)");
6306 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6307 Swapchain->presentParms.BackBufferCount = 0;
6309 LEAVE_GL();
6311 if(Swapchain->backBuffer[0])
6312 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6313 Swapchain->backBuffer[0] = Back;
6315 if(Swapchain->backBuffer[0]) {
6316 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6317 } else {
6318 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6319 Swapchain->backBuffer = NULL;
6324 return WINED3D_OK;
6327 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6329 *ppZStencilSurface = This->stencilBufferTarget;
6330 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6332 if(*ppZStencilSurface != NULL) {
6333 /* Note inc ref on returned surface */
6334 IWineD3DSurface_AddRef(*ppZStencilSurface);
6335 return WINED3D_OK;
6336 } else {
6337 return WINED3DERR_NOTFOUND;
6341 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6342 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6345 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6346 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6347 GLenum gl_filter;
6348 POINT offset = {0, 0};
6350 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6351 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6352 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6353 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6355 switch (filter) {
6356 case WINED3DTEXF_LINEAR:
6357 gl_filter = GL_LINEAR;
6358 break;
6360 default:
6361 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6362 case WINED3DTEXF_NONE:
6363 case WINED3DTEXF_POINT:
6364 gl_filter = GL_NEAREST;
6365 break;
6368 /* Attach src surface to src fbo */
6369 src_swapchain = get_swapchain(src_surface);
6370 if (src_swapchain) {
6371 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6373 TRACE("Source surface %p is onscreen\n", src_surface);
6374 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6375 /* Make sure the drawable is up to date. In the offscreen case
6376 * attach_surface_fbo() implicitly takes care of this. */
6377 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6379 if(buffer == GL_FRONT) {
6380 RECT windowsize;
6381 UINT h;
6382 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6383 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6384 h = windowsize.bottom - windowsize.top;
6385 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6386 src_rect->y1 = offset.y + h - src_rect->y1;
6387 src_rect->y2 = offset.y + h - src_rect->y2;
6388 } else {
6389 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6390 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6393 ENTER_GL();
6394 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6395 glReadBuffer(buffer);
6396 checkGLcall("glReadBuffer()");
6397 } else {
6398 TRACE("Source surface %p is offscreen\n", src_surface);
6399 ENTER_GL();
6400 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6401 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6402 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6403 checkGLcall("glReadBuffer()");
6404 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6405 checkGLcall("glFramebufferRenderbufferEXT");
6407 LEAVE_GL();
6409 /* Attach dst surface to dst fbo */
6410 dst_swapchain = get_swapchain(dst_surface);
6411 if (dst_swapchain) {
6412 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6414 TRACE("Destination surface %p is onscreen\n", dst_surface);
6415 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6416 /* Make sure the drawable is up to date. In the offscreen case
6417 * attach_surface_fbo() implicitly takes care of this. */
6418 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6420 if(buffer == GL_FRONT) {
6421 RECT windowsize;
6422 UINT h;
6423 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6424 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6425 h = windowsize.bottom - windowsize.top;
6426 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6427 dst_rect->y1 = offset.y + h - dst_rect->y1;
6428 dst_rect->y2 = offset.y + h - dst_rect->y2;
6429 } else {
6430 /* Screen coords = window coords, surface height = window height */
6431 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6432 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6435 ENTER_GL();
6436 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6437 glDrawBuffer(buffer);
6438 checkGLcall("glDrawBuffer()");
6439 } else {
6440 TRACE("Destination surface %p is offscreen\n", dst_surface);
6442 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6443 if(!src_swapchain) {
6444 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6447 ENTER_GL();
6448 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6449 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6450 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6451 checkGLcall("glDrawBuffer()");
6452 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6453 checkGLcall("glFramebufferRenderbufferEXT");
6455 glDisable(GL_SCISSOR_TEST);
6456 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6458 if (flip) {
6459 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6460 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6461 checkGLcall("glBlitFramebuffer()");
6462 } else {
6463 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6464 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6465 checkGLcall("glBlitFramebuffer()");
6468 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6470 if (This->activeContext->current_fbo) {
6471 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6472 } else {
6473 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6474 checkGLcall("glBindFramebuffer()");
6477 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6478 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6479 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6480 glDrawBuffer(GL_BACK);
6481 checkGLcall("glDrawBuffer()");
6483 LEAVE_GL();
6486 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6488 WINED3DVIEWPORT viewport;
6490 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6492 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6493 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6494 This, RenderTargetIndex, GL_LIMITS(buffers));
6495 return WINED3DERR_INVALIDCALL;
6498 /* MSDN says that null disables the render target
6499 but a device must always be associated with a render target
6500 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6502 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6503 FIXME("Trying to set render target 0 to NULL\n");
6504 return WINED3DERR_INVALIDCALL;
6506 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6507 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);
6508 return WINED3DERR_INVALIDCALL;
6511 /* If we are trying to set what we already have, don't bother */
6512 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6513 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6514 return WINED3D_OK;
6516 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6517 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6518 This->render_targets[RenderTargetIndex] = pRenderTarget;
6520 /* Render target 0 is special */
6521 if(RenderTargetIndex == 0) {
6522 /* Finally, reset the viewport as the MSDN states. */
6523 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6524 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6525 viewport.X = 0;
6526 viewport.Y = 0;
6527 viewport.MaxZ = 1.0f;
6528 viewport.MinZ = 0.0f;
6529 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6530 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6531 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6533 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6535 return WINED3D_OK;
6538 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6540 HRESULT hr = WINED3D_OK;
6541 IWineD3DSurface *tmp;
6543 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6545 if (pNewZStencil == This->stencilBufferTarget) {
6546 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6547 } else {
6548 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6549 * depending on the renter target implementation being used.
6550 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6551 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6552 * stencil buffer and incur an extra memory overhead
6553 ******************************************************/
6555 if (This->stencilBufferTarget) {
6556 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6557 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6558 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6559 } else {
6560 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6561 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6562 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6566 tmp = This->stencilBufferTarget;
6567 This->stencilBufferTarget = pNewZStencil;
6568 /* should we be calling the parent or the wined3d surface? */
6569 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6570 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6571 hr = WINED3D_OK;
6573 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6574 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6575 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6576 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6577 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6581 return hr;
6584 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6585 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6587 /* TODO: the use of Impl is deprecated. */
6588 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6589 WINED3DLOCKED_RECT lockedRect;
6591 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6593 /* some basic validation checks */
6594 if(This->cursorTexture) {
6595 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6596 ENTER_GL();
6597 glDeleteTextures(1, &This->cursorTexture);
6598 LEAVE_GL();
6599 This->cursorTexture = 0;
6602 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6603 This->haveHardwareCursor = TRUE;
6604 else
6605 This->haveHardwareCursor = FALSE;
6607 if(pCursorBitmap) {
6608 WINED3DLOCKED_RECT rect;
6610 /* MSDN: Cursor must be A8R8G8B8 */
6611 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6612 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6613 return WINED3DERR_INVALIDCALL;
6616 /* MSDN: Cursor must be smaller than the display mode */
6617 if(pSur->currentDesc.Width > This->ddraw_width ||
6618 pSur->currentDesc.Height > This->ddraw_height) {
6619 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);
6620 return WINED3DERR_INVALIDCALL;
6623 if (!This->haveHardwareCursor) {
6624 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6626 /* Do not store the surface's pointer because the application may
6627 * release it after setting the cursor image. Windows doesn't
6628 * addref the set surface, so we can't do this either without
6629 * creating circular refcount dependencies. Copy out the gl texture
6630 * instead.
6632 This->cursorWidth = pSur->currentDesc.Width;
6633 This->cursorHeight = pSur->currentDesc.Height;
6634 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6636 const struct GlPixelFormatDesc *glDesc;
6637 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6638 char *mem, *bits = (char *)rect.pBits;
6639 GLint intfmt = glDesc->glInternal;
6640 GLint format = glDesc->glFormat;
6641 GLint type = glDesc->glType;
6642 INT height = This->cursorHeight;
6643 INT width = This->cursorWidth;
6644 INT bpp = tableEntry->bpp;
6645 INT i, sampler;
6647 /* Reformat the texture memory (pitch and width can be
6648 * different) */
6649 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6650 for(i = 0; i < height; i++)
6651 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6652 IWineD3DSurface_UnlockRect(pCursorBitmap);
6653 ENTER_GL();
6655 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6656 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6657 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6660 /* Make sure that a proper texture unit is selected */
6661 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6662 checkGLcall("glActiveTextureARB");
6663 sampler = This->rev_tex_unit_map[0];
6664 if (sampler != -1) {
6665 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6667 /* Create a new cursor texture */
6668 glGenTextures(1, &This->cursorTexture);
6669 checkGLcall("glGenTextures");
6670 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6671 checkGLcall("glBindTexture");
6672 /* Copy the bitmap memory into the cursor texture */
6673 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6674 HeapFree(GetProcessHeap(), 0, mem);
6675 checkGLcall("glTexImage2D");
6677 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6678 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6679 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6682 LEAVE_GL();
6684 else
6686 FIXME("A cursor texture was not returned.\n");
6687 This->cursorTexture = 0;
6690 else
6692 /* Draw a hardware cursor */
6693 ICONINFO cursorInfo;
6694 HCURSOR cursor;
6695 /* Create and clear maskBits because it is not needed for
6696 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6697 * chunks. */
6698 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6699 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6700 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6701 WINED3DLOCK_NO_DIRTY_UPDATE |
6702 WINED3DLOCK_READONLY
6704 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6705 pSur->currentDesc.Height);
6707 cursorInfo.fIcon = FALSE;
6708 cursorInfo.xHotspot = XHotSpot;
6709 cursorInfo.yHotspot = YHotSpot;
6710 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6711 pSur->currentDesc.Height, 1,
6712 1, &maskBits);
6713 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6714 pSur->currentDesc.Height, 1,
6715 32, lockedRect.pBits);
6716 IWineD3DSurface_UnlockRect(pCursorBitmap);
6717 /* Create our cursor and clean up. */
6718 cursor = CreateIconIndirect(&cursorInfo);
6719 SetCursor(cursor);
6720 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6721 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6722 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6723 This->hardwareCursor = cursor;
6724 HeapFree(GetProcessHeap(), 0, maskBits);
6728 This->xHotSpot = XHotSpot;
6729 This->yHotSpot = YHotSpot;
6730 return WINED3D_OK;
6733 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6735 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6737 This->xScreenSpace = XScreenSpace;
6738 This->yScreenSpace = YScreenSpace;
6740 return;
6744 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6746 BOOL oldVisible = This->bCursorVisible;
6747 POINT pt;
6749 TRACE("(%p) : visible(%d)\n", This, bShow);
6752 * When ShowCursor is first called it should make the cursor appear at the OS's last
6753 * known cursor position. Because of this, some applications just repetitively call
6754 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6756 GetCursorPos(&pt);
6757 This->xScreenSpace = pt.x;
6758 This->yScreenSpace = pt.y;
6760 if (This->haveHardwareCursor) {
6761 This->bCursorVisible = bShow;
6762 if (bShow)
6763 SetCursor(This->hardwareCursor);
6764 else
6765 SetCursor(NULL);
6767 else
6769 if (This->cursorTexture)
6770 This->bCursorVisible = bShow;
6773 return oldVisible;
6776 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6778 IWineD3DResourceImpl *resource;
6779 TRACE("(%p) : state (%u)\n", This, This->state);
6781 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6782 switch (This->state) {
6783 case WINED3D_OK:
6784 return WINED3D_OK;
6785 case WINED3DERR_DEVICELOST:
6787 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6788 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6789 return WINED3DERR_DEVICENOTRESET;
6791 return WINED3DERR_DEVICELOST;
6793 case WINED3DERR_DRIVERINTERNALERROR:
6794 return WINED3DERR_DRIVERINTERNALERROR;
6797 /* Unknown state */
6798 return WINED3DERR_DRIVERINTERNALERROR;
6802 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6804 /** FIXME: Resource tracking needs to be done,
6805 * The closes we can do to this is set the priorities of all managed textures low
6806 * and then reset them.
6807 ***********************************************************/
6808 FIXME("(%p) : stub\n", This);
6809 return WINED3D_OK;
6812 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6814 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6816 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6817 if(surface->Flags & SFLAG_DIBSECTION) {
6818 /* Release the DC */
6819 SelectObject(surface->hDC, surface->dib.holdbitmap);
6820 DeleteDC(surface->hDC);
6821 /* Release the DIB section */
6822 DeleteObject(surface->dib.DIBsection);
6823 surface->dib.bitmap_data = NULL;
6824 surface->resource.allocatedMemory = NULL;
6825 surface->Flags &= ~SFLAG_DIBSECTION;
6827 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6828 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6829 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6830 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6831 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6832 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6833 } else {
6834 surface->pow2Width = surface->pow2Height = 1;
6835 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6836 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6838 surface->glRect.left = 0;
6839 surface->glRect.top = 0;
6840 surface->glRect.right = surface->pow2Width;
6841 surface->glRect.bottom = surface->pow2Height;
6843 if(surface->glDescription.textureName) {
6844 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6845 ENTER_GL();
6846 glDeleteTextures(1, &surface->glDescription.textureName);
6847 LEAVE_GL();
6848 surface->glDescription.textureName = 0;
6849 surface->Flags &= ~SFLAG_CLIENT;
6851 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6852 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6853 surface->Flags |= SFLAG_NONPOW2;
6854 } else {
6855 surface->Flags &= ~SFLAG_NONPOW2;
6857 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6858 surface->resource.allocatedMemory = NULL;
6859 surface->resource.heapMemory = NULL;
6860 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6861 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6862 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6863 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6864 } else {
6865 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6869 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6870 TRACE("Unloading resource %p\n", resource);
6871 IWineD3DResource_UnLoad(resource);
6872 IWineD3DResource_Release(resource);
6873 return S_OK;
6876 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6878 UINT i, count;
6879 WINED3DDISPLAYMODE m;
6880 HRESULT hr;
6882 /* All Windowed modes are supported, as is leaving the current mode */
6883 if(pp->Windowed) return TRUE;
6884 if(!pp->BackBufferWidth) return TRUE;
6885 if(!pp->BackBufferHeight) return TRUE;
6887 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6888 for(i = 0; i < count; i++) {
6889 memset(&m, 0, sizeof(m));
6890 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6891 if(FAILED(hr)) {
6892 ERR("EnumAdapterModes failed\n");
6894 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6895 /* Mode found, it is supported */
6896 return TRUE;
6899 /* Mode not found -> not supported */
6900 return FALSE;
6903 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6905 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6906 UINT i;
6907 IWineD3DBaseShaderImpl *shader;
6909 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6910 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6911 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6914 ENTER_GL();
6915 if(This->depth_blt_texture) {
6916 glDeleteTextures(1, &This->depth_blt_texture);
6917 This->depth_blt_texture = 0;
6919 if (This->depth_blt_rb) {
6920 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
6921 This->depth_blt_rb = 0;
6922 This->depth_blt_rb_w = 0;
6923 This->depth_blt_rb_h = 0;
6925 LEAVE_GL();
6927 This->blitter->free_private(iface);
6928 This->frag_pipe->free_private(iface);
6929 This->shader_backend->shader_free_private(iface);
6931 ENTER_GL();
6932 for (i = 0; i < GL_LIMITS(textures); i++) {
6933 /* Textures are recreated below */
6934 glDeleteTextures(1, &This->dummyTextureName[i]);
6935 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6936 This->dummyTextureName[i] = 0;
6938 LEAVE_GL();
6940 while(This->numContexts) {
6941 DestroyContext(This, This->contexts[0]);
6943 This->activeContext = NULL;
6944 HeapFree(GetProcessHeap(), 0, swapchain->context);
6945 swapchain->context = NULL;
6946 swapchain->num_contexts = 0;
6949 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6951 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6952 HRESULT hr;
6953 IWineD3DSurfaceImpl *target;
6955 /* Recreate the primary swapchain's context */
6956 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6957 if(swapchain->backBuffer) {
6958 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6959 } else {
6960 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6962 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
6963 &swapchain->presentParms);
6964 swapchain->num_contexts = 1;
6965 This->activeContext = swapchain->context[0];
6967 create_dummy_textures(This);
6969 hr = This->shader_backend->shader_alloc_private(iface);
6970 if(FAILED(hr)) {
6971 ERR("Failed to recreate shader private data\n");
6972 goto err_out;
6974 hr = This->frag_pipe->alloc_private(iface);
6975 if(FAILED(hr)) {
6976 TRACE("Fragment pipeline private data couldn't be allocated\n");
6977 goto err_out;
6979 hr = This->blitter->alloc_private(iface);
6980 if(FAILED(hr)) {
6981 TRACE("Blitter private data couldn't be allocated\n");
6982 goto err_out;
6985 return WINED3D_OK;
6987 err_out:
6988 This->blitter->free_private(iface);
6989 This->frag_pipe->free_private(iface);
6990 This->shader_backend->shader_free_private(iface);
6991 return hr;
6994 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6996 IWineD3DSwapChainImpl *swapchain;
6997 HRESULT hr;
6998 BOOL DisplayModeChanged = FALSE;
6999 WINED3DDISPLAYMODE mode;
7000 TRACE("(%p)\n", This);
7002 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7003 if(FAILED(hr)) {
7004 ERR("Failed to get the first implicit swapchain\n");
7005 return hr;
7008 if(!is_display_mode_supported(This, pPresentationParameters)) {
7009 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7010 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7011 pPresentationParameters->BackBufferHeight);
7012 return WINED3DERR_INVALIDCALL;
7015 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7016 * on an existing gl context, so there's no real need for recreation.
7018 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7020 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7022 TRACE("New params:\n");
7023 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7024 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7025 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7026 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7027 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7028 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7029 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7030 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7031 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7032 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7033 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7034 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7035 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7037 /* No special treatment of these parameters. Just store them */
7038 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7039 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7040 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7041 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7043 /* What to do about these? */
7044 if(pPresentationParameters->BackBufferCount != 0 &&
7045 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7046 ERR("Cannot change the back buffer count yet\n");
7048 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7049 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7050 ERR("Cannot change the back buffer format yet\n");
7052 if(pPresentationParameters->hDeviceWindow != NULL &&
7053 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7054 ERR("Cannot change the device window yet\n");
7056 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7057 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7058 return WINED3DERR_INVALIDCALL;
7061 /* Reset the depth stencil */
7062 if (pPresentationParameters->EnableAutoDepthStencil)
7063 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7064 else
7065 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7067 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7069 if(pPresentationParameters->Windowed) {
7070 mode.Width = swapchain->orig_width;
7071 mode.Height = swapchain->orig_height;
7072 mode.RefreshRate = 0;
7073 mode.Format = swapchain->presentParms.BackBufferFormat;
7074 } else {
7075 mode.Width = pPresentationParameters->BackBufferWidth;
7076 mode.Height = pPresentationParameters->BackBufferHeight;
7077 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7078 mode.Format = swapchain->presentParms.BackBufferFormat;
7081 /* Should Width == 800 && Height == 0 set 800x600? */
7082 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7083 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7084 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7086 WINED3DVIEWPORT vp;
7087 UINT i;
7089 vp.X = 0;
7090 vp.Y = 0;
7091 vp.Width = pPresentationParameters->BackBufferWidth;
7092 vp.Height = pPresentationParameters->BackBufferHeight;
7093 vp.MinZ = 0;
7094 vp.MaxZ = 1;
7096 if(!pPresentationParameters->Windowed) {
7097 DisplayModeChanged = TRUE;
7099 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7100 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7102 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7103 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7104 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7106 if(This->auto_depth_stencil_buffer) {
7107 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7111 /* Now set the new viewport */
7112 IWineD3DDevice_SetViewport(iface, &vp);
7115 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7116 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7117 DisplayModeChanged) {
7119 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7121 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7122 if(swapchain->presentParms.Windowed) {
7123 /* switch from windowed to fs */
7124 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7125 pPresentationParameters->BackBufferWidth,
7126 pPresentationParameters->BackBufferHeight);
7127 } else {
7128 /* Fullscreen -> fullscreen mode change */
7129 MoveWindow(swapchain->win_handle, 0, 0,
7130 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7131 TRUE);
7133 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7134 /* Fullscreen -> windowed switch */
7135 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7137 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7138 } else if(!pPresentationParameters->Windowed) {
7139 DWORD style = This->style, exStyle = This->exStyle;
7140 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7141 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7142 * Reset to clear up their mess. Guild Wars also loses the device during that.
7144 This->style = 0;
7145 This->exStyle = 0;
7146 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7147 pPresentationParameters->BackBufferWidth,
7148 pPresentationParameters->BackBufferHeight);
7149 This->style = style;
7150 This->exStyle = exStyle;
7153 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7154 if(FAILED(hr)) {
7155 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7158 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7159 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7161 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7162 * first use
7164 return hr;
7167 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7169 /** FIXME: always true at the moment **/
7170 if(!bEnableDialogs) {
7171 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7173 return WINED3D_OK;
7177 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7179 TRACE("(%p) : pParameters %p\n", This, pParameters);
7181 *pParameters = This->createParms;
7182 return WINED3D_OK;
7185 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7186 IWineD3DSwapChain *swapchain;
7188 TRACE("Relaying to swapchain\n");
7190 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7191 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7192 IWineD3DSwapChain_Release(swapchain);
7194 return;
7197 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7198 IWineD3DSwapChain *swapchain;
7200 TRACE("Relaying to swapchain\n");
7202 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7203 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7204 IWineD3DSwapChain_Release(swapchain);
7206 return;
7210 /** ********************************************************
7211 * Notification functions
7212 ** ********************************************************/
7213 /** This function must be called in the release of a resource when ref == 0,
7214 * the contents of resource must still be correct,
7215 * any handles to other resource held by the caller must be closed
7216 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7217 *****************************************************/
7218 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7219 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7221 TRACE("(%p) : Adding Resource %p\n", This, resource);
7222 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7225 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7228 TRACE("(%p) : Removing resource %p\n", This, resource);
7230 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7234 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7236 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7237 int counter;
7239 TRACE("(%p) : resource %p\n", This, resource);
7241 context_resource_released(iface, resource, type);
7243 switch (type) {
7244 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7245 case WINED3DRTYPE_SURFACE: {
7246 unsigned int i;
7248 /* Cleanup any FBO attachments if d3d is enabled */
7249 if(This->d3d_initialized) {
7250 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7251 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7253 TRACE("Last active render target destroyed\n");
7254 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7255 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7256 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7257 * and the lastActiveRenderTarget member shouldn't matter
7259 if(swapchain) {
7260 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7261 TRACE("Activating primary back buffer\n");
7262 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7263 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7264 /* Single buffering environment */
7265 TRACE("Activating primary front buffer\n");
7266 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7267 } else {
7268 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7269 /* Implicit render target destroyed, that means the device is being destroyed
7270 * whatever we set here, it shouldn't matter
7272 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7274 } else {
7275 /* May happen during ddraw uninitialization */
7276 TRACE("Render target set, but swapchain does not exist!\n");
7277 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7281 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7282 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7283 This->render_targets[i] = NULL;
7286 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7287 This->stencilBufferTarget = NULL;
7291 break;
7293 case WINED3DRTYPE_TEXTURE:
7294 case WINED3DRTYPE_CUBETEXTURE:
7295 case WINED3DRTYPE_VOLUMETEXTURE:
7296 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7297 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7298 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7299 This->stateBlock->textures[counter] = NULL;
7301 if (This->updateStateBlock != This->stateBlock ){
7302 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7303 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7304 This->updateStateBlock->textures[counter] = NULL;
7308 break;
7309 case WINED3DRTYPE_VOLUME:
7310 /* TODO: nothing really? */
7311 break;
7312 case WINED3DRTYPE_VERTEXBUFFER:
7313 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7315 int streamNumber;
7316 TRACE("Cleaning up stream pointers\n");
7318 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7319 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7320 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7322 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7323 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7324 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7325 This->updateStateBlock->streamSource[streamNumber] = 0;
7326 /* Set changed flag? */
7329 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) */
7330 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7331 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7332 This->stateBlock->streamSource[streamNumber] = 0;
7337 break;
7338 case WINED3DRTYPE_INDEXBUFFER:
7339 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7340 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7341 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7342 This->updateStateBlock->pIndexData = NULL;
7345 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7346 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7347 This->stateBlock->pIndexData = NULL;
7351 break;
7352 default:
7353 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7354 break;
7358 /* Remove the resource from the resourceStore */
7359 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7361 TRACE("Resource released\n");
7365 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7367 IWineD3DResourceImpl *resource, *cursor;
7368 HRESULT ret;
7369 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7371 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7372 TRACE("enumerating resource %p\n", resource);
7373 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7374 ret = pCallback((IWineD3DResource *) resource, pData);
7375 if(ret == S_FALSE) {
7376 TRACE("Canceling enumeration\n");
7377 break;
7380 return WINED3D_OK;
7383 /**********************************************************
7384 * IWineD3DDevice VTbl follows
7385 **********************************************************/
7387 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7389 /*** IUnknown methods ***/
7390 IWineD3DDeviceImpl_QueryInterface,
7391 IWineD3DDeviceImpl_AddRef,
7392 IWineD3DDeviceImpl_Release,
7393 /*** IWineD3DDevice methods ***/
7394 IWineD3DDeviceImpl_GetParent,
7395 /*** Creation methods**/
7396 IWineD3DDeviceImpl_CreateVertexBuffer,
7397 IWineD3DDeviceImpl_CreateIndexBuffer,
7398 IWineD3DDeviceImpl_CreateStateBlock,
7399 IWineD3DDeviceImpl_CreateSurface,
7400 IWineD3DDeviceImpl_CreateTexture,
7401 IWineD3DDeviceImpl_CreateVolumeTexture,
7402 IWineD3DDeviceImpl_CreateVolume,
7403 IWineD3DDeviceImpl_CreateCubeTexture,
7404 IWineD3DDeviceImpl_CreateQuery,
7405 IWineD3DDeviceImpl_CreateSwapChain,
7406 IWineD3DDeviceImpl_CreateVertexDeclaration,
7407 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7408 IWineD3DDeviceImpl_CreateVertexShader,
7409 IWineD3DDeviceImpl_CreatePixelShader,
7410 IWineD3DDeviceImpl_CreatePalette,
7411 /*** Odd functions **/
7412 IWineD3DDeviceImpl_Init3D,
7413 IWineD3DDeviceImpl_InitGDI,
7414 IWineD3DDeviceImpl_Uninit3D,
7415 IWineD3DDeviceImpl_UninitGDI,
7416 IWineD3DDeviceImpl_SetMultithreaded,
7417 IWineD3DDeviceImpl_EvictManagedResources,
7418 IWineD3DDeviceImpl_GetAvailableTextureMem,
7419 IWineD3DDeviceImpl_GetBackBuffer,
7420 IWineD3DDeviceImpl_GetCreationParameters,
7421 IWineD3DDeviceImpl_GetDeviceCaps,
7422 IWineD3DDeviceImpl_GetDirect3D,
7423 IWineD3DDeviceImpl_GetDisplayMode,
7424 IWineD3DDeviceImpl_SetDisplayMode,
7425 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7426 IWineD3DDeviceImpl_GetRasterStatus,
7427 IWineD3DDeviceImpl_GetSwapChain,
7428 IWineD3DDeviceImpl_Reset,
7429 IWineD3DDeviceImpl_SetDialogBoxMode,
7430 IWineD3DDeviceImpl_SetCursorProperties,
7431 IWineD3DDeviceImpl_SetCursorPosition,
7432 IWineD3DDeviceImpl_ShowCursor,
7433 IWineD3DDeviceImpl_TestCooperativeLevel,
7434 /*** Getters and setters **/
7435 IWineD3DDeviceImpl_SetClipPlane,
7436 IWineD3DDeviceImpl_GetClipPlane,
7437 IWineD3DDeviceImpl_SetClipStatus,
7438 IWineD3DDeviceImpl_GetClipStatus,
7439 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7440 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7441 IWineD3DDeviceImpl_SetDepthStencilSurface,
7442 IWineD3DDeviceImpl_GetDepthStencilSurface,
7443 IWineD3DDeviceImpl_SetGammaRamp,
7444 IWineD3DDeviceImpl_GetGammaRamp,
7445 IWineD3DDeviceImpl_SetIndices,
7446 IWineD3DDeviceImpl_GetIndices,
7447 IWineD3DDeviceImpl_SetBaseVertexIndex,
7448 IWineD3DDeviceImpl_GetBaseVertexIndex,
7449 IWineD3DDeviceImpl_SetLight,
7450 IWineD3DDeviceImpl_GetLight,
7451 IWineD3DDeviceImpl_SetLightEnable,
7452 IWineD3DDeviceImpl_GetLightEnable,
7453 IWineD3DDeviceImpl_SetMaterial,
7454 IWineD3DDeviceImpl_GetMaterial,
7455 IWineD3DDeviceImpl_SetNPatchMode,
7456 IWineD3DDeviceImpl_GetNPatchMode,
7457 IWineD3DDeviceImpl_SetPaletteEntries,
7458 IWineD3DDeviceImpl_GetPaletteEntries,
7459 IWineD3DDeviceImpl_SetPixelShader,
7460 IWineD3DDeviceImpl_GetPixelShader,
7461 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7462 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7463 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7464 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7465 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7466 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7467 IWineD3DDeviceImpl_SetRenderState,
7468 IWineD3DDeviceImpl_GetRenderState,
7469 IWineD3DDeviceImpl_SetRenderTarget,
7470 IWineD3DDeviceImpl_GetRenderTarget,
7471 IWineD3DDeviceImpl_SetFrontBackBuffers,
7472 IWineD3DDeviceImpl_SetSamplerState,
7473 IWineD3DDeviceImpl_GetSamplerState,
7474 IWineD3DDeviceImpl_SetScissorRect,
7475 IWineD3DDeviceImpl_GetScissorRect,
7476 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7477 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7478 IWineD3DDeviceImpl_SetStreamSource,
7479 IWineD3DDeviceImpl_GetStreamSource,
7480 IWineD3DDeviceImpl_SetStreamSourceFreq,
7481 IWineD3DDeviceImpl_GetStreamSourceFreq,
7482 IWineD3DDeviceImpl_SetTexture,
7483 IWineD3DDeviceImpl_GetTexture,
7484 IWineD3DDeviceImpl_SetTextureStageState,
7485 IWineD3DDeviceImpl_GetTextureStageState,
7486 IWineD3DDeviceImpl_SetTransform,
7487 IWineD3DDeviceImpl_GetTransform,
7488 IWineD3DDeviceImpl_SetVertexDeclaration,
7489 IWineD3DDeviceImpl_GetVertexDeclaration,
7490 IWineD3DDeviceImpl_SetVertexShader,
7491 IWineD3DDeviceImpl_GetVertexShader,
7492 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7493 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7494 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7495 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7496 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7497 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7498 IWineD3DDeviceImpl_SetViewport,
7499 IWineD3DDeviceImpl_GetViewport,
7500 IWineD3DDeviceImpl_MultiplyTransform,
7501 IWineD3DDeviceImpl_ValidateDevice,
7502 IWineD3DDeviceImpl_ProcessVertices,
7503 /*** State block ***/
7504 IWineD3DDeviceImpl_BeginStateBlock,
7505 IWineD3DDeviceImpl_EndStateBlock,
7506 /*** Scene management ***/
7507 IWineD3DDeviceImpl_BeginScene,
7508 IWineD3DDeviceImpl_EndScene,
7509 IWineD3DDeviceImpl_Present,
7510 IWineD3DDeviceImpl_Clear,
7511 /*** Drawing ***/
7512 IWineD3DDeviceImpl_DrawPrimitive,
7513 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7514 IWineD3DDeviceImpl_DrawPrimitiveUP,
7515 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7516 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7517 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7518 IWineD3DDeviceImpl_DrawRectPatch,
7519 IWineD3DDeviceImpl_DrawTriPatch,
7520 IWineD3DDeviceImpl_DeletePatch,
7521 IWineD3DDeviceImpl_ColorFill,
7522 IWineD3DDeviceImpl_UpdateTexture,
7523 IWineD3DDeviceImpl_UpdateSurface,
7524 IWineD3DDeviceImpl_GetFrontBufferData,
7525 /*** object tracking ***/
7526 IWineD3DDeviceImpl_ResourceReleased,
7527 IWineD3DDeviceImpl_EnumResources
7530 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7531 WINED3DRS_ALPHABLENDENABLE ,
7532 WINED3DRS_ALPHAFUNC ,
7533 WINED3DRS_ALPHAREF ,
7534 WINED3DRS_ALPHATESTENABLE ,
7535 WINED3DRS_BLENDOP ,
7536 WINED3DRS_COLORWRITEENABLE ,
7537 WINED3DRS_DESTBLEND ,
7538 WINED3DRS_DITHERENABLE ,
7539 WINED3DRS_FILLMODE ,
7540 WINED3DRS_FOGDENSITY ,
7541 WINED3DRS_FOGEND ,
7542 WINED3DRS_FOGSTART ,
7543 WINED3DRS_LASTPIXEL ,
7544 WINED3DRS_SHADEMODE ,
7545 WINED3DRS_SRCBLEND ,
7546 WINED3DRS_STENCILENABLE ,
7547 WINED3DRS_STENCILFAIL ,
7548 WINED3DRS_STENCILFUNC ,
7549 WINED3DRS_STENCILMASK ,
7550 WINED3DRS_STENCILPASS ,
7551 WINED3DRS_STENCILREF ,
7552 WINED3DRS_STENCILWRITEMASK ,
7553 WINED3DRS_STENCILZFAIL ,
7554 WINED3DRS_TEXTUREFACTOR ,
7555 WINED3DRS_WRAP0 ,
7556 WINED3DRS_WRAP1 ,
7557 WINED3DRS_WRAP2 ,
7558 WINED3DRS_WRAP3 ,
7559 WINED3DRS_WRAP4 ,
7560 WINED3DRS_WRAP5 ,
7561 WINED3DRS_WRAP6 ,
7562 WINED3DRS_WRAP7 ,
7563 WINED3DRS_ZENABLE ,
7564 WINED3DRS_ZFUNC ,
7565 WINED3DRS_ZWRITEENABLE
7568 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7569 WINED3DTSS_ADDRESSW ,
7570 WINED3DTSS_ALPHAARG0 ,
7571 WINED3DTSS_ALPHAARG1 ,
7572 WINED3DTSS_ALPHAARG2 ,
7573 WINED3DTSS_ALPHAOP ,
7574 WINED3DTSS_BUMPENVLOFFSET ,
7575 WINED3DTSS_BUMPENVLSCALE ,
7576 WINED3DTSS_BUMPENVMAT00 ,
7577 WINED3DTSS_BUMPENVMAT01 ,
7578 WINED3DTSS_BUMPENVMAT10 ,
7579 WINED3DTSS_BUMPENVMAT11 ,
7580 WINED3DTSS_COLORARG0 ,
7581 WINED3DTSS_COLORARG1 ,
7582 WINED3DTSS_COLORARG2 ,
7583 WINED3DTSS_COLOROP ,
7584 WINED3DTSS_RESULTARG ,
7585 WINED3DTSS_TEXCOORDINDEX ,
7586 WINED3DTSS_TEXTURETRANSFORMFLAGS
7589 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7590 WINED3DSAMP_ADDRESSU ,
7591 WINED3DSAMP_ADDRESSV ,
7592 WINED3DSAMP_ADDRESSW ,
7593 WINED3DSAMP_BORDERCOLOR ,
7594 WINED3DSAMP_MAGFILTER ,
7595 WINED3DSAMP_MINFILTER ,
7596 WINED3DSAMP_MIPFILTER ,
7597 WINED3DSAMP_MIPMAPLODBIAS ,
7598 WINED3DSAMP_MAXMIPLEVEL ,
7599 WINED3DSAMP_MAXANISOTROPY ,
7600 WINED3DSAMP_SRGBTEXTURE ,
7601 WINED3DSAMP_ELEMENTINDEX
7604 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7605 WINED3DRS_AMBIENT ,
7606 WINED3DRS_AMBIENTMATERIALSOURCE ,
7607 WINED3DRS_CLIPPING ,
7608 WINED3DRS_CLIPPLANEENABLE ,
7609 WINED3DRS_COLORVERTEX ,
7610 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7611 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7612 WINED3DRS_FOGDENSITY ,
7613 WINED3DRS_FOGEND ,
7614 WINED3DRS_FOGSTART ,
7615 WINED3DRS_FOGTABLEMODE ,
7616 WINED3DRS_FOGVERTEXMODE ,
7617 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7618 WINED3DRS_LIGHTING ,
7619 WINED3DRS_LOCALVIEWER ,
7620 WINED3DRS_MULTISAMPLEANTIALIAS ,
7621 WINED3DRS_MULTISAMPLEMASK ,
7622 WINED3DRS_NORMALIZENORMALS ,
7623 WINED3DRS_PATCHEDGESTYLE ,
7624 WINED3DRS_POINTSCALE_A ,
7625 WINED3DRS_POINTSCALE_B ,
7626 WINED3DRS_POINTSCALE_C ,
7627 WINED3DRS_POINTSCALEENABLE ,
7628 WINED3DRS_POINTSIZE ,
7629 WINED3DRS_POINTSIZE_MAX ,
7630 WINED3DRS_POINTSIZE_MIN ,
7631 WINED3DRS_POINTSPRITEENABLE ,
7632 WINED3DRS_RANGEFOGENABLE ,
7633 WINED3DRS_SPECULARMATERIALSOURCE ,
7634 WINED3DRS_TWEENFACTOR ,
7635 WINED3DRS_VERTEXBLEND ,
7636 WINED3DRS_CULLMODE ,
7637 WINED3DRS_FOGCOLOR
7640 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7641 WINED3DTSS_TEXCOORDINDEX ,
7642 WINED3DTSS_TEXTURETRANSFORMFLAGS
7645 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7646 WINED3DSAMP_DMAPOFFSET
7649 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7650 DWORD rep = This->StateTable[state].representative;
7651 DWORD idx;
7652 BYTE shift;
7653 UINT i;
7654 WineD3DContext *context;
7656 if(!rep) return;
7657 for(i = 0; i < This->numContexts; i++) {
7658 context = This->contexts[i];
7659 if(isStateDirty(context, rep)) continue;
7661 context->dirtyArray[context->numDirtyEntries++] = rep;
7662 idx = rep >> 5;
7663 shift = rep & 0x1f;
7664 context->isStateDirty[idx] |= (1 << shift);
7668 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7669 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7670 /* The drawable size of a pbuffer render target is the current pbuffer size
7672 *width = dev->pbufferWidth;
7673 *height = dev->pbufferHeight;
7676 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7677 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7679 *width = This->pow2Width;
7680 *height = This->pow2Height;
7683 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7684 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7685 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7686 * current context's drawable, which is the size of the back buffer of the swapchain
7687 * the active context belongs to. The back buffer of the swapchain is stored as the
7688 * surface the context belongs to.
7690 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7691 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;