push 15b96ea46b12fa9aa8d3d4072be1bf1f7af34661
[wine/hacks.git] / dlls / wined3d / device.c
blob79c9f68de32acb6c5731e4513a93a4bf8dbcd657
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 WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
66 object->ref = 1; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 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[i] = TRUE;
462 object->num_contained_ps_consts_b = MAX_CONST_B;
463 for (i = 0; i < MAX_CONST_I; ++i) {
464 object->contained_ps_consts_i[i] = i;
465 object->changed.pixelShaderConstantsI[i] = TRUE;
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->changed.vertexShaderConstantsB[i] = TRUE;
518 object->contained_vs_consts_b[i] = i;
520 object->num_contained_vs_consts_b = MAX_CONST_B;
521 for (i = 0; i < MAX_CONST_I; ++i) {
522 object->changed.vertexShaderConstantsI[i] = TRUE;
523 object->contained_vs_consts_i[i] = i;
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 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 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 pow2Width = Width;
825 pow2Height = Height;
826 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
827 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
828 (Width != pow2Width || Height != pow2Height) &&
829 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
831 object->baseTexture.pow2Matrix[0] = (float)Width;
832 object->baseTexture.pow2Matrix[5] = (float)Height;
833 object->baseTexture.pow2Matrix[10] = 1.0;
834 object->baseTexture.pow2Matrix[15] = 1.0;
835 object->target = GL_TEXTURE_RECTANGLE_ARB;
836 object->cond_np2 = TRUE;
837 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
838 } else {
839 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
840 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
841 object->baseTexture.pow2Matrix[10] = 1.0;
842 object->baseTexture.pow2Matrix[15] = 1.0;
843 object->target = GL_TEXTURE_2D;
844 object->cond_np2 = FALSE;
846 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
848 /* Calculate levels for mip mapping */
849 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
850 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
851 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
852 return WINED3DERR_INVALIDCALL;
854 if(Levels > 1) {
855 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
856 return WINED3DERR_INVALIDCALL;
858 object->baseTexture.levels = 1;
859 } else if (Levels == 0) {
860 TRACE("calculating levels %d\n", object->baseTexture.levels);
861 object->baseTexture.levels++;
862 tmpW = Width;
863 tmpH = Height;
864 while (tmpW > 1 || tmpH > 1) {
865 tmpW = max(1, tmpW >> 1);
866 tmpH = max(1, tmpH >> 1);
867 object->baseTexture.levels++;
869 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
872 /* Generate all the surfaces */
873 tmpW = Width;
874 tmpH = Height;
875 for (i = 0; i < object->baseTexture.levels; i++)
877 /* use the callback to create the texture surface */
878 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
879 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
880 FIXME("Failed to create surface %p\n", object);
881 /* clean up */
882 object->surfaces[i] = NULL;
883 IWineD3DTexture_Release((IWineD3DTexture *)object);
885 *ppTexture = NULL;
886 return hr;
889 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
890 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
891 surface_set_texture_target(object->surfaces[i], object->target);
892 /* calculate the next mipmap level */
893 tmpW = max(1, tmpW >> 1);
894 tmpH = max(1, tmpH >> 1);
896 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
898 TRACE("(%p) : Created texture %p\n", This, object);
899 return WINED3D_OK;
902 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
903 UINT Width, UINT Height, UINT Depth,
904 UINT Levels, DWORD Usage,
905 WINED3DFORMAT Format, WINED3DPOOL Pool,
906 IWineD3DVolumeTexture **ppVolumeTexture,
907 HANDLE *pSharedHandle, IUnknown *parent,
908 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
911 IWineD3DVolumeTextureImpl *object;
912 unsigned int i;
913 UINT tmpW;
914 UINT tmpH;
915 UINT tmpD;
916 const GlPixelFormatDesc *glDesc;
918 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
920 /* TODO: It should only be possible to create textures for formats
921 that are reported as supported */
922 if (WINED3DFMT_UNKNOWN >= Format) {
923 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
924 return WINED3DERR_INVALIDCALL;
926 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
927 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
928 return WINED3DERR_INVALIDCALL;
931 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
932 D3DINITIALIZEBASETEXTURE(object->baseTexture);
934 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
935 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
937 object->width = Width;
938 object->height = Height;
939 object->depth = Depth;
941 /* Is NP2 support for volumes needed? */
942 object->baseTexture.pow2Matrix[ 0] = 1.0;
943 object->baseTexture.pow2Matrix[ 5] = 1.0;
944 object->baseTexture.pow2Matrix[10] = 1.0;
945 object->baseTexture.pow2Matrix[15] = 1.0;
947 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
948 object->baseTexture.minMipLookup = &minMipLookup;
949 object->baseTexture.magLookup = &magLookup;
950 } else {
951 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
952 object->baseTexture.magLookup = &magLookup_noFilter;
955 /* Calculate levels for mip mapping */
956 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
957 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
958 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
959 return WINED3DERR_INVALIDCALL;
961 if(Levels > 1) {
962 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
963 return WINED3DERR_INVALIDCALL;
965 Levels = 1;
966 } else if (Levels == 0) {
967 object->baseTexture.levels++;
968 tmpW = Width;
969 tmpH = Height;
970 tmpD = Depth;
971 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
972 tmpW = max(1, tmpW >> 1);
973 tmpH = max(1, tmpH >> 1);
974 tmpD = max(1, tmpD >> 1);
975 object->baseTexture.levels++;
977 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
980 /* Generate all the surfaces */
981 tmpW = Width;
982 tmpH = Height;
983 tmpD = Depth;
985 for (i = 0; i < object->baseTexture.levels; i++)
987 HRESULT hr;
988 /* Create the volume */
989 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
990 &object->volumes[i], pSharedHandle);
992 if(FAILED(hr)) {
993 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
994 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
995 *ppVolumeTexture = NULL;
996 return hr;
999 /* Set its container to this object */
1000 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1002 /* calculate the next mipmap level */
1003 tmpW = max(1, tmpW >> 1);
1004 tmpH = max(1, tmpH >> 1);
1005 tmpD = max(1, tmpD >> 1);
1007 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1009 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1010 TRACE("(%p) : Created volume texture %p\n", This, object);
1011 return WINED3D_OK;
1014 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1015 UINT Width, UINT Height, UINT Depth,
1016 DWORD Usage,
1017 WINED3DFORMAT Format, WINED3DPOOL Pool,
1018 IWineD3DVolume** ppVolume,
1019 HANDLE* pSharedHandle, IUnknown *parent) {
1021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1022 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1023 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1025 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1026 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1027 return WINED3DERR_INVALIDCALL;
1030 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1032 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1033 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1035 object->currentDesc.Width = Width;
1036 object->currentDesc.Height = Height;
1037 object->currentDesc.Depth = Depth;
1038 object->bytesPerPixel = formatDesc->bpp;
1040 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1041 object->lockable = TRUE;
1042 object->locked = FALSE;
1043 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1044 object->dirty = TRUE;
1046 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1049 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1050 UINT Levels, DWORD Usage,
1051 WINED3DFORMAT Format, WINED3DPOOL Pool,
1052 IWineD3DCubeTexture **ppCubeTexture,
1053 HANDLE *pSharedHandle, IUnknown *parent,
1054 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1057 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1058 unsigned int i, j;
1059 UINT tmpW;
1060 HRESULT hr;
1061 unsigned int pow2EdgeLength = EdgeLength;
1062 const GlPixelFormatDesc *glDesc;
1063 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1065 /* TODO: It should only be possible to create textures for formats
1066 that are reported as supported */
1067 if (WINED3DFMT_UNKNOWN >= Format) {
1068 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1069 return WINED3DERR_INVALIDCALL;
1072 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1073 WARN("(%p) : Tried to create not supported cube texture\n", This);
1074 return WINED3DERR_INVALIDCALL;
1077 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1078 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1080 TRACE("(%p) Create Cube Texture\n", This);
1082 /** Non-power2 support **/
1084 /* Find the nearest pow2 match */
1085 pow2EdgeLength = 1;
1086 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1088 object->edgeLength = EdgeLength;
1089 /* TODO: support for native non-power 2 */
1090 /* Precalculated scaling for 'faked' non power of two texture coords */
1091 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1092 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1093 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1094 object->baseTexture.pow2Matrix[15] = 1.0;
1096 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1097 object->baseTexture.minMipLookup = &minMipLookup;
1098 object->baseTexture.magLookup = &magLookup;
1099 } else {
1100 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
1101 object->baseTexture.magLookup = &magLookup_noFilter;
1104 /* Calculate levels for mip mapping */
1105 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1106 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1107 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1108 HeapFree(GetProcessHeap(), 0, object);
1109 *ppCubeTexture = NULL;
1111 return WINED3DERR_INVALIDCALL;
1113 if(Levels > 1) {
1114 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1115 HeapFree(GetProcessHeap(), 0, object);
1116 *ppCubeTexture = NULL;
1118 return WINED3DERR_INVALIDCALL;
1120 Levels = 1;
1121 } else if (Levels == 0) {
1122 object->baseTexture.levels++;
1123 tmpW = EdgeLength;
1124 while (tmpW > 1) {
1125 tmpW = max(1, tmpW >> 1);
1126 object->baseTexture.levels++;
1128 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1131 /* Generate all the surfaces */
1132 tmpW = EdgeLength;
1133 for (i = 0; i < object->baseTexture.levels; i++) {
1135 /* Create the 6 faces */
1136 for (j = 0; j < 6; j++) {
1137 static const GLenum cube_targets[6] = {
1138 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1139 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1140 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1141 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1142 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1143 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1146 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1147 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1149 if(hr!= WINED3D_OK) {
1150 /* clean up */
1151 int k;
1152 int l;
1153 for (l = 0; l < j; l++) {
1154 IWineD3DSurface_Release(object->surfaces[l][i]);
1156 for (k = 0; k < i; k++) {
1157 for (l = 0; l < 6; l++) {
1158 IWineD3DSurface_Release(object->surfaces[l][k]);
1162 FIXME("(%p) Failed to create surface\n",object);
1163 HeapFree(GetProcessHeap(),0,object);
1164 *ppCubeTexture = NULL;
1165 return hr;
1167 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1168 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1169 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1171 tmpW = max(1, tmpW >> 1);
1173 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1175 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1176 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1177 return WINED3D_OK;
1180 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1182 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1183 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1184 const IWineD3DQueryVtbl *vtable;
1186 /* Just a check to see if we support this type of query */
1187 switch(Type) {
1188 case WINED3DQUERYTYPE_OCCLUSION:
1189 TRACE("(%p) occlusion query\n", This);
1190 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1191 hr = WINED3D_OK;
1192 else
1193 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1195 vtable = &IWineD3DOcclusionQuery_Vtbl;
1196 break;
1198 case WINED3DQUERYTYPE_EVENT:
1199 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1200 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1201 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1203 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1205 vtable = &IWineD3DEventQuery_Vtbl;
1206 hr = WINED3D_OK;
1207 break;
1209 case WINED3DQUERYTYPE_VCACHE:
1210 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1211 case WINED3DQUERYTYPE_VERTEXSTATS:
1212 case WINED3DQUERYTYPE_TIMESTAMP:
1213 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1214 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1215 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1216 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1217 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1218 case WINED3DQUERYTYPE_PIXELTIMINGS:
1219 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1220 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1221 default:
1222 /* Use the base Query vtable until we have a special one for each query */
1223 vtable = &IWineD3DQuery_Vtbl;
1224 FIXME("(%p) Unhandled query type %d\n", This, Type);
1226 if(NULL == ppQuery || hr != WINED3D_OK) {
1227 return hr;
1230 D3DCREATEOBJECTINSTANCE(object, Query)
1231 object->lpVtbl = vtable;
1232 object->type = Type;
1233 object->state = QUERY_CREATED;
1234 /* allocated the 'extended' data based on the type of query requested */
1235 switch(Type){
1236 case WINED3DQUERYTYPE_OCCLUSION:
1237 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1238 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1240 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1241 TRACE("(%p) Allocating data for an occlusion query\n", This);
1242 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1243 break;
1245 case WINED3DQUERYTYPE_EVENT:
1246 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1247 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1249 if(GL_SUPPORT(APPLE_FENCE)) {
1250 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1251 checkGLcall("glGenFencesAPPLE");
1252 } else if(GL_SUPPORT(NV_FENCE)) {
1253 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1254 checkGLcall("glGenFencesNV");
1256 break;
1258 case WINED3DQUERYTYPE_VCACHE:
1259 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1260 case WINED3DQUERYTYPE_VERTEXSTATS:
1261 case WINED3DQUERYTYPE_TIMESTAMP:
1262 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1263 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1264 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1265 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1266 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1267 case WINED3DQUERYTYPE_PIXELTIMINGS:
1268 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1269 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1270 default:
1271 object->extendedData = 0;
1272 FIXME("(%p) Unhandled query type %d\n",This , Type);
1274 TRACE("(%p) : Created Query %p\n", This, object);
1275 return WINED3D_OK;
1278 /*****************************************************************************
1279 * IWineD3DDeviceImpl_SetupFullscreenWindow
1281 * Helper function that modifies a HWND's Style and ExStyle for proper
1282 * fullscreen use.
1284 * Params:
1285 * iface: Pointer to the IWineD3DDevice interface
1286 * window: Window to setup
1288 *****************************************************************************/
1289 static LONG fullscreen_style(LONG orig_style) {
1290 LONG style = orig_style;
1291 style &= ~WS_CAPTION;
1292 style &= ~WS_THICKFRAME;
1294 /* Make sure the window is managed, otherwise we won't get keyboard input */
1295 style |= WS_POPUP | WS_SYSMENU;
1297 return style;
1300 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1301 LONG exStyle = orig_exStyle;
1303 /* Filter out window decorations */
1304 exStyle &= ~WS_EX_WINDOWEDGE;
1305 exStyle &= ~WS_EX_CLIENTEDGE;
1307 return exStyle;
1310 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1313 LONG style, exStyle;
1314 /* Don't do anything if an original style is stored.
1315 * That shouldn't happen
1317 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1318 if (This->style || This->exStyle) {
1319 ERR("(%p): Want to change the window parameters of HWND %p, but "
1320 "another style is stored for restoration afterwards\n", This, window);
1323 /* Get the parameters and save them */
1324 style = GetWindowLongW(window, GWL_STYLE);
1325 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1326 This->style = style;
1327 This->exStyle = exStyle;
1329 style = fullscreen_style(style);
1330 exStyle = fullscreen_exStyle(exStyle);
1332 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1333 This->style, This->exStyle, style, exStyle);
1335 SetWindowLongW(window, GWL_STYLE, style);
1336 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1338 /* Inform the window about the update. */
1339 SetWindowPos(window, HWND_TOP, 0, 0,
1340 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1343 /*****************************************************************************
1344 * IWineD3DDeviceImpl_RestoreWindow
1346 * Helper function that restores a windows' properties when taking it out
1347 * of fullscreen mode
1349 * Params:
1350 * iface: Pointer to the IWineD3DDevice interface
1351 * window: Window to setup
1353 *****************************************************************************/
1354 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1356 LONG style, exStyle;
1358 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1359 * switch, do nothing
1361 if (!This->style && !This->exStyle) return;
1363 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1364 This, window, This->style, This->exStyle);
1366 style = GetWindowLongW(window, GWL_STYLE);
1367 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1369 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1370 * Some applications change it before calling Reset() when switching between windowed and
1371 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1373 if(style == fullscreen_style(This->style) &&
1374 exStyle == fullscreen_style(This->exStyle)) {
1375 SetWindowLongW(window, GWL_STYLE, This->style);
1376 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1379 /* Delete the old values */
1380 This->style = 0;
1381 This->exStyle = 0;
1383 /* Inform the window about the update */
1384 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1385 0, 0, 0, 0, /* Pos, Size, ignored */
1386 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1389 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1390 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1391 IUnknown* parent,
1392 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1393 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil,
1394 WINED3DSURFTYPE surface_type) {
1395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1397 HDC hDc;
1398 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1399 HRESULT hr;
1400 IUnknown *bufferParent;
1401 BOOL displaymode_set = FALSE;
1402 WINED3DDISPLAYMODE Mode;
1403 const StaticPixelFormatDesc *formatDesc;
1405 TRACE("(%p) : Created Additional Swap Chain\n", This);
1407 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1408 * does a device hold a reference to a swap chain giving them a lifetime of the device
1409 * or does the swap chain notify the device of its destruction.
1410 *******************************/
1412 /* Check the params */
1413 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1414 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1415 return WINED3DERR_INVALIDCALL;
1416 } else if (pPresentationParameters->BackBufferCount > 1) {
1417 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1420 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1421 switch(surface_type) {
1422 case SURFACE_GDI:
1423 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1424 break;
1425 case SURFACE_OPENGL:
1426 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1427 break;
1428 case SURFACE_UNKNOWN:
1429 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1430 return WINED3DERR_INVALIDCALL;
1433 /*********************
1434 * Lookup the window Handle and the relating X window handle
1435 ********************/
1437 /* Setup hwnd we are using, plus which display this equates to */
1438 object->win_handle = pPresentationParameters->hDeviceWindow;
1439 if (!object->win_handle) {
1440 object->win_handle = This->createParms.hFocusWindow;
1442 if(!pPresentationParameters->Windowed && object->win_handle) {
1443 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1444 pPresentationParameters->BackBufferWidth,
1445 pPresentationParameters->BackBufferHeight);
1448 hDc = GetDC(object->win_handle);
1449 TRACE("Using hDc %p\n", hDc);
1451 if (NULL == hDc) {
1452 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1453 return WINED3DERR_NOTAVAILABLE;
1456 /* Get info on the current display setup */
1457 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1458 object->orig_width = Mode.Width;
1459 object->orig_height = Mode.Height;
1460 object->orig_fmt = Mode.Format;
1461 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1463 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1464 * then the corresponding dimension of the client area of the hDeviceWindow
1465 * (or the focus window, if hDeviceWindow is NULL) is taken.
1466 **********************/
1468 if (pPresentationParameters->Windowed &&
1469 ((pPresentationParameters->BackBufferWidth == 0) ||
1470 (pPresentationParameters->BackBufferHeight == 0) ||
1471 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1473 RECT Rect;
1474 GetClientRect(object->win_handle, &Rect);
1476 if (pPresentationParameters->BackBufferWidth == 0) {
1477 pPresentationParameters->BackBufferWidth = Rect.right;
1478 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1480 if (pPresentationParameters->BackBufferHeight == 0) {
1481 pPresentationParameters->BackBufferHeight = Rect.bottom;
1482 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1484 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1485 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1486 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1490 /* Put the correct figures in the presentation parameters */
1491 TRACE("Copying across presentation parameters\n");
1492 object->presentParms = *pPresentationParameters;
1494 TRACE("calling rendertarget CB\n");
1495 hr = D3DCB_CreateRenderTarget(This->parent,
1496 parent,
1497 object->presentParms.BackBufferWidth,
1498 object->presentParms.BackBufferHeight,
1499 object->presentParms.BackBufferFormat,
1500 object->presentParms.MultiSampleType,
1501 object->presentParms.MultiSampleQuality,
1502 TRUE /* Lockable */,
1503 &object->frontBuffer,
1504 NULL /* pShared (always null)*/);
1505 if (SUCCEEDED(hr)) {
1506 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1507 if(surface_type == SURFACE_OPENGL) {
1508 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1510 } else {
1511 ERR("Failed to create the front buffer\n");
1512 goto error;
1515 /*********************
1516 * Windowed / Fullscreen
1517 *******************/
1520 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1521 * so we should really check to see if there is a fullscreen swapchain already
1522 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1523 **************************************/
1525 if (!pPresentationParameters->Windowed) {
1526 WINED3DDISPLAYMODE mode;
1529 /* Change the display settings */
1530 mode.Width = pPresentationParameters->BackBufferWidth;
1531 mode.Height = pPresentationParameters->BackBufferHeight;
1532 mode.Format = pPresentationParameters->BackBufferFormat;
1533 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1535 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1536 displaymode_set = TRUE;
1540 * Create an opengl context for the display visual
1541 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1542 * use different properties after that point in time. FIXME: How to handle when requested format
1543 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1544 * it chooses is identical to the one already being used!
1545 **********************************/
1546 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1548 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1549 if(!object->context)
1550 return E_OUTOFMEMORY;
1551 object->num_contexts = 1;
1553 if(surface_type == SURFACE_OPENGL) {
1554 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1555 if (!object->context[0]) {
1556 ERR("Failed to create a new context\n");
1557 hr = WINED3DERR_NOTAVAILABLE;
1558 goto error;
1559 } else {
1560 TRACE("Context created (HWND=%p, glContext=%p)\n",
1561 object->win_handle, object->context[0]->glCtx);
1565 /*********************
1566 * Create the back, front and stencil buffers
1567 *******************/
1568 if(object->presentParms.BackBufferCount > 0) {
1569 int i;
1571 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1572 if(!object->backBuffer) {
1573 ERR("Out of memory\n");
1574 hr = E_OUTOFMEMORY;
1575 goto error;
1578 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1579 TRACE("calling rendertarget CB\n");
1580 hr = D3DCB_CreateRenderTarget(This->parent,
1581 parent,
1582 object->presentParms.BackBufferWidth,
1583 object->presentParms.BackBufferHeight,
1584 object->presentParms.BackBufferFormat,
1585 object->presentParms.MultiSampleType,
1586 object->presentParms.MultiSampleQuality,
1587 TRUE /* Lockable */,
1588 &object->backBuffer[i],
1589 NULL /* pShared (always null)*/);
1590 if(SUCCEEDED(hr)) {
1591 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1592 } else {
1593 ERR("Cannot create new back buffer\n");
1594 goto error;
1596 if(surface_type == SURFACE_OPENGL) {
1597 ENTER_GL();
1598 glDrawBuffer(GL_BACK);
1599 checkGLcall("glDrawBuffer(GL_BACK)");
1600 LEAVE_GL();
1603 } else {
1604 object->backBuffer = NULL;
1606 /* Single buffering - draw to front buffer */
1607 if(surface_type == SURFACE_OPENGL) {
1608 ENTER_GL();
1609 glDrawBuffer(GL_FRONT);
1610 checkGLcall("glDrawBuffer(GL_FRONT)");
1611 LEAVE_GL();
1615 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1616 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1617 TRACE("Creating depth stencil buffer\n");
1618 if (This->auto_depth_stencil_buffer == NULL ) {
1619 hr = D3DCB_CreateDepthStencil(This->parent,
1620 parent,
1621 object->presentParms.BackBufferWidth,
1622 object->presentParms.BackBufferHeight,
1623 object->presentParms.AutoDepthStencilFormat,
1624 object->presentParms.MultiSampleType,
1625 object->presentParms.MultiSampleQuality,
1626 FALSE /* FIXME: Discard */,
1627 &This->auto_depth_stencil_buffer,
1628 NULL /* pShared (always null)*/ );
1629 if (SUCCEEDED(hr)) {
1630 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1631 } else {
1632 ERR("Failed to create the auto depth stencil\n");
1633 goto error;
1638 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1640 TRACE("Created swapchain %p\n", object);
1641 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1642 return WINED3D_OK;
1644 error:
1645 if (displaymode_set) {
1646 DEVMODEW devmode;
1647 RECT clip_rc;
1649 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1650 ClipCursor(NULL);
1652 /* Change the display settings */
1653 memset(&devmode, 0, sizeof(devmode));
1654 devmode.dmSize = sizeof(devmode);
1655 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1656 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1657 devmode.dmPelsWidth = object->orig_width;
1658 devmode.dmPelsHeight = object->orig_height;
1659 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1662 if (object->backBuffer) {
1663 int i;
1664 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1665 if(object->backBuffer[i]) {
1666 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1667 IUnknown_Release(bufferParent); /* once for the get parent */
1668 if (IUnknown_Release(bufferParent) > 0) {
1669 FIXME("(%p) Something's still holding the back buffer\n",This);
1673 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1674 object->backBuffer = NULL;
1676 if(object->context[0])
1677 DestroyContext(This, object->context[0]);
1678 if(object->frontBuffer) {
1679 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1680 IUnknown_Release(bufferParent); /* once for the get parent */
1681 if (IUnknown_Release(bufferParent) > 0) {
1682 FIXME("(%p) Something's still holding the front buffer\n",This);
1685 HeapFree(GetProcessHeap(), 0, object);
1686 return hr;
1689 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1690 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1692 TRACE("(%p)\n", This);
1694 return This->NumberOfSwapChains;
1697 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1699 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1701 if(iSwapChain < This->NumberOfSwapChains) {
1702 *pSwapChain = This->swapchains[iSwapChain];
1703 IWineD3DSwapChain_AddRef(*pSwapChain);
1704 TRACE("(%p) returning %p\n", This, *pSwapChain);
1705 return WINED3D_OK;
1706 } else {
1707 TRACE("Swapchain out of range\n");
1708 *pSwapChain = NULL;
1709 return WINED3DERR_INVALIDCALL;
1713 /*****
1714 * Vertex Declaration
1715 *****/
1716 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1717 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1719 IWineD3DVertexDeclarationImpl *object = NULL;
1720 HRESULT hr = WINED3D_OK;
1722 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1723 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1725 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1727 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1728 if(FAILED(hr)) {
1729 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1730 *ppVertexDeclaration = NULL;
1733 return hr;
1736 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1737 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1739 unsigned int idx, idx2;
1740 unsigned int offset;
1741 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1742 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1743 BOOL has_blend_idx = has_blend &&
1744 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1745 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1746 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1747 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1748 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1749 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1750 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1752 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1753 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1755 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1756 WINED3DVERTEXELEMENT *elements = NULL;
1758 unsigned int size;
1759 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1760 if (has_blend_idx) num_blends--;
1762 /* Compute declaration size */
1763 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1764 has_psize + has_diffuse + has_specular + num_textures + 1;
1766 /* convert the declaration */
1767 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1768 if (!elements)
1769 return 0;
1771 elements[size-1] = end_element;
1772 idx = 0;
1773 if (has_pos) {
1774 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1775 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1776 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1778 else {
1779 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1780 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1782 elements[idx].UsageIndex = 0;
1783 idx++;
1785 if (has_blend && (num_blends > 0)) {
1786 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1787 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1788 else
1789 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1790 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1791 elements[idx].UsageIndex = 0;
1792 idx++;
1794 if (has_blend_idx) {
1795 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1796 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1797 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1798 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1799 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1800 else
1801 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1802 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1803 elements[idx].UsageIndex = 0;
1804 idx++;
1806 if (has_normal) {
1807 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1808 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1809 elements[idx].UsageIndex = 0;
1810 idx++;
1812 if (has_psize) {
1813 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1814 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1815 elements[idx].UsageIndex = 0;
1816 idx++;
1818 if (has_diffuse) {
1819 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1820 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1821 elements[idx].UsageIndex = 0;
1822 idx++;
1824 if (has_specular) {
1825 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1826 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1827 elements[idx].UsageIndex = 1;
1828 idx++;
1830 for (idx2 = 0; idx2 < num_textures; idx2++) {
1831 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1832 switch (numcoords) {
1833 case WINED3DFVF_TEXTUREFORMAT1:
1834 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1835 break;
1836 case WINED3DFVF_TEXTUREFORMAT2:
1837 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1838 break;
1839 case WINED3DFVF_TEXTUREFORMAT3:
1840 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1841 break;
1842 case WINED3DFVF_TEXTUREFORMAT4:
1843 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1844 break;
1846 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1847 elements[idx].UsageIndex = idx2;
1848 idx++;
1851 /* Now compute offsets, and initialize the rest of the fields */
1852 for (idx = 0, offset = 0; idx < size-1; idx++) {
1853 elements[idx].Stream = 0;
1854 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1855 elements[idx].Offset = offset;
1856 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1859 *ppVertexElements = elements;
1860 return size;
1863 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1864 WINED3DVERTEXELEMENT* elements = NULL;
1865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1866 unsigned int size;
1867 DWORD hr;
1869 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1870 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1872 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1873 HeapFree(GetProcessHeap(), 0, elements);
1874 if (hr != S_OK) return hr;
1876 return WINED3D_OK;
1879 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1881 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1882 HRESULT hr = WINED3D_OK;
1883 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1884 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1886 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1888 if (vertex_declaration) {
1889 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1892 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1894 if (WINED3D_OK != hr) {
1895 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1896 IWineD3DVertexShader_Release(*ppVertexShader);
1897 return WINED3DERR_INVALIDCALL;
1899 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1901 return WINED3D_OK;
1904 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1906 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1907 HRESULT hr = WINED3D_OK;
1909 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1910 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1911 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1912 if (WINED3D_OK == hr) {
1913 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1914 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1915 } else {
1916 WARN("(%p) : Failed to create pixel shader\n", This);
1919 return hr;
1922 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1924 IWineD3DPaletteImpl *object;
1925 HRESULT hr;
1926 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1928 /* Create the new object */
1929 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1930 if(!object) {
1931 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1932 return E_OUTOFMEMORY;
1935 object->lpVtbl = &IWineD3DPalette_Vtbl;
1936 object->ref = 1;
1937 object->Flags = Flags;
1938 object->parent = Parent;
1939 object->wineD3DDevice = This;
1940 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1942 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1944 if(!object->hpal) {
1945 HeapFree( GetProcessHeap(), 0, object);
1946 return E_OUTOFMEMORY;
1949 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1950 if(FAILED(hr)) {
1951 IWineD3DPalette_Release((IWineD3DPalette *) object);
1952 return hr;
1955 *Palette = (IWineD3DPalette *) object;
1957 return WINED3D_OK;
1960 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1961 HBITMAP hbm;
1962 BITMAP bm;
1963 HRESULT hr;
1964 HDC dcb = NULL, dcs = NULL;
1965 WINEDDCOLORKEY colorkey;
1967 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1968 if(hbm)
1970 GetObjectA(hbm, sizeof(BITMAP), &bm);
1971 dcb = CreateCompatibleDC(NULL);
1972 if(!dcb) goto out;
1973 SelectObject(dcb, hbm);
1975 else
1977 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1978 * couldn't be loaded
1980 memset(&bm, 0, sizeof(bm));
1981 bm.bmWidth = 32;
1982 bm.bmHeight = 32;
1985 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1986 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1987 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1988 if(FAILED(hr)) {
1989 ERR("Wine logo requested, but failed to create surface\n");
1990 goto out;
1993 if(dcb) {
1994 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1995 if(FAILED(hr)) goto out;
1996 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1997 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1999 colorkey.dwColorSpaceLowValue = 0;
2000 colorkey.dwColorSpaceHighValue = 0;
2001 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2002 } else {
2003 /* Fill the surface with a white color to show that wined3d is there */
2004 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2007 out:
2008 if(dcb) {
2009 DeleteDC(dcb);
2011 if(hbm) {
2012 DeleteObject(hbm);
2014 return;
2017 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2018 unsigned int i;
2019 /* Under DirectX you can have texture stage operations even if no texture is
2020 bound, whereas opengl will only do texture operations when a valid texture is
2021 bound. We emulate this by creating dummy textures and binding them to each
2022 texture stage, but disable all stages by default. Hence if a stage is enabled
2023 then the default texture will kick in until replaced by a SetTexture call */
2024 ENTER_GL();
2026 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2027 /* The dummy texture does not have client storage backing */
2028 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2029 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2031 for (i = 0; i < GL_LIMITS(textures); i++) {
2032 GLubyte white = 255;
2034 /* Make appropriate texture active */
2035 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2036 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2037 checkGLcall("glActiveTextureARB");
2038 } else if (i > 0) {
2039 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2042 /* Generate an opengl texture name */
2043 glGenTextures(1, &This->dummyTextureName[i]);
2044 checkGLcall("glGenTextures");
2045 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2047 /* Generate a dummy 2d texture (not using 1d because they cause many
2048 * DRI drivers fall back to sw) */
2049 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2050 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2051 checkGLcall("glBindTexture");
2053 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2054 checkGLcall("glTexImage2D");
2056 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2057 /* Reenable because if supported it is enabled by default */
2058 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2059 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2062 LEAVE_GL();
2065 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2067 IWineD3DSwapChainImpl *swapchain = NULL;
2068 HRESULT hr;
2069 DWORD state;
2070 unsigned int i;
2072 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2073 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2074 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2076 /* TODO: Test if OpenGL is compiled in and loaded */
2078 TRACE("(%p) : Creating stateblock\n", This);
2079 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2080 hr = IWineD3DDevice_CreateStateBlock(iface,
2081 WINED3DSBT_INIT,
2082 (IWineD3DStateBlock **)&This->stateBlock,
2083 NULL);
2084 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2085 WARN("Failed to create stateblock\n");
2086 goto err_out;
2088 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2089 This->updateStateBlock = This->stateBlock;
2090 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2092 hr = allocate_shader_constants(This->updateStateBlock);
2093 if (WINED3D_OK != hr) {
2094 goto err_out;
2097 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2098 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2100 This->NumberOfPalettes = 1;
2101 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2102 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2103 ERR("Out of memory!\n");
2104 goto err_out;
2106 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2107 if(!This->palettes[0]) {
2108 ERR("Out of memory!\n");
2109 goto err_out;
2111 for (i = 0; i < 256; ++i) {
2112 This->palettes[0][i].peRed = 0xFF;
2113 This->palettes[0][i].peGreen = 0xFF;
2114 This->palettes[0][i].peBlue = 0xFF;
2115 This->palettes[0][i].peFlags = 0xFF;
2117 This->currentPalette = 0;
2119 /* Initialize the texture unit mapping to a 1:1 mapping */
2120 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2121 if (state < GL_LIMITS(fragment_samplers)) {
2122 This->texUnitMap[state] = state;
2123 This->rev_tex_unit_map[state] = state;
2124 } else {
2125 This->texUnitMap[state] = -1;
2126 This->rev_tex_unit_map[state] = -1;
2130 /* Setup the implicit swapchain */
2131 TRACE("Creating implicit swapchain\n");
2132 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2133 if (FAILED(hr) || !swapchain) {
2134 WARN("Failed to create implicit swapchain\n");
2135 goto err_out;
2138 This->NumberOfSwapChains = 1;
2139 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2140 if(!This->swapchains) {
2141 ERR("Out of memory!\n");
2142 goto err_out;
2144 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2146 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2147 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2148 This->render_targets[0] = swapchain->backBuffer[0];
2149 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2151 else {
2152 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2153 This->render_targets[0] = swapchain->frontBuffer;
2154 This->lastActiveRenderTarget = swapchain->frontBuffer;
2156 IWineD3DSurface_AddRef(This->render_targets[0]);
2157 This->activeContext = swapchain->context[0];
2158 This->lastThread = GetCurrentThreadId();
2160 /* Depth Stencil support */
2161 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2162 if (NULL != This->stencilBufferTarget) {
2163 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2166 hr = This->shader_backend->shader_alloc_private(iface);
2167 if(FAILED(hr)) {
2168 TRACE("Shader private data couldn't be allocated\n");
2169 goto err_out;
2171 hr = This->frag_pipe->alloc_private(iface);
2172 if(FAILED(hr)) {
2173 TRACE("Fragment pipeline private data couldn't be allocated\n");
2174 goto err_out;
2176 hr = This->blitter->alloc_private(iface);
2177 if(FAILED(hr)) {
2178 TRACE("Blitter private data couldn't be allocated\n");
2179 goto err_out;
2182 /* Set up some starting GL setup */
2184 /* Setup all the devices defaults */
2185 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2186 create_dummy_textures(This);
2188 ENTER_GL();
2190 { /* Set a default viewport */
2191 WINED3DVIEWPORT vp;
2192 vp.X = 0;
2193 vp.Y = 0;
2194 vp.Width = pPresentationParameters->BackBufferWidth;
2195 vp.Height = pPresentationParameters->BackBufferHeight;
2196 vp.MinZ = 0.0f;
2197 vp.MaxZ = 1.0f;
2198 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2201 /* Initialize the current view state */
2202 This->view_ident = 1;
2203 This->contexts[0]->last_was_rhw = 0;
2204 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2205 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2207 switch(wined3d_settings.offscreen_rendering_mode) {
2208 case ORM_FBO:
2209 case ORM_PBUFFER:
2210 This->offscreenBuffer = GL_BACK;
2211 break;
2213 case ORM_BACKBUFFER:
2215 if(This->activeContext->aux_buffers > 0) {
2216 TRACE("Using auxilliary buffer for offscreen rendering\n");
2217 This->offscreenBuffer = GL_AUX0;
2218 } else {
2219 TRACE("Using back buffer for offscreen rendering\n");
2220 This->offscreenBuffer = GL_BACK;
2225 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2226 LEAVE_GL();
2228 /* Clear the screen */
2229 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2230 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2231 0x00, 1.0, 0);
2233 This->d3d_initialized = TRUE;
2235 if(wined3d_settings.logo) {
2236 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2238 This->highest_dirty_ps_const = 0;
2239 This->highest_dirty_vs_const = 0;
2240 return WINED3D_OK;
2242 err_out:
2243 HeapFree(GetProcessHeap(), 0, This->render_targets);
2244 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2245 HeapFree(GetProcessHeap(), 0, This->swapchains);
2246 This->NumberOfSwapChains = 0;
2247 if(This->palettes) {
2248 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2249 HeapFree(GetProcessHeap(), 0, This->palettes);
2251 This->NumberOfPalettes = 0;
2252 if(swapchain) {
2253 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2255 if(This->stateBlock) {
2256 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2257 This->stateBlock = NULL;
2259 if (This->blit_priv) {
2260 This->blitter->free_private(iface);
2262 if (This->fragment_priv) {
2263 This->frag_pipe->free_private(iface);
2265 if (This->shader_priv) {
2266 This->shader_backend->shader_free_private(iface);
2268 return hr;
2271 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2273 IWineD3DSwapChainImpl *swapchain = NULL;
2274 HRESULT hr;
2276 /* Setup the implicit swapchain */
2277 TRACE("Creating implicit swapchain\n");
2278 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2279 if (FAILED(hr) || !swapchain) {
2280 WARN("Failed to create implicit swapchain\n");
2281 goto err_out;
2284 This->NumberOfSwapChains = 1;
2285 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2286 if(!This->swapchains) {
2287 ERR("Out of memory!\n");
2288 goto err_out;
2290 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2291 return WINED3D_OK;
2293 err_out:
2294 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2295 return hr;
2298 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2300 int sampler;
2301 UINT i;
2302 TRACE("(%p)\n", This);
2304 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2306 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2307 * it was created. Thus make sure a context is active for the glDelete* calls
2309 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2311 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2313 TRACE("Deleting high order patches\n");
2314 for(i = 0; i < PATCHMAP_SIZE; i++) {
2315 struct list *e1, *e2;
2316 struct WineD3DRectPatch *patch;
2317 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2318 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2319 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2323 /* Delete the palette conversion shader if it is around */
2324 if(This->paletteConversionShader) {
2325 ENTER_GL();
2326 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2327 LEAVE_GL();
2328 This->paletteConversionShader = 0;
2331 /* Delete the pbuffer context if there is any */
2332 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2334 /* Delete the mouse cursor texture */
2335 if(This->cursorTexture) {
2336 ENTER_GL();
2337 glDeleteTextures(1, &This->cursorTexture);
2338 LEAVE_GL();
2339 This->cursorTexture = 0;
2342 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2343 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2345 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2346 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2349 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2350 * private data, it might contain opengl pointers
2352 if(This->depth_blt_texture) {
2353 glDeleteTextures(1, &This->depth_blt_texture);
2354 This->depth_blt_texture = 0;
2356 if (This->depth_blt_rb) {
2357 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2358 This->depth_blt_rb = 0;
2359 This->depth_blt_rb_w = 0;
2360 This->depth_blt_rb_h = 0;
2363 /* Release the update stateblock */
2364 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2365 if(This->updateStateBlock != This->stateBlock)
2366 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2368 This->updateStateBlock = NULL;
2370 { /* because were not doing proper internal refcounts releasing the primary state block
2371 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2372 to set this->stateBlock = NULL; first */
2373 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2374 This->stateBlock = NULL;
2376 /* Release the stateblock */
2377 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2378 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2382 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2383 This->blitter->free_private(iface);
2384 This->frag_pipe->free_private(iface);
2385 This->shader_backend->shader_free_private(iface);
2387 /* Release the buffers (with sanity checks)*/
2388 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2389 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2390 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2391 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2393 This->stencilBufferTarget = NULL;
2395 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2396 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2397 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2399 TRACE("Setting rendertarget to NULL\n");
2400 This->render_targets[0] = NULL;
2402 if (This->auto_depth_stencil_buffer) {
2403 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2404 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2406 This->auto_depth_stencil_buffer = NULL;
2409 for(i=0; i < This->NumberOfSwapChains; i++) {
2410 TRACE("Releasing the implicit swapchain %d\n", i);
2411 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2412 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2416 HeapFree(GetProcessHeap(), 0, This->swapchains);
2417 This->swapchains = NULL;
2418 This->NumberOfSwapChains = 0;
2420 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2421 HeapFree(GetProcessHeap(), 0, This->palettes);
2422 This->palettes = NULL;
2423 This->NumberOfPalettes = 0;
2425 HeapFree(GetProcessHeap(), 0, This->render_targets);
2426 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2427 This->render_targets = NULL;
2428 This->draw_buffers = NULL;
2430 This->d3d_initialized = FALSE;
2431 return WINED3D_OK;
2434 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2436 unsigned int i;
2438 for(i=0; i < This->NumberOfSwapChains; i++) {
2439 TRACE("Releasing the implicit swapchain %d\n", i);
2440 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2441 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2445 HeapFree(GetProcessHeap(), 0, This->swapchains);
2446 This->swapchains = NULL;
2447 This->NumberOfSwapChains = 0;
2448 return WINED3D_OK;
2451 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2452 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2453 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2455 * There is no way to deactivate thread safety once it is enabled.
2457 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2460 /*For now just store the flag(needed in case of ddraw) */
2461 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2463 return;
2466 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2467 DEVMODEW devmode;
2468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2469 LONG ret;
2470 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2471 RECT clip_rc;
2473 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2475 /* Resize the screen even without a window:
2476 * The app could have unset it with SetCooperativeLevel, but not called
2477 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2478 * but we don't have any hwnd
2481 memset(&devmode, 0, sizeof(devmode));
2482 devmode.dmSize = sizeof(devmode);
2483 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2484 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2485 devmode.dmPelsWidth = pMode->Width;
2486 devmode.dmPelsHeight = pMode->Height;
2488 devmode.dmDisplayFrequency = pMode->RefreshRate;
2489 if (pMode->RefreshRate != 0) {
2490 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2493 /* Only change the mode if necessary */
2494 if( (This->ddraw_width == pMode->Width) &&
2495 (This->ddraw_height == pMode->Height) &&
2496 (This->ddraw_format == pMode->Format) &&
2497 (pMode->RefreshRate == 0) ) {
2498 return WINED3D_OK;
2501 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2502 if (ret != DISP_CHANGE_SUCCESSFUL) {
2503 if(devmode.dmDisplayFrequency != 0) {
2504 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2505 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2506 devmode.dmDisplayFrequency = 0;
2507 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2509 if(ret != DISP_CHANGE_SUCCESSFUL) {
2510 return WINED3DERR_NOTAVAILABLE;
2514 /* Store the new values */
2515 This->ddraw_width = pMode->Width;
2516 This->ddraw_height = pMode->Height;
2517 This->ddraw_format = pMode->Format;
2519 /* And finally clip mouse to our screen */
2520 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2521 ClipCursor(&clip_rc);
2523 return WINED3D_OK;
2526 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2528 *ppD3D= This->wineD3D;
2529 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2530 IWineD3D_AddRef(*ppD3D);
2531 return WINED3D_OK;
2534 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2537 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2538 (This->adapter->TextureRam/(1024*1024)),
2539 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2540 /* return simulated texture memory left */
2541 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2546 /*****
2547 * Get / Set FVF
2548 *****/
2549 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2552 /* Update the current state block */
2553 This->updateStateBlock->changed.fvf = TRUE;
2555 if(This->updateStateBlock->fvf == fvf) {
2556 TRACE("Application is setting the old fvf over, nothing to do\n");
2557 return WINED3D_OK;
2560 This->updateStateBlock->fvf = fvf;
2561 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2562 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2563 return WINED3D_OK;
2567 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2569 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2570 *pfvf = This->stateBlock->fvf;
2571 return WINED3D_OK;
2574 /*****
2575 * Get / Set Stream Source
2576 *****/
2577 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2579 IWineD3DVertexBuffer *oldSrc;
2581 if (StreamNumber >= MAX_STREAMS) {
2582 WARN("Stream out of range %d\n", StreamNumber);
2583 return WINED3DERR_INVALIDCALL;
2584 } else if(OffsetInBytes & 0x3) {
2585 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2586 return WINED3DERR_INVALIDCALL;
2589 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2590 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2592 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2594 if(oldSrc == pStreamData &&
2595 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2596 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2597 TRACE("Application is setting the old values over, nothing to do\n");
2598 return WINED3D_OK;
2601 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2602 if (pStreamData) {
2603 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2604 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2607 /* Handle recording of state blocks */
2608 if (This->isRecordingState) {
2609 TRACE("Recording... not performing anything\n");
2610 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2611 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2612 return WINED3D_OK;
2615 /* Need to do a getParent and pass the references up */
2616 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2617 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2618 so for now, just count internally */
2619 if (pStreamData != NULL) {
2620 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2621 InterlockedIncrement(&vbImpl->bindCount);
2622 IWineD3DVertexBuffer_AddRef(pStreamData);
2624 if (oldSrc != NULL) {
2625 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2626 IWineD3DVertexBuffer_Release(oldSrc);
2629 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2631 return WINED3D_OK;
2634 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2637 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2638 This->stateBlock->streamSource[StreamNumber],
2639 This->stateBlock->streamOffset[StreamNumber],
2640 This->stateBlock->streamStride[StreamNumber]);
2642 if (StreamNumber >= MAX_STREAMS) {
2643 WARN("Stream out of range %d\n", StreamNumber);
2644 return WINED3DERR_INVALIDCALL;
2646 *pStream = This->stateBlock->streamSource[StreamNumber];
2647 *pStride = This->stateBlock->streamStride[StreamNumber];
2648 if (pOffset) {
2649 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2652 if (*pStream != NULL) {
2653 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2655 return WINED3D_OK;
2658 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2660 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2661 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2663 /* Verify input at least in d3d9 this is invalid*/
2664 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2665 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2666 return WINED3DERR_INVALIDCALL;
2668 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2669 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2670 return WINED3DERR_INVALIDCALL;
2672 if( Divider == 0 ){
2673 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2674 return WINED3DERR_INVALIDCALL;
2677 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2678 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2680 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2681 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2683 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2684 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2685 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2688 return WINED3D_OK;
2691 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2694 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2695 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2697 TRACE("(%p) : returning %d\n", This, *Divider);
2699 return WINED3D_OK;
2702 /*****
2703 * Get / Set & Multiply Transform
2704 *****/
2705 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2708 /* Most of this routine, comments included copied from ddraw tree initially: */
2709 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2711 /* Handle recording of state blocks */
2712 if (This->isRecordingState) {
2713 TRACE("Recording... not performing anything\n");
2714 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2715 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2716 return WINED3D_OK;
2720 * If the new matrix is the same as the current one,
2721 * we cut off any further processing. this seems to be a reasonable
2722 * optimization because as was noticed, some apps (warcraft3 for example)
2723 * tend towards setting the same matrix repeatedly for some reason.
2725 * From here on we assume that the new matrix is different, wherever it matters.
2727 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2728 TRACE("The app is setting the same matrix over again\n");
2729 return WINED3D_OK;
2730 } else {
2731 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2735 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2736 where ViewMat = Camera space, WorldMat = world space.
2738 In OpenGL, camera and world space is combined into GL_MODELVIEW
2739 matrix. The Projection matrix stay projection matrix.
2742 /* Capture the times we can just ignore the change for now */
2743 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2744 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2745 /* Handled by the state manager */
2748 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2749 return WINED3D_OK;
2752 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2754 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2755 *pMatrix = This->stateBlock->transforms[State];
2756 return WINED3D_OK;
2759 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2760 WINED3DMATRIX *mat = NULL;
2761 WINED3DMATRIX temp;
2763 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2764 * below means it will be recorded in a state block change, but it
2765 * works regardless where it is recorded.
2766 * If this is found to be wrong, change to StateBlock.
2768 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2769 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2771 if (State < HIGHEST_TRANSFORMSTATE)
2773 mat = &This->updateStateBlock->transforms[State];
2774 } else {
2775 FIXME("Unhandled transform state!!\n");
2778 multiply_matrix(&temp, mat, pMatrix);
2780 /* Apply change via set transform - will reapply to eg. lights this way */
2781 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2784 /*****
2785 * Get / Set Light
2786 *****/
2787 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2788 you can reference any indexes you want as long as that number max are enabled at any
2789 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2790 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2791 but when recording, just build a chain pretty much of commands to be replayed. */
2793 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2794 float rho;
2795 PLIGHTINFOEL *object = NULL;
2796 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2797 struct list *e;
2799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2800 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2802 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2803 * the gl driver.
2805 if(!pLight) {
2806 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2807 return WINED3DERR_INVALIDCALL;
2810 switch(pLight->Type) {
2811 case WINED3DLIGHT_POINT:
2812 case WINED3DLIGHT_SPOT:
2813 case WINED3DLIGHT_PARALLELPOINT:
2814 case WINED3DLIGHT_GLSPOT:
2815 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2816 * most wanted
2818 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2819 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2820 return WINED3DERR_INVALIDCALL;
2822 break;
2824 case WINED3DLIGHT_DIRECTIONAL:
2825 /* Ignores attenuation */
2826 break;
2828 default:
2829 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2830 return WINED3DERR_INVALIDCALL;
2833 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2834 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2835 if(object->OriginalIndex == Index) break;
2836 object = NULL;
2839 if(!object) {
2840 TRACE("Adding new light\n");
2841 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2842 if(!object) {
2843 ERR("Out of memory error when allocating a light\n");
2844 return E_OUTOFMEMORY;
2846 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2847 object->glIndex = -1;
2848 object->OriginalIndex = Index;
2849 object->changed = TRUE;
2852 /* Initialize the object */
2853 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,
2854 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2855 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2856 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2857 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2858 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2859 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2861 /* Save away the information */
2862 object->OriginalParms = *pLight;
2864 switch (pLight->Type) {
2865 case WINED3DLIGHT_POINT:
2866 /* Position */
2867 object->lightPosn[0] = pLight->Position.x;
2868 object->lightPosn[1] = pLight->Position.y;
2869 object->lightPosn[2] = pLight->Position.z;
2870 object->lightPosn[3] = 1.0f;
2871 object->cutoff = 180.0f;
2872 /* FIXME: Range */
2873 break;
2875 case WINED3DLIGHT_DIRECTIONAL:
2876 /* Direction */
2877 object->lightPosn[0] = -pLight->Direction.x;
2878 object->lightPosn[1] = -pLight->Direction.y;
2879 object->lightPosn[2] = -pLight->Direction.z;
2880 object->lightPosn[3] = 0.0;
2881 object->exponent = 0.0f;
2882 object->cutoff = 180.0f;
2883 break;
2885 case WINED3DLIGHT_SPOT:
2886 /* Position */
2887 object->lightPosn[0] = pLight->Position.x;
2888 object->lightPosn[1] = pLight->Position.y;
2889 object->lightPosn[2] = pLight->Position.z;
2890 object->lightPosn[3] = 1.0;
2892 /* Direction */
2893 object->lightDirn[0] = pLight->Direction.x;
2894 object->lightDirn[1] = pLight->Direction.y;
2895 object->lightDirn[2] = pLight->Direction.z;
2896 object->lightDirn[3] = 1.0;
2899 * opengl-ish and d3d-ish spot lights use too different models for the
2900 * light "intensity" as a function of the angle towards the main light direction,
2901 * so we only can approximate very roughly.
2902 * however spot lights are rather rarely used in games (if ever used at all).
2903 * furthermore if still used, probably nobody pays attention to such details.
2905 if (pLight->Falloff == 0) {
2906 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2907 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2908 * will always be 1.0 for both of them, and we don't have to care for the
2909 * rest of the rather complex calculation
2911 object->exponent = 0;
2912 } else {
2913 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2914 if (rho < 0.0001) rho = 0.0001f;
2915 object->exponent = -0.3/log(cos(rho/2));
2917 if (object->exponent > 128.0) {
2918 object->exponent = 128.0;
2920 object->cutoff = pLight->Phi*90/M_PI;
2922 /* FIXME: Range */
2923 break;
2925 default:
2926 FIXME("Unrecognized light type %d\n", pLight->Type);
2929 /* Update the live definitions if the light is currently assigned a glIndex */
2930 if (object->glIndex != -1 && !This->isRecordingState) {
2931 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2933 return WINED3D_OK;
2936 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2937 PLIGHTINFOEL *lightInfo = NULL;
2938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2939 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2940 struct list *e;
2941 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2943 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2944 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2945 if(lightInfo->OriginalIndex == Index) break;
2946 lightInfo = NULL;
2949 if (lightInfo == NULL) {
2950 TRACE("Light information requested but light not defined\n");
2951 return WINED3DERR_INVALIDCALL;
2954 *pLight = lightInfo->OriginalParms;
2955 return WINED3D_OK;
2958 /*****
2959 * Get / Set Light Enable
2960 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2961 *****/
2962 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2963 PLIGHTINFOEL *lightInfo = NULL;
2964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2965 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2966 struct list *e;
2967 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2969 /* Tests show true = 128...not clear why */
2970 Enable = Enable? 128: 0;
2972 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2973 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2974 if(lightInfo->OriginalIndex == Index) break;
2975 lightInfo = NULL;
2977 TRACE("Found light: %p\n", lightInfo);
2979 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2980 if (lightInfo == NULL) {
2982 TRACE("Light enabled requested but light not defined, so defining one!\n");
2983 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2985 /* Search for it again! Should be fairly quick as near head of list */
2986 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2987 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2988 if(lightInfo->OriginalIndex == Index) break;
2989 lightInfo = NULL;
2991 if (lightInfo == NULL) {
2992 FIXME("Adding default lights has failed dismally\n");
2993 return WINED3DERR_INVALIDCALL;
2997 lightInfo->enabledChanged = TRUE;
2998 if(!Enable) {
2999 if(lightInfo->glIndex != -1) {
3000 if(!This->isRecordingState) {
3001 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3004 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3005 lightInfo->glIndex = -1;
3006 } else {
3007 TRACE("Light already disabled, nothing to do\n");
3009 lightInfo->enabled = FALSE;
3010 } else {
3011 lightInfo->enabled = TRUE;
3012 if (lightInfo->glIndex != -1) {
3013 /* nop */
3014 TRACE("Nothing to do as light was enabled\n");
3015 } else {
3016 int i;
3017 /* Find a free gl light */
3018 for(i = 0; i < This->maxConcurrentLights; i++) {
3019 if(This->updateStateBlock->activeLights[i] == NULL) {
3020 This->updateStateBlock->activeLights[i] = lightInfo;
3021 lightInfo->glIndex = i;
3022 break;
3025 if(lightInfo->glIndex == -1) {
3026 /* Our tests show that Windows returns D3D_OK in this situation, even with
3027 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3028 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3029 * as well for those lights.
3031 * TODO: Test how this affects rendering
3033 FIXME("Too many concurrently active lights\n");
3034 return WINED3D_OK;
3037 /* i == lightInfo->glIndex */
3038 if(!This->isRecordingState) {
3039 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3044 return WINED3D_OK;
3047 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3049 PLIGHTINFOEL *lightInfo = NULL;
3050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3051 struct list *e;
3052 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3053 TRACE("(%p) : for idx(%d)\n", This, Index);
3055 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3056 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3057 if(lightInfo->OriginalIndex == Index) break;
3058 lightInfo = NULL;
3061 if (lightInfo == NULL) {
3062 TRACE("Light enabled state requested but light not defined\n");
3063 return WINED3DERR_INVALIDCALL;
3065 /* true is 128 according to SetLightEnable */
3066 *pEnable = lightInfo->enabled ? 128 : 0;
3067 return WINED3D_OK;
3070 /*****
3071 * Get / Set Clip Planes
3072 *****/
3073 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3075 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3077 /* Validate Index */
3078 if (Index >= GL_LIMITS(clipplanes)) {
3079 TRACE("Application has requested clipplane this device doesn't support\n");
3080 return WINED3DERR_INVALIDCALL;
3083 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3085 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3086 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3087 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3088 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3089 TRACE("Application is setting old values over, nothing to do\n");
3090 return WINED3D_OK;
3093 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3094 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3095 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3096 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3098 /* Handle recording of state blocks */
3099 if (This->isRecordingState) {
3100 TRACE("Recording... not performing anything\n");
3101 return WINED3D_OK;
3104 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3106 return WINED3D_OK;
3109 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3111 TRACE("(%p) : for idx %d\n", This, Index);
3113 /* Validate Index */
3114 if (Index >= GL_LIMITS(clipplanes)) {
3115 TRACE("Application has requested clipplane this device doesn't support\n");
3116 return WINED3DERR_INVALIDCALL;
3119 pPlane[0] = This->stateBlock->clipplane[Index][0];
3120 pPlane[1] = This->stateBlock->clipplane[Index][1];
3121 pPlane[2] = This->stateBlock->clipplane[Index][2];
3122 pPlane[3] = This->stateBlock->clipplane[Index][3];
3123 return WINED3D_OK;
3126 /*****
3127 * Get / Set Clip Plane Status
3128 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3129 *****/
3130 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3132 FIXME("(%p) : stub\n", This);
3133 if (NULL == pClipStatus) {
3134 return WINED3DERR_INVALIDCALL;
3136 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3137 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3138 return WINED3D_OK;
3141 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3143 FIXME("(%p) : stub\n", This);
3144 if (NULL == pClipStatus) {
3145 return WINED3DERR_INVALIDCALL;
3147 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3148 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3149 return WINED3D_OK;
3152 /*****
3153 * Get / Set Material
3154 *****/
3155 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3158 This->updateStateBlock->changed.material = TRUE;
3159 This->updateStateBlock->material = *pMaterial;
3161 /* Handle recording of state blocks */
3162 if (This->isRecordingState) {
3163 TRACE("Recording... not performing anything\n");
3164 return WINED3D_OK;
3167 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3168 return WINED3D_OK;
3171 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3173 *pMaterial = This->updateStateBlock->material;
3174 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3175 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3176 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3177 pMaterial->Ambient.b, pMaterial->Ambient.a);
3178 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3179 pMaterial->Specular.b, pMaterial->Specular.a);
3180 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3181 pMaterial->Emissive.b, pMaterial->Emissive.a);
3182 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3184 return WINED3D_OK;
3187 /*****
3188 * Get / Set Indices
3189 *****/
3190 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3192 IWineD3DIndexBuffer *oldIdxs;
3194 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3195 oldIdxs = This->updateStateBlock->pIndexData;
3197 This->updateStateBlock->changed.indices = TRUE;
3198 This->updateStateBlock->pIndexData = pIndexData;
3200 /* Handle recording of state blocks */
3201 if (This->isRecordingState) {
3202 TRACE("Recording... not performing anything\n");
3203 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3204 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3205 return WINED3D_OK;
3208 if(oldIdxs != pIndexData) {
3209 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3210 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3211 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3213 return WINED3D_OK;
3216 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3219 *ppIndexData = This->stateBlock->pIndexData;
3221 /* up ref count on ppindexdata */
3222 if (*ppIndexData) {
3223 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3224 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3225 }else{
3226 TRACE("(%p) No index data set\n", This);
3228 TRACE("Returning %p\n", *ppIndexData);
3230 return WINED3D_OK;
3233 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3234 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3236 TRACE("(%p)->(%d)\n", This, BaseIndex);
3238 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3239 TRACE("Application is setting the old value over, nothing to do\n");
3240 return WINED3D_OK;
3243 This->updateStateBlock->baseVertexIndex = BaseIndex;
3245 if (This->isRecordingState) {
3246 TRACE("Recording... not performing anything\n");
3247 return WINED3D_OK;
3249 /* The base vertex index affects the stream sources */
3250 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3251 return WINED3D_OK;
3254 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3256 TRACE("(%p) : base_index %p\n", This, base_index);
3258 *base_index = This->stateBlock->baseVertexIndex;
3260 TRACE("Returning %u\n", *base_index);
3262 return WINED3D_OK;
3265 /*****
3266 * Get / Set Viewports
3267 *****/
3268 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3271 TRACE("(%p)\n", This);
3272 This->updateStateBlock->changed.viewport = TRUE;
3273 This->updateStateBlock->viewport = *pViewport;
3275 /* Handle recording of state blocks */
3276 if (This->isRecordingState) {
3277 TRACE("Recording... not performing anything\n");
3278 return WINED3D_OK;
3281 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3282 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3284 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3285 return WINED3D_OK;
3289 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3291 TRACE("(%p)\n", This);
3292 *pViewport = This->stateBlock->viewport;
3293 return WINED3D_OK;
3296 /*****
3297 * Get / Set Render States
3298 * TODO: Verify against dx9 definitions
3299 *****/
3300 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3303 DWORD oldValue = This->stateBlock->renderState[State];
3305 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3307 This->updateStateBlock->changed.renderState[State] = TRUE;
3308 This->updateStateBlock->renderState[State] = Value;
3310 /* Handle recording of state blocks */
3311 if (This->isRecordingState) {
3312 TRACE("Recording... not performing anything\n");
3313 return WINED3D_OK;
3316 /* Compared here and not before the assignment to allow proper stateblock recording */
3317 if(Value == oldValue) {
3318 TRACE("Application is setting the old value over, nothing to do\n");
3319 } else {
3320 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3323 return WINED3D_OK;
3326 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3327 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3328 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3329 *pValue = This->stateBlock->renderState[State];
3330 return WINED3D_OK;
3333 /*****
3334 * Get / Set Sampler States
3335 * TODO: Verify against dx9 definitions
3336 *****/
3338 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3340 DWORD oldValue;
3342 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3343 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3345 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3346 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3349 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3350 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3351 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3354 * SetSampler is designed to allow for more than the standard up to 8 textures
3355 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3356 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3358 * http://developer.nvidia.com/object/General_FAQ.html#t6
3360 * There are two new settings for GForce
3361 * the sampler one:
3362 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3363 * and the texture one:
3364 * GL_MAX_TEXTURE_COORDS_ARB.
3365 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3366 ******************/
3368 oldValue = This->stateBlock->samplerState[Sampler][Type];
3369 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3370 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3372 /* Handle recording of state blocks */
3373 if (This->isRecordingState) {
3374 TRACE("Recording... not performing anything\n");
3375 return WINED3D_OK;
3378 if(oldValue == Value) {
3379 TRACE("Application is setting the old value over, nothing to do\n");
3380 return WINED3D_OK;
3383 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3385 return WINED3D_OK;
3388 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3391 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3392 This, Sampler, debug_d3dsamplerstate(Type), Type);
3394 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3395 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3398 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3399 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3400 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3402 *Value = This->stateBlock->samplerState[Sampler][Type];
3403 TRACE("(%p) : Returning %#x\n", This, *Value);
3405 return WINED3D_OK;
3408 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3409 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3411 This->updateStateBlock->changed.scissorRect = TRUE;
3412 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3413 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3414 return WINED3D_OK;
3416 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3418 if(This->isRecordingState) {
3419 TRACE("Recording... not performing anything\n");
3420 return WINED3D_OK;
3423 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3425 return WINED3D_OK;
3428 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3431 *pRect = This->updateStateBlock->scissorRect;
3432 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3433 return WINED3D_OK;
3436 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3438 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3440 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3442 This->updateStateBlock->vertexDecl = pDecl;
3443 This->updateStateBlock->changed.vertexDecl = TRUE;
3445 if (This->isRecordingState) {
3446 TRACE("Recording... not performing anything\n");
3447 return WINED3D_OK;
3448 } else if(pDecl == oldDecl) {
3449 /* Checked after the assignment to allow proper stateblock recording */
3450 TRACE("Application is setting the old declaration over, nothing to do\n");
3451 return WINED3D_OK;
3454 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3455 return WINED3D_OK;
3458 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3461 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3463 *ppDecl = This->stateBlock->vertexDecl;
3464 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3465 return WINED3D_OK;
3468 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3470 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3472 This->updateStateBlock->vertexShader = pShader;
3473 This->updateStateBlock->changed.vertexShader = TRUE;
3475 if (This->isRecordingState) {
3476 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3477 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3478 TRACE("Recording... not performing anything\n");
3479 return WINED3D_OK;
3480 } else if(oldShader == pShader) {
3481 /* Checked here to allow proper stateblock recording */
3482 TRACE("App is setting the old shader over, nothing to do\n");
3483 return WINED3D_OK;
3486 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3487 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3488 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3490 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3492 return WINED3D_OK;
3495 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3498 if (NULL == ppShader) {
3499 return WINED3DERR_INVALIDCALL;
3501 *ppShader = This->stateBlock->vertexShader;
3502 if( NULL != *ppShader)
3503 IWineD3DVertexShader_AddRef(*ppShader);
3505 TRACE("(%p) : returning %p\n", This, *ppShader);
3506 return WINED3D_OK;
3509 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3510 IWineD3DDevice *iface,
3511 UINT start,
3512 CONST BOOL *srcData,
3513 UINT count) {
3515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3516 int i, cnt = min(count, MAX_CONST_B - start);
3518 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3519 iface, srcData, start, count);
3521 if (srcData == NULL || cnt < 0)
3522 return WINED3DERR_INVALIDCALL;
3524 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3525 for (i = 0; i < cnt; i++)
3526 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3528 for (i = start; i < cnt + start; ++i) {
3529 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3532 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3534 return WINED3D_OK;
3537 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3538 IWineD3DDevice *iface,
3539 UINT start,
3540 BOOL *dstData,
3541 UINT count) {
3543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3544 int cnt = min(count, MAX_CONST_B - start);
3546 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3547 iface, dstData, start, count);
3549 if (dstData == NULL || cnt < 0)
3550 return WINED3DERR_INVALIDCALL;
3552 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3553 return WINED3D_OK;
3556 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3557 IWineD3DDevice *iface,
3558 UINT start,
3559 CONST int *srcData,
3560 UINT count) {
3562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3563 int i, cnt = min(count, MAX_CONST_I - start);
3565 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3566 iface, srcData, start, count);
3568 if (srcData == NULL || cnt < 0)
3569 return WINED3DERR_INVALIDCALL;
3571 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3572 for (i = 0; i < cnt; i++)
3573 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3574 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3576 for (i = start; i < cnt + start; ++i) {
3577 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3580 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3582 return WINED3D_OK;
3585 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3586 IWineD3DDevice *iface,
3587 UINT start,
3588 int *dstData,
3589 UINT count) {
3591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3592 int cnt = min(count, MAX_CONST_I - start);
3594 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3595 iface, dstData, start, count);
3597 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3598 return WINED3DERR_INVALIDCALL;
3600 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3601 return WINED3D_OK;
3604 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3605 IWineD3DDevice *iface,
3606 UINT start,
3607 CONST float *srcData,
3608 UINT count) {
3610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3611 int i;
3613 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3614 iface, srcData, start, count);
3616 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3617 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3618 return WINED3DERR_INVALIDCALL;
3620 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3621 if(TRACE_ON(d3d)) {
3622 for (i = 0; i < count; i++)
3623 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3624 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3627 for (i = start; i < count + start; ++i) {
3628 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3629 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3630 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3631 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3632 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3634 ptr->idx[ptr->count++] = i;
3635 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3639 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3641 return WINED3D_OK;
3644 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3645 IWineD3DDevice *iface,
3646 UINT start,
3647 CONST float *srcData,
3648 UINT count) {
3650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3651 int i;
3653 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3654 iface, srcData, start, count);
3656 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3657 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3658 return WINED3DERR_INVALIDCALL;
3660 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3661 if(TRACE_ON(d3d)) {
3662 for (i = 0; i < count; i++)
3663 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3664 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3667 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3668 * context. On a context switch the old context will be fully dirtified
3670 memset(This->activeContext->vshader_const_dirty + start, 1,
3671 sizeof(*This->activeContext->vshader_const_dirty) * count);
3672 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3674 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3676 return WINED3D_OK;
3679 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3680 IWineD3DDevice *iface,
3681 UINT start,
3682 float *dstData,
3683 UINT count) {
3685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3686 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3688 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3689 iface, dstData, start, count);
3691 if (dstData == NULL || cnt < 0)
3692 return WINED3DERR_INVALIDCALL;
3694 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3695 return WINED3D_OK;
3698 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3699 DWORD i;
3700 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3701 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3705 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3706 int i = This->rev_tex_unit_map[unit];
3707 int j = This->texUnitMap[stage];
3709 This->texUnitMap[stage] = unit;
3710 if (i != -1 && i != stage) {
3711 This->texUnitMap[i] = -1;
3714 This->rev_tex_unit_map[unit] = stage;
3715 if (j != -1 && j != unit) {
3716 This->rev_tex_unit_map[j] = -1;
3720 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3721 int i;
3723 for (i = 0; i < MAX_TEXTURES; ++i) {
3724 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3725 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3726 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3727 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3728 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3729 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3730 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3731 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3733 if (color_op == WINED3DTOP_DISABLE) {
3734 /* Not used, and disable higher stages */
3735 while (i < MAX_TEXTURES) {
3736 This->fixed_function_usage_map[i] = FALSE;
3737 ++i;
3739 break;
3742 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3743 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3744 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3745 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3746 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3747 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3748 This->fixed_function_usage_map[i] = TRUE;
3749 } else {
3750 This->fixed_function_usage_map[i] = FALSE;
3753 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3754 This->fixed_function_usage_map[i+1] = TRUE;
3759 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3760 int i, tex;
3762 device_update_fixed_function_usage_map(This);
3764 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3765 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3766 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3767 if (!This->fixed_function_usage_map[i]) continue;
3769 if (This->texUnitMap[i] != i) {
3770 device_map_stage(This, i, i);
3771 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3772 markTextureStagesDirty(This, i);
3775 return;
3778 /* Now work out the mapping */
3779 tex = 0;
3780 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3781 if (!This->fixed_function_usage_map[i]) continue;
3783 if (This->texUnitMap[i] != tex) {
3784 device_map_stage(This, i, tex);
3785 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3786 markTextureStagesDirty(This, i);
3789 ++tex;
3793 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3794 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3795 int i;
3797 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3798 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3799 device_map_stage(This, i, i);
3800 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3801 if (i < MAX_TEXTURES) {
3802 markTextureStagesDirty(This, i);
3808 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3809 int current_mapping = This->rev_tex_unit_map[unit];
3811 if (current_mapping == -1) {
3812 /* Not currently used */
3813 return TRUE;
3816 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3817 /* Used by a fragment sampler */
3819 if (!pshader_sampler_tokens) {
3820 /* No pixel shader, check fixed function */
3821 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3824 /* Pixel shader, check the shader's sampler map */
3825 return !pshader_sampler_tokens[current_mapping];
3828 /* Used by a vertex sampler */
3829 return !vshader_sampler_tokens[current_mapping];
3832 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3833 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3834 DWORD *pshader_sampler_tokens = NULL;
3835 int start = GL_LIMITS(combined_samplers) - 1;
3836 int i;
3838 if (ps) {
3839 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3841 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3842 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3843 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3846 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3847 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3848 if (vshader_sampler_tokens[i]) {
3849 if (This->texUnitMap[vsampler_idx] != -1) {
3850 /* Already mapped somewhere */
3851 continue;
3854 while (start >= 0) {
3855 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3856 device_map_stage(This, vsampler_idx, start);
3857 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3859 --start;
3860 break;
3863 --start;
3869 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3870 BOOL vs = use_vs(This);
3871 BOOL ps = use_ps(This);
3873 * Rules are:
3874 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3875 * that would be really messy and require shader recompilation
3876 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3877 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3879 if (ps) {
3880 device_map_psamplers(This);
3881 } else {
3882 device_map_fixed_function_samplers(This);
3885 if (vs) {
3886 device_map_vsamplers(This, ps);
3890 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3892 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3893 This->updateStateBlock->pixelShader = pShader;
3894 This->updateStateBlock->changed.pixelShader = TRUE;
3896 /* Handle recording of state blocks */
3897 if (This->isRecordingState) {
3898 TRACE("Recording... not performing anything\n");
3901 if (This->isRecordingState) {
3902 TRACE("Recording... not performing anything\n");
3903 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3904 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3905 return WINED3D_OK;
3908 if(pShader == oldShader) {
3909 TRACE("App is setting the old pixel shader over, nothing to do\n");
3910 return WINED3D_OK;
3913 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3914 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3916 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3917 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3919 return WINED3D_OK;
3922 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3925 if (NULL == ppShader) {
3926 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3927 return WINED3DERR_INVALIDCALL;
3930 *ppShader = This->stateBlock->pixelShader;
3931 if (NULL != *ppShader) {
3932 IWineD3DPixelShader_AddRef(*ppShader);
3934 TRACE("(%p) : returning %p\n", This, *ppShader);
3935 return WINED3D_OK;
3938 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3939 IWineD3DDevice *iface,
3940 UINT start,
3941 CONST BOOL *srcData,
3942 UINT count) {
3944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3945 int i, cnt = min(count, MAX_CONST_B - start);
3947 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3948 iface, srcData, start, count);
3950 if (srcData == NULL || cnt < 0)
3951 return WINED3DERR_INVALIDCALL;
3953 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3954 for (i = 0; i < cnt; i++)
3955 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3957 for (i = start; i < cnt + start; ++i) {
3958 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3961 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3963 return WINED3D_OK;
3966 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3967 IWineD3DDevice *iface,
3968 UINT start,
3969 BOOL *dstData,
3970 UINT count) {
3972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3973 int cnt = min(count, MAX_CONST_B - start);
3975 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3976 iface, dstData, start, count);
3978 if (dstData == NULL || cnt < 0)
3979 return WINED3DERR_INVALIDCALL;
3981 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3982 return WINED3D_OK;
3985 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3986 IWineD3DDevice *iface,
3987 UINT start,
3988 CONST int *srcData,
3989 UINT count) {
3991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3992 int i, cnt = min(count, MAX_CONST_I - start);
3994 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3995 iface, srcData, start, count);
3997 if (srcData == NULL || cnt < 0)
3998 return WINED3DERR_INVALIDCALL;
4000 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4001 for (i = 0; i < cnt; i++)
4002 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4003 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4005 for (i = start; i < cnt + start; ++i) {
4006 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4009 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4011 return WINED3D_OK;
4014 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4015 IWineD3DDevice *iface,
4016 UINT start,
4017 int *dstData,
4018 UINT count) {
4020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4021 int cnt = min(count, MAX_CONST_I - start);
4023 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4024 iface, dstData, start, count);
4026 if (dstData == NULL || cnt < 0)
4027 return WINED3DERR_INVALIDCALL;
4029 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4030 return WINED3D_OK;
4033 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4034 IWineD3DDevice *iface,
4035 UINT start,
4036 CONST float *srcData,
4037 UINT count) {
4039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4040 int i;
4042 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4043 iface, srcData, start, count);
4045 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4046 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4047 return WINED3DERR_INVALIDCALL;
4049 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4050 if(TRACE_ON(d3d)) {
4051 for (i = 0; i < count; i++)
4052 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4053 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4056 for (i = start; i < count + start; ++i) {
4057 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
4058 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
4059 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
4060 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
4061 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
4063 ptr->idx[ptr->count++] = i;
4064 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4068 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4070 return WINED3D_OK;
4073 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4074 IWineD3DDevice *iface,
4075 UINT start,
4076 CONST float *srcData,
4077 UINT count) {
4079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4080 int i;
4082 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4083 iface, srcData, start, count);
4085 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4086 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4087 return WINED3DERR_INVALIDCALL;
4089 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4090 if(TRACE_ON(d3d)) {
4091 for (i = 0; i < count; i++)
4092 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4093 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4096 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4097 * context. On a context switch the old context will be fully dirtified
4099 memset(This->activeContext->pshader_const_dirty + start, 1,
4100 sizeof(*This->activeContext->pshader_const_dirty) * count);
4101 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4103 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4105 return WINED3D_OK;
4108 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4109 IWineD3DDevice *iface,
4110 UINT start,
4111 float *dstData,
4112 UINT count) {
4114 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4115 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4117 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4118 iface, dstData, start, count);
4120 if (dstData == NULL || cnt < 0)
4121 return WINED3DERR_INVALIDCALL;
4123 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4124 return WINED3D_OK;
4127 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4128 static HRESULT
4129 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4130 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4131 unsigned int i;
4132 DWORD DestFVF = dest->fvf;
4133 WINED3DVIEWPORT vp;
4134 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4135 BOOL doClip;
4136 int numTextures;
4138 if (lpStrideData->u.s.normal.lpData) {
4139 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4142 if (lpStrideData->u.s.position.lpData == NULL) {
4143 ERR("Source has no position mask\n");
4144 return WINED3DERR_INVALIDCALL;
4147 /* We might access VBOs from this code, so hold the lock */
4148 ENTER_GL();
4150 if (dest->resource.allocatedMemory == NULL) {
4151 /* This may happen if we do direct locking into a vbo. Unlikely,
4152 * but theoretically possible(ddraw processvertices test)
4154 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4155 if(!dest->resource.allocatedMemory) {
4156 LEAVE_GL();
4157 ERR("Out of memory\n");
4158 return E_OUTOFMEMORY;
4160 if(dest->vbo) {
4161 void *src;
4162 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4163 checkGLcall("glBindBufferARB");
4164 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4165 if(src) {
4166 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4168 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4169 checkGLcall("glUnmapBufferARB");
4173 /* Get a pointer into the destination vbo(create one if none exists) and
4174 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4176 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4177 dest->Flags |= VBFLAG_CREATEVBO;
4178 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4181 if(dest->vbo) {
4182 unsigned char extrabytes = 0;
4183 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4184 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4185 * this may write 4 extra bytes beyond the area that should be written
4187 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4188 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4189 if(!dest_conv_addr) {
4190 ERR("Out of memory\n");
4191 /* Continue without storing converted vertices */
4193 dest_conv = dest_conv_addr;
4196 /* Should I clip?
4197 * a) WINED3DRS_CLIPPING is enabled
4198 * b) WINED3DVOP_CLIP is passed
4200 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4201 static BOOL warned = FALSE;
4203 * The clipping code is not quite correct. Some things need
4204 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4205 * so disable clipping for now.
4206 * (The graphics in Half-Life are broken, and my processvertices
4207 * test crashes with IDirect3DDevice3)
4208 doClip = TRUE;
4210 doClip = FALSE;
4211 if(!warned) {
4212 warned = TRUE;
4213 FIXME("Clipping is broken and disabled for now\n");
4215 } else doClip = FALSE;
4216 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4218 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4219 WINED3DTS_VIEW,
4220 &view_mat);
4221 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4222 WINED3DTS_PROJECTION,
4223 &proj_mat);
4224 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4225 WINED3DTS_WORLDMATRIX(0),
4226 &world_mat);
4228 TRACE("View mat:\n");
4229 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);
4230 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);
4231 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);
4232 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);
4234 TRACE("Proj mat:\n");
4235 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);
4236 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);
4237 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);
4238 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);
4240 TRACE("World mat:\n");
4241 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);
4242 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);
4243 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);
4244 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);
4246 /* Get the viewport */
4247 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4248 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4249 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4251 multiply_matrix(&mat,&view_mat,&world_mat);
4252 multiply_matrix(&mat,&proj_mat,&mat);
4254 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4256 for (i = 0; i < dwCount; i+= 1) {
4257 unsigned int tex_index;
4259 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4260 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4261 /* The position first */
4262 float *p =
4263 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4264 float x, y, z, rhw;
4265 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4267 /* Multiplication with world, view and projection matrix */
4268 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);
4269 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);
4270 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);
4271 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);
4273 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4275 /* WARNING: The following things are taken from d3d7 and were not yet checked
4276 * against d3d8 or d3d9!
4279 /* Clipping conditions: From msdn
4281 * A vertex is clipped if it does not match the following requirements
4282 * -rhw < x <= rhw
4283 * -rhw < y <= rhw
4284 * 0 < z <= rhw
4285 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4287 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4288 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4292 if( !doClip ||
4293 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4294 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4295 ( rhw > eps ) ) ) {
4297 /* "Normal" viewport transformation (not clipped)
4298 * 1) The values are divided by rhw
4299 * 2) The y axis is negative, so multiply it with -1
4300 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4301 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4302 * 4) Multiply x with Width/2 and add Width/2
4303 * 5) The same for the height
4304 * 6) Add the viewpoint X and Y to the 2D coordinates and
4305 * The minimum Z value to z
4306 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4308 * Well, basically it's simply a linear transformation into viewport
4309 * coordinates
4312 x /= rhw;
4313 y /= rhw;
4314 z /= rhw;
4316 y *= -1;
4318 x *= vp.Width / 2;
4319 y *= vp.Height / 2;
4320 z *= vp.MaxZ - vp.MinZ;
4322 x += vp.Width / 2 + vp.X;
4323 y += vp.Height / 2 + vp.Y;
4324 z += vp.MinZ;
4326 rhw = 1 / rhw;
4327 } else {
4328 /* That vertex got clipped
4329 * Contrary to OpenGL it is not dropped completely, it just
4330 * undergoes a different calculation.
4332 TRACE("Vertex got clipped\n");
4333 x += rhw;
4334 y += rhw;
4336 x /= 2;
4337 y /= 2;
4339 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4340 * outside of the main vertex buffer memory. That needs some more
4341 * investigation...
4345 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4348 ( (float *) dest_ptr)[0] = x;
4349 ( (float *) dest_ptr)[1] = y;
4350 ( (float *) dest_ptr)[2] = z;
4351 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4353 dest_ptr += 3 * sizeof(float);
4355 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4356 dest_ptr += sizeof(float);
4359 if(dest_conv) {
4360 float w = 1 / rhw;
4361 ( (float *) dest_conv)[0] = x * w;
4362 ( (float *) dest_conv)[1] = y * w;
4363 ( (float *) dest_conv)[2] = z * w;
4364 ( (float *) dest_conv)[3] = w;
4366 dest_conv += 3 * sizeof(float);
4368 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4369 dest_conv += sizeof(float);
4373 if (DestFVF & WINED3DFVF_PSIZE) {
4374 dest_ptr += sizeof(DWORD);
4375 if(dest_conv) dest_conv += sizeof(DWORD);
4377 if (DestFVF & WINED3DFVF_NORMAL) {
4378 float *normal =
4379 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4380 /* AFAIK this should go into the lighting information */
4381 FIXME("Didn't expect the destination to have a normal\n");
4382 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4383 if(dest_conv) {
4384 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4388 if (DestFVF & WINED3DFVF_DIFFUSE) {
4389 DWORD *color_d =
4390 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4391 if(!color_d) {
4392 static BOOL warned = FALSE;
4394 if(!warned) {
4395 ERR("No diffuse color in source, but destination has one\n");
4396 warned = TRUE;
4399 *( (DWORD *) dest_ptr) = 0xffffffff;
4400 dest_ptr += sizeof(DWORD);
4402 if(dest_conv) {
4403 *( (DWORD *) dest_conv) = 0xffffffff;
4404 dest_conv += sizeof(DWORD);
4407 else {
4408 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4409 if(dest_conv) {
4410 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4411 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4412 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4413 dest_conv += sizeof(DWORD);
4418 if (DestFVF & WINED3DFVF_SPECULAR) {
4419 /* What's the color value in the feedback buffer? */
4420 DWORD *color_s =
4421 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4422 if(!color_s) {
4423 static BOOL warned = FALSE;
4425 if(!warned) {
4426 ERR("No specular color in source, but destination has one\n");
4427 warned = TRUE;
4430 *( (DWORD *) dest_ptr) = 0xFF000000;
4431 dest_ptr += sizeof(DWORD);
4433 if(dest_conv) {
4434 *( (DWORD *) dest_conv) = 0xFF000000;
4435 dest_conv += sizeof(DWORD);
4438 else {
4439 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4440 if(dest_conv) {
4441 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4442 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4443 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4444 dest_conv += sizeof(DWORD);
4449 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4450 float *tex_coord =
4451 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4452 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4453 if(!tex_coord) {
4454 ERR("No source texture, but destination requests one\n");
4455 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4456 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4458 else {
4459 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4460 if(dest_conv) {
4461 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4467 if(dest_conv) {
4468 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4469 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4470 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4471 dwCount * get_flexible_vertex_size(DestFVF),
4472 dest_conv_addr));
4473 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4474 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4477 LEAVE_GL();
4479 return WINED3D_OK;
4481 #undef copy_and_next
4483 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4485 WineDirect3DVertexStridedData strided;
4486 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4487 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4489 if(pVertexDecl) {
4490 ERR("Output vertex declaration not implemented yet\n");
4493 /* Need any context to write to the vbo. */
4494 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4496 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4497 * control the streamIsUP flag, thus restore it afterwards.
4499 This->stateBlock->streamIsUP = FALSE;
4500 memset(&strided, 0, sizeof(strided));
4501 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4502 This->stateBlock->streamIsUP = streamWasUP;
4504 if(vbo || SrcStartIndex) {
4505 unsigned int i;
4506 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4507 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4509 * Also get the start index in, but only loop over all elements if there's something to add at all.
4511 #define FIXSRC(type) \
4512 if(strided.u.s.type.VBO) { \
4513 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4514 strided.u.s.type.VBO = 0; \
4515 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4516 ENTER_GL(); \
4517 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4518 vb->vbo = 0; \
4519 LEAVE_GL(); \
4521 if(strided.u.s.type.lpData) { \
4522 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4524 FIXSRC(position);
4525 FIXSRC(blendWeights);
4526 FIXSRC(blendMatrixIndices);
4527 FIXSRC(normal);
4528 FIXSRC(pSize);
4529 FIXSRC(diffuse);
4530 FIXSRC(specular);
4531 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4532 FIXSRC(texCoords[i]);
4534 FIXSRC(position2);
4535 FIXSRC(normal2);
4536 FIXSRC(tangent);
4537 FIXSRC(binormal);
4538 FIXSRC(tessFactor);
4539 FIXSRC(fog);
4540 FIXSRC(depth);
4541 FIXSRC(sample);
4542 #undef FIXSRC
4545 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4548 /*****
4549 * Get / Set Texture Stage States
4550 * TODO: Verify against dx9 definitions
4551 *****/
4552 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4554 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4556 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4558 if (Stage >= MAX_TEXTURES) {
4559 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4560 return WINED3D_OK;
4563 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4564 This->updateStateBlock->textureState[Stage][Type] = Value;
4566 if (This->isRecordingState) {
4567 TRACE("Recording... not performing anything\n");
4568 return WINED3D_OK;
4571 /* Checked after the assignments to allow proper stateblock recording */
4572 if(oldValue == Value) {
4573 TRACE("App is setting the old value over, nothing to do\n");
4574 return WINED3D_OK;
4577 if(Stage > This->stateBlock->lowest_disabled_stage &&
4578 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4579 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4580 * Changes in other states are important on disabled stages too
4582 return WINED3D_OK;
4585 if(Type == WINED3DTSS_COLOROP) {
4586 int i;
4588 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4589 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4590 * they have to be disabled
4592 * The current stage is dirtified below.
4594 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4595 TRACE("Additionally dirtifying stage %d\n", i);
4596 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4598 This->stateBlock->lowest_disabled_stage = Stage;
4599 TRACE("New lowest disabled: %d\n", Stage);
4600 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4601 /* Previously disabled stage enabled. Stages above it may need enabling
4602 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4603 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4605 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4608 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4609 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4610 break;
4612 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4613 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4615 This->stateBlock->lowest_disabled_stage = i;
4616 TRACE("New lowest disabled: %d\n", i);
4620 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4622 return WINED3D_OK;
4625 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4627 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4628 *pValue = This->updateStateBlock->textureState[Stage][Type];
4629 return WINED3D_OK;
4632 /*****
4633 * Get / Set Texture
4634 *****/
4635 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4637 IWineD3DBaseTexture *oldTexture;
4639 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4641 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4642 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4645 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4646 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4647 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4650 oldTexture = This->updateStateBlock->textures[Stage];
4652 if(pTexture != NULL) {
4653 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4655 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4656 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4657 return WINED3DERR_INVALIDCALL;
4659 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4662 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4663 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4665 This->updateStateBlock->changed.textures[Stage] = TRUE;
4666 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4667 This->updateStateBlock->textures[Stage] = pTexture;
4669 /* Handle recording of state blocks */
4670 if (This->isRecordingState) {
4671 TRACE("Recording... not performing anything\n");
4672 return WINED3D_OK;
4675 if(oldTexture == pTexture) {
4676 TRACE("App is setting the same texture again, nothing to do\n");
4677 return WINED3D_OK;
4680 /** NOTE: MSDN says that setTexture increases the reference count,
4681 * and that the application must set the texture back to null (or have a leaky application),
4682 * This means we should pass the refcount up to the parent
4683 *******************************/
4684 if (NULL != This->updateStateBlock->textures[Stage]) {
4685 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4686 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4688 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4689 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4690 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4691 * so the COLOROP and ALPHAOP have to be dirtified.
4693 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4694 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4696 if(bindCount == 1) {
4697 new->baseTexture.sampler = Stage;
4699 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4703 if (NULL != oldTexture) {
4704 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4705 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4707 IWineD3DBaseTexture_Release(oldTexture);
4708 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4709 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4710 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4713 if(bindCount && old->baseTexture.sampler == Stage) {
4714 int i;
4715 /* Have to do a search for the other sampler(s) where the texture is bound to
4716 * Shouldn't happen as long as apps bind a texture only to one stage
4718 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4719 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4720 if(This->updateStateBlock->textures[i] == oldTexture) {
4721 old->baseTexture.sampler = i;
4722 break;
4728 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4730 return WINED3D_OK;
4733 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4736 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4738 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4739 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4742 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4743 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4744 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4747 *ppTexture=This->stateBlock->textures[Stage];
4748 if (*ppTexture)
4749 IWineD3DBaseTexture_AddRef(*ppTexture);
4751 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4753 return WINED3D_OK;
4756 /*****
4757 * Get Back Buffer
4758 *****/
4759 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4760 IWineD3DSurface **ppBackBuffer) {
4761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4762 IWineD3DSwapChain *swapChain;
4763 HRESULT hr;
4765 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4767 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4768 if (hr == WINED3D_OK) {
4769 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4770 IWineD3DSwapChain_Release(swapChain);
4771 } else {
4772 *ppBackBuffer = NULL;
4774 return hr;
4777 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4779 WARN("(%p) : stub, calling idirect3d for now\n", This);
4780 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4783 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4785 IWineD3DSwapChain *swapChain;
4786 HRESULT hr;
4788 if(iSwapChain > 0) {
4789 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4790 if (hr == WINED3D_OK) {
4791 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4792 IWineD3DSwapChain_Release(swapChain);
4793 } else {
4794 FIXME("(%p) Error getting display mode\n", This);
4796 } else {
4797 /* Don't read the real display mode,
4798 but return the stored mode instead. X11 can't change the color
4799 depth, and some apps are pretty angry if they SetDisplayMode from
4800 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4802 Also don't relay to the swapchain because with ddraw it's possible
4803 that there isn't a swapchain at all */
4804 pMode->Width = This->ddraw_width;
4805 pMode->Height = This->ddraw_height;
4806 pMode->Format = This->ddraw_format;
4807 pMode->RefreshRate = 0;
4808 hr = WINED3D_OK;
4811 return hr;
4814 /*****
4815 * Stateblock related functions
4816 *****/
4818 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4820 IWineD3DStateBlockImpl *object;
4821 HRESULT temp_result;
4822 int i;
4824 TRACE("(%p)\n", This);
4826 if (This->isRecordingState) {
4827 return WINED3DERR_INVALIDCALL;
4830 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4831 if (NULL == object ) {
4832 FIXME("(%p)Error allocating memory for stateblock\n", This);
4833 return E_OUTOFMEMORY;
4835 TRACE("(%p) created object %p\n", This, object);
4836 object->wineD3DDevice= This;
4837 /** FIXME: object->parent = parent; **/
4838 object->parent = NULL;
4839 object->blockType = WINED3DSBT_RECORDED;
4840 object->ref = 1;
4841 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4843 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4844 list_init(&object->lightMap[i]);
4847 temp_result = allocate_shader_constants(object);
4848 if (WINED3D_OK != temp_result)
4849 return temp_result;
4851 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4852 This->updateStateBlock = object;
4853 This->isRecordingState = TRUE;
4855 TRACE("(%p) recording stateblock %p\n",This , object);
4856 return WINED3D_OK;
4859 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4861 unsigned int i, j;
4862 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4864 if (!This->isRecordingState) {
4865 FIXME("(%p) not recording! returning error\n", This);
4866 *ppStateBlock = NULL;
4867 return WINED3DERR_INVALIDCALL;
4870 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4871 if(object->changed.renderState[i]) {
4872 object->contained_render_states[object->num_contained_render_states] = i;
4873 object->num_contained_render_states++;
4876 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4877 if(object->changed.transform[i]) {
4878 object->contained_transform_states[object->num_contained_transform_states] = i;
4879 object->num_contained_transform_states++;
4882 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4883 if(object->changed.vertexShaderConstantsF[i]) {
4884 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4885 object->num_contained_vs_consts_f++;
4888 for(i = 0; i < MAX_CONST_I; i++) {
4889 if(object->changed.vertexShaderConstantsI[i]) {
4890 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4891 object->num_contained_vs_consts_i++;
4894 for(i = 0; i < MAX_CONST_B; i++) {
4895 if(object->changed.vertexShaderConstantsB[i]) {
4896 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4897 object->num_contained_vs_consts_b++;
4900 for(i = 0; i < MAX_CONST_I; i++) {
4901 if(object->changed.pixelShaderConstantsI[i]) {
4902 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4903 object->num_contained_ps_consts_i++;
4906 for(i = 0; i < MAX_CONST_B; i++) {
4907 if(object->changed.pixelShaderConstantsB[i]) {
4908 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4909 object->num_contained_ps_consts_b++;
4912 for(i = 0; i < MAX_TEXTURES; i++) {
4913 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4914 if(object->changed.textureState[i][j]) {
4915 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4916 object->contained_tss_states[object->num_contained_tss_states].state = j;
4917 object->num_contained_tss_states++;
4921 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4922 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4923 if(object->changed.samplerState[i][j]) {
4924 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4925 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4926 object->num_contained_sampler_states++;
4931 *ppStateBlock = (IWineD3DStateBlock*) object;
4932 This->isRecordingState = FALSE;
4933 This->updateStateBlock = This->stateBlock;
4934 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4935 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4936 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4937 return WINED3D_OK;
4940 /*****
4941 * Scene related functions
4942 *****/
4943 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4944 /* At the moment we have no need for any functionality at the beginning
4945 of a scene */
4946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4947 TRACE("(%p)\n", This);
4949 if(This->inScene) {
4950 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4951 return WINED3DERR_INVALIDCALL;
4953 This->inScene = TRUE;
4954 return WINED3D_OK;
4957 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4959 TRACE("(%p)\n", This);
4961 if(!This->inScene) {
4962 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4963 return WINED3DERR_INVALIDCALL;
4966 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4967 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4968 glFlush();
4969 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4970 * fails
4973 This->inScene = FALSE;
4974 return WINED3D_OK;
4977 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4978 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4979 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4981 IWineD3DSwapChain *swapChain = NULL;
4982 int i;
4983 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4985 TRACE("(%p) Presenting the frame\n", This);
4987 for(i = 0 ; i < swapchains ; i ++) {
4989 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4990 TRACE("presentinng chain %d, %p\n", i, swapChain);
4991 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4992 IWineD3DSwapChain_Release(swapChain);
4995 return WINED3D_OK;
4998 /* Not called from the VTable (internal subroutine) */
4999 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5000 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5001 float Z, DWORD Stencil) {
5002 GLbitfield glMask = 0;
5003 unsigned int i;
5004 WINED3DRECT curRect;
5005 RECT vp_rect;
5006 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5007 UINT drawable_width, drawable_height;
5008 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5009 IWineD3DSwapChainImpl *swapchain = NULL;
5011 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5012 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5013 * for the cleared parts, and the untouched parts.
5015 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5016 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5017 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5018 * checking all this if the dest surface is in the drawable anyway.
5020 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5021 while(1) {
5022 if(vp->X != 0 || vp->Y != 0 ||
5023 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5024 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5025 break;
5027 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5028 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5029 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5030 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5031 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5032 break;
5034 if(Count > 0 && pRects && (
5035 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5036 pRects[0].x2 < target->currentDesc.Width ||
5037 pRects[0].y2 < target->currentDesc.Height)) {
5038 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5039 break;
5041 break;
5045 target->get_drawable_size(target, &drawable_width, &drawable_height);
5047 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5048 ENTER_GL();
5050 /* Only set the values up once, as they are not changing */
5051 if (Flags & WINED3DCLEAR_STENCIL) {
5052 glClearStencil(Stencil);
5053 checkGLcall("glClearStencil");
5054 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5055 glStencilMask(0xFFFFFFFF);
5058 if (Flags & WINED3DCLEAR_ZBUFFER) {
5059 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5060 glDepthMask(GL_TRUE);
5061 glClearDepth(Z);
5062 checkGLcall("glClearDepth");
5063 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5064 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5066 if (vp->X != 0 || vp->Y != 0 ||
5067 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5068 surface_load_ds_location(This->stencilBufferTarget, location);
5070 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5071 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5072 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5073 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5074 surface_load_ds_location(This->stencilBufferTarget, location);
5076 else if (Count > 0 && pRects && (
5077 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5078 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5079 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5080 surface_load_ds_location(This->stencilBufferTarget, location);
5084 if (Flags & WINED3DCLEAR_TARGET) {
5085 TRACE("Clearing screen with glClear to color %x\n", Color);
5086 glClearColor(D3DCOLOR_R(Color),
5087 D3DCOLOR_G(Color),
5088 D3DCOLOR_B(Color),
5089 D3DCOLOR_A(Color));
5090 checkGLcall("glClearColor");
5092 /* Clear ALL colors! */
5093 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5094 glMask = glMask | GL_COLOR_BUFFER_BIT;
5097 vp_rect.left = vp->X;
5098 vp_rect.top = vp->Y;
5099 vp_rect.right = vp->X + vp->Width;
5100 vp_rect.bottom = vp->Y + vp->Height;
5101 if (!(Count > 0 && pRects)) {
5102 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5103 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5105 if(This->render_offscreen) {
5106 glScissor(vp_rect.left, vp_rect.top,
5107 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5108 } else {
5109 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5110 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5112 checkGLcall("glScissor");
5113 glClear(glMask);
5114 checkGLcall("glClear");
5115 } else {
5116 /* Now process each rect in turn */
5117 for (i = 0; i < Count; i++) {
5118 /* Note gl uses lower left, width/height */
5119 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5120 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5121 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5123 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5124 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5125 curRect.x1, (target->currentDesc.Height - curRect.y2),
5126 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5128 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5129 * The rectangle is not cleared, no error is returned, but further rectanlges are
5130 * still cleared if they are valid
5132 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5133 TRACE("Rectangle with negative dimensions, ignoring\n");
5134 continue;
5137 if(This->render_offscreen) {
5138 glScissor(curRect.x1, curRect.y1,
5139 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5140 } else {
5141 glScissor(curRect.x1, drawable_height - curRect.y2,
5142 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5144 checkGLcall("glScissor");
5146 glClear(glMask);
5147 checkGLcall("glClear");
5151 /* Restore the old values (why..?) */
5152 if (Flags & WINED3DCLEAR_STENCIL) {
5153 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5155 if (Flags & WINED3DCLEAR_TARGET) {
5156 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5157 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5158 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5159 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5160 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5162 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5163 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5165 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5167 if (Flags & WINED3DCLEAR_ZBUFFER) {
5168 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5169 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5170 surface_modify_ds_location(This->stencilBufferTarget, location);
5173 LEAVE_GL();
5175 IWineD3DSurface_GetContainer( (IWineD3DSurface *) target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5176 if (swapchain) {
5177 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5178 glFlush();
5180 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5183 return WINED3D_OK;
5186 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5187 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5189 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5191 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5192 Count, pRects, Flags, Color, Z, Stencil);
5194 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5195 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5196 /* TODO: What about depth stencil buffers without stencil bits? */
5197 return WINED3DERR_INVALIDCALL;
5200 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5203 /*****
5204 * Drawing functions
5205 *****/
5206 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5207 UINT PrimitiveCount) {
5209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5211 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5212 debug_d3dprimitivetype(PrimitiveType),
5213 StartVertex, PrimitiveCount);
5215 if(!This->stateBlock->vertexDecl) {
5216 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5217 return WINED3DERR_INVALIDCALL;
5220 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5221 if(This->stateBlock->streamIsUP) {
5222 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5223 This->stateBlock->streamIsUP = FALSE;
5226 if(This->stateBlock->loadBaseVertexIndex != 0) {
5227 This->stateBlock->loadBaseVertexIndex = 0;
5228 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5230 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5231 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5232 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5233 return WINED3D_OK;
5236 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5237 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5238 WINED3DPRIMITIVETYPE PrimitiveType,
5239 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5242 UINT idxStride = 2;
5243 IWineD3DIndexBuffer *pIB;
5244 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5245 GLuint vbo;
5247 pIB = This->stateBlock->pIndexData;
5248 if (!pIB) {
5249 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5250 * without an index buffer set. (The first time at least...)
5251 * D3D8 simply dies, but I doubt it can do much harm to return
5252 * D3DERR_INVALIDCALL there as well. */
5253 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5254 return WINED3DERR_INVALIDCALL;
5257 if(!This->stateBlock->vertexDecl) {
5258 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5259 return WINED3DERR_INVALIDCALL;
5262 if(This->stateBlock->streamIsUP) {
5263 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5264 This->stateBlock->streamIsUP = FALSE;
5266 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5268 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5269 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5270 minIndex, NumVertices, startIndex, primCount);
5272 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5273 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5274 idxStride = 2;
5275 } else {
5276 idxStride = 4;
5279 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5280 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5281 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5284 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5285 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5287 return WINED3D_OK;
5290 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5291 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5292 UINT VertexStreamZeroStride) {
5293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5294 IWineD3DVertexBuffer *vb;
5296 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5297 debug_d3dprimitivetype(PrimitiveType),
5298 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5300 if(!This->stateBlock->vertexDecl) {
5301 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5302 return WINED3DERR_INVALIDCALL;
5305 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5306 vb = This->stateBlock->streamSource[0];
5307 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5308 if(vb) IWineD3DVertexBuffer_Release(vb);
5309 This->stateBlock->streamOffset[0] = 0;
5310 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5311 This->stateBlock->streamIsUP = TRUE;
5312 This->stateBlock->loadBaseVertexIndex = 0;
5314 /* TODO: Only mark dirty if drawing from a different UP address */
5315 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5317 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5318 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5320 /* MSDN specifies stream zero settings must be set to NULL */
5321 This->stateBlock->streamStride[0] = 0;
5322 This->stateBlock->streamSource[0] = NULL;
5324 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5325 * the new stream sources or use UP drawing again
5327 return WINED3D_OK;
5330 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5331 UINT MinVertexIndex, UINT NumVertices,
5332 UINT PrimitiveCount, CONST void* pIndexData,
5333 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5334 UINT VertexStreamZeroStride) {
5335 int idxStride;
5336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5337 IWineD3DVertexBuffer *vb;
5338 IWineD3DIndexBuffer *ib;
5340 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5341 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5342 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5343 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5345 if(!This->stateBlock->vertexDecl) {
5346 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5347 return WINED3DERR_INVALIDCALL;
5350 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5351 idxStride = 2;
5352 } else {
5353 idxStride = 4;
5356 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5357 vb = This->stateBlock->streamSource[0];
5358 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5359 if(vb) IWineD3DVertexBuffer_Release(vb);
5360 This->stateBlock->streamIsUP = TRUE;
5361 This->stateBlock->streamOffset[0] = 0;
5362 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5364 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5365 This->stateBlock->baseVertexIndex = 0;
5366 This->stateBlock->loadBaseVertexIndex = 0;
5367 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5368 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5369 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5371 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5373 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5374 This->stateBlock->streamSource[0] = NULL;
5375 This->stateBlock->streamStride[0] = 0;
5376 ib = This->stateBlock->pIndexData;
5377 if(ib) {
5378 IWineD3DIndexBuffer_Release(ib);
5379 This->stateBlock->pIndexData = NULL;
5381 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5382 * SetStreamSource to specify a vertex buffer
5385 return WINED3D_OK;
5388 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5391 /* Mark the state dirty until we have nicer tracking
5392 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5393 * that value.
5395 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5396 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5397 This->stateBlock->baseVertexIndex = 0;
5398 This->up_strided = DrawPrimStrideData;
5399 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5400 This->up_strided = NULL;
5401 return WINED3D_OK;
5404 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5406 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5408 /* Mark the state dirty until we have nicer tracking
5409 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5410 * that value.
5412 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5413 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5414 This->stateBlock->streamIsUP = TRUE;
5415 This->stateBlock->baseVertexIndex = 0;
5416 This->up_strided = DrawPrimStrideData;
5417 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5418 This->up_strided = NULL;
5419 return WINED3D_OK;
5422 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5423 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5424 * not callable by the app directly no parameter validation checks are needed here.
5426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5427 WINED3DLOCKED_BOX src;
5428 WINED3DLOCKED_BOX dst;
5429 HRESULT hr;
5430 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5432 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5433 * dirtification to improve loading performance.
5435 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5436 if(FAILED(hr)) return hr;
5437 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5438 if(FAILED(hr)) {
5439 IWineD3DVolume_UnlockBox(pSourceVolume);
5440 return hr;
5443 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5445 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5446 if(FAILED(hr)) {
5447 IWineD3DVolume_UnlockBox(pSourceVolume);
5448 } else {
5449 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5451 return hr;
5454 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5455 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5457 HRESULT hr = WINED3D_OK;
5458 WINED3DRESOURCETYPE sourceType;
5459 WINED3DRESOURCETYPE destinationType;
5460 int i ,levels;
5462 /* TODO: think about moving the code into IWineD3DBaseTexture */
5464 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5466 /* verify that the source and destination textures aren't NULL */
5467 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5468 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5469 This, pSourceTexture, pDestinationTexture);
5470 hr = WINED3DERR_INVALIDCALL;
5473 if (pSourceTexture == pDestinationTexture) {
5474 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5475 This, pSourceTexture, pDestinationTexture);
5476 hr = WINED3DERR_INVALIDCALL;
5478 /* Verify that the source and destination textures are the same type */
5479 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5480 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5482 if (sourceType != destinationType) {
5483 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5484 This);
5485 hr = WINED3DERR_INVALIDCALL;
5488 /* check that both textures have the identical numbers of levels */
5489 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5490 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5491 hr = WINED3DERR_INVALIDCALL;
5494 if (WINED3D_OK == hr) {
5496 /* Make sure that the destination texture is loaded */
5497 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5499 /* Update every surface level of the texture */
5500 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5502 switch (sourceType) {
5503 case WINED3DRTYPE_TEXTURE:
5505 IWineD3DSurface *srcSurface;
5506 IWineD3DSurface *destSurface;
5508 for (i = 0 ; i < levels ; ++i) {
5509 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5510 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5511 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5512 IWineD3DSurface_Release(srcSurface);
5513 IWineD3DSurface_Release(destSurface);
5514 if (WINED3D_OK != hr) {
5515 WARN("(%p) : Call to update surface failed\n", This);
5516 return hr;
5520 break;
5521 case WINED3DRTYPE_CUBETEXTURE:
5523 IWineD3DSurface *srcSurface;
5524 IWineD3DSurface *destSurface;
5525 WINED3DCUBEMAP_FACES faceType;
5527 for (i = 0 ; i < levels ; ++i) {
5528 /* Update each cube face */
5529 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5530 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5531 if (WINED3D_OK != hr) {
5532 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5533 } else {
5534 TRACE("Got srcSurface %p\n", srcSurface);
5536 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5537 if (WINED3D_OK != hr) {
5538 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5539 } else {
5540 TRACE("Got desrSurface %p\n", destSurface);
5542 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5543 IWineD3DSurface_Release(srcSurface);
5544 IWineD3DSurface_Release(destSurface);
5545 if (WINED3D_OK != hr) {
5546 WARN("(%p) : Call to update surface failed\n", This);
5547 return hr;
5552 break;
5554 case WINED3DRTYPE_VOLUMETEXTURE:
5556 IWineD3DVolume *srcVolume = NULL;
5557 IWineD3DVolume *destVolume = NULL;
5559 for (i = 0 ; i < levels ; ++i) {
5560 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5561 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5562 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5563 IWineD3DVolume_Release(srcVolume);
5564 IWineD3DVolume_Release(destVolume);
5565 if (WINED3D_OK != hr) {
5566 WARN("(%p) : Call to update volume failed\n", This);
5567 return hr;
5571 break;
5573 default:
5574 FIXME("(%p) : Unsupported source and destination type\n", This);
5575 hr = WINED3DERR_INVALIDCALL;
5579 return hr;
5582 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5583 IWineD3DSwapChain *swapChain;
5584 HRESULT hr;
5585 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5586 if(hr == WINED3D_OK) {
5587 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5588 IWineD3DSwapChain_Release(swapChain);
5590 return hr;
5593 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5595 IWineD3DBaseTextureImpl *texture;
5596 const GlPixelFormatDesc *gl_info;
5597 DWORD i;
5599 TRACE("(%p) : %p\n", This, pNumPasses);
5601 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5602 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5603 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5604 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5606 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5607 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5608 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5611 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5612 if(!texture) continue;
5613 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5614 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5616 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5617 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5618 return E_FAIL;
5620 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5621 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5622 return E_FAIL;
5624 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5625 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5626 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5627 return E_FAIL;
5631 /* return a sensible default */
5632 *pNumPasses = 1;
5634 TRACE("returning D3D_OK\n");
5635 return WINED3D_OK;
5638 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5640 int i;
5642 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5643 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5644 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5645 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5650 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5652 int j;
5653 UINT NewSize;
5654 PALETTEENTRY **palettes;
5656 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5658 if (PaletteNumber >= MAX_PALETTES) {
5659 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5660 return WINED3DERR_INVALIDCALL;
5663 if (PaletteNumber >= This->NumberOfPalettes) {
5664 NewSize = This->NumberOfPalettes;
5665 do {
5666 NewSize *= 2;
5667 } while(PaletteNumber >= NewSize);
5668 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5669 if (!palettes) {
5670 ERR("Out of memory!\n");
5671 return E_OUTOFMEMORY;
5673 This->palettes = palettes;
5674 This->NumberOfPalettes = NewSize;
5677 if (!This->palettes[PaletteNumber]) {
5678 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5679 if (!This->palettes[PaletteNumber]) {
5680 ERR("Out of memory!\n");
5681 return E_OUTOFMEMORY;
5685 for (j = 0; j < 256; ++j) {
5686 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5687 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5688 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5689 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5691 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5692 TRACE("(%p) : returning\n", This);
5693 return WINED3D_OK;
5696 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5698 int j;
5699 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5700 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5701 /* What happens in such situation isn't documented; Native seems to silently abort
5702 on such conditions. Return Invalid Call. */
5703 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5704 return WINED3DERR_INVALIDCALL;
5706 for (j = 0; j < 256; ++j) {
5707 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5708 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5709 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5710 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5712 TRACE("(%p) : returning\n", This);
5713 return WINED3D_OK;
5716 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5718 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5719 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5720 (tested with reference rasterizer). Return Invalid Call. */
5721 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5722 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5723 return WINED3DERR_INVALIDCALL;
5725 /*TODO: stateblocks */
5726 if (This->currentPalette != PaletteNumber) {
5727 This->currentPalette = PaletteNumber;
5728 dirtify_p8_texture_samplers(This);
5730 TRACE("(%p) : returning\n", This);
5731 return WINED3D_OK;
5734 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5736 if (PaletteNumber == NULL) {
5737 WARN("(%p) : returning Invalid Call\n", This);
5738 return WINED3DERR_INVALIDCALL;
5740 /*TODO: stateblocks */
5741 *PaletteNumber = This->currentPalette;
5742 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5743 return WINED3D_OK;
5746 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5748 static BOOL showFixmes = TRUE;
5749 if (showFixmes) {
5750 FIXME("(%p) : stub\n", This);
5751 showFixmes = FALSE;
5754 This->softwareVertexProcessing = bSoftware;
5755 return WINED3D_OK;
5759 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5761 static BOOL showFixmes = TRUE;
5762 if (showFixmes) {
5763 FIXME("(%p) : stub\n", This);
5764 showFixmes = FALSE;
5766 return This->softwareVertexProcessing;
5770 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5772 IWineD3DSwapChain *swapChain;
5773 HRESULT hr;
5775 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5777 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5778 if(hr == WINED3D_OK){
5779 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5780 IWineD3DSwapChain_Release(swapChain);
5781 }else{
5782 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5784 return hr;
5788 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5790 static BOOL showfixmes = TRUE;
5791 if(nSegments != 0.0f) {
5792 if( showfixmes) {
5793 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5794 showfixmes = FALSE;
5797 return WINED3D_OK;
5800 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5802 static BOOL showfixmes = TRUE;
5803 if( showfixmes) {
5804 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5805 showfixmes = FALSE;
5807 return 0.0f;
5810 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5812 /** TODO: remove casts to IWineD3DSurfaceImpl
5813 * NOTE: move code to surface to accomplish this
5814 ****************************************/
5815 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5816 int srcWidth, srcHeight;
5817 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5818 WINED3DFORMAT destFormat, srcFormat;
5819 UINT destSize;
5820 int srcLeft, destLeft, destTop;
5821 WINED3DPOOL srcPool, destPool;
5822 int offset = 0;
5823 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5824 glDescriptor *glDescription = NULL;
5825 GLenum dummy;
5826 int sampler;
5827 int bpp;
5828 CONVERT_TYPES convert = NO_CONVERSION;
5830 WINED3DSURFACE_DESC winedesc;
5832 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5833 memset(&winedesc, 0, sizeof(winedesc));
5834 winedesc.Width = &srcSurfaceWidth;
5835 winedesc.Height = &srcSurfaceHeight;
5836 winedesc.Pool = &srcPool;
5837 winedesc.Format = &srcFormat;
5839 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5841 winedesc.Width = &destSurfaceWidth;
5842 winedesc.Height = &destSurfaceHeight;
5843 winedesc.Pool = &destPool;
5844 winedesc.Format = &destFormat;
5845 winedesc.Size = &destSize;
5847 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5849 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5850 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5851 return WINED3DERR_INVALIDCALL;
5854 /* This call loads the opengl surface directly, instead of copying the surface to the
5855 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5856 * copy in sysmem and use regular surface loading.
5858 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5859 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5860 if(convert != NO_CONVERSION) {
5861 return IWineD3DSurface_BltFast(pDestinationSurface,
5862 pDestPoint ? pDestPoint->x : 0,
5863 pDestPoint ? pDestPoint->y : 0,
5864 pSourceSurface, (RECT *) pSourceRect, 0);
5867 if (destFormat == WINED3DFMT_UNKNOWN) {
5868 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5869 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5871 /* Get the update surface description */
5872 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5875 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5877 ENTER_GL();
5879 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5880 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5881 checkGLcall("glActiveTextureARB");
5884 /* Make sure the surface is loaded and up to date */
5885 IWineD3DSurface_PreLoad(pDestinationSurface);
5886 IWineD3DSurface_BindTexture(pDestinationSurface);
5888 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5890 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5891 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5892 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5893 srcLeft = pSourceRect ? pSourceRect->left : 0;
5894 destLeft = pDestPoint ? pDestPoint->x : 0;
5895 destTop = pDestPoint ? pDestPoint->y : 0;
5898 /* This function doesn't support compressed textures
5899 the pitch is just bytesPerPixel * width */
5900 if(srcWidth != srcSurfaceWidth || srcLeft ){
5901 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5902 offset += srcLeft * pSrcSurface->bytesPerPixel;
5903 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5905 /* TODO DXT formats */
5907 if(pSourceRect != NULL && pSourceRect->top != 0){
5908 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5910 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5911 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
5912 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5914 /* Sanity check */
5915 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5917 /* need to lock the surface to get the data */
5918 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5921 /* TODO: Cube and volume support */
5922 if(rowoffset != 0){
5923 /* not a whole row so we have to do it a line at a time */
5924 int j;
5926 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5927 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5929 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5931 glTexSubImage2D(glDescription->target
5932 ,glDescription->level
5933 ,destLeft
5935 ,srcWidth
5937 ,glDescription->glFormat
5938 ,glDescription->glType
5939 ,data /* could be quicker using */
5941 data += rowoffset;
5944 } else { /* Full width, so just write out the whole texture */
5945 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5947 if (WINED3DFMT_DXT1 == destFormat ||
5948 WINED3DFMT_DXT2 == destFormat ||
5949 WINED3DFMT_DXT3 == destFormat ||
5950 WINED3DFMT_DXT4 == destFormat ||
5951 WINED3DFMT_DXT5 == destFormat) {
5952 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5953 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5954 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5955 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5956 } if (destFormat != srcFormat) {
5957 FIXME("Updating mixed format compressed texture is not curretly support\n");
5958 } else {
5959 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
5960 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
5962 } else {
5963 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5967 } else {
5968 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
5969 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
5972 checkGLcall("glTexSubImage2D");
5974 LEAVE_GL();
5976 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5977 sampler = This->rev_tex_unit_map[0];
5978 if (sampler != -1) {
5979 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5982 return WINED3D_OK;
5985 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5987 struct WineD3DRectPatch *patch;
5988 unsigned int i;
5989 struct list *e;
5990 BOOL found;
5991 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5993 if(!(Handle || pRectPatchInfo)) {
5994 /* TODO: Write a test for the return value, thus the FIXME */
5995 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5996 return WINED3DERR_INVALIDCALL;
5999 if(Handle) {
6000 i = PATCHMAP_HASHFUNC(Handle);
6001 found = FALSE;
6002 LIST_FOR_EACH(e, &This->patches[i]) {
6003 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6004 if(patch->Handle == Handle) {
6005 found = TRUE;
6006 break;
6010 if(!found) {
6011 TRACE("Patch does not exist. Creating a new one\n");
6012 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6013 patch->Handle = Handle;
6014 list_add_head(&This->patches[i], &patch->entry);
6015 } else {
6016 TRACE("Found existing patch %p\n", patch);
6018 } else {
6019 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6020 * attributes we have to tesselate, read back, and draw. This needs a patch
6021 * management structure instance. Create one.
6023 * A possible improvement is to check if a vertex shader is used, and if not directly
6024 * draw the patch.
6026 FIXME("Drawing an uncached patch. This is slow\n");
6027 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6030 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6031 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6032 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6033 HRESULT hr;
6034 TRACE("Tesselation density or patch info changed, retesselating\n");
6036 if(pRectPatchInfo) {
6037 patch->RectPatchInfo = *pRectPatchInfo;
6039 patch->numSegs[0] = pNumSegs[0];
6040 patch->numSegs[1] = pNumSegs[1];
6041 patch->numSegs[2] = pNumSegs[2];
6042 patch->numSegs[3] = pNumSegs[3];
6044 hr = tesselate_rectpatch(This, patch);
6045 if(FAILED(hr)) {
6046 WARN("Patch tesselation failed\n");
6048 /* Do not release the handle to store the params of the patch */
6049 if(!Handle) {
6050 HeapFree(GetProcessHeap(), 0, patch);
6052 return hr;
6056 This->currentPatch = patch;
6057 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6058 This->currentPatch = NULL;
6060 /* Destroy uncached patches */
6061 if(!Handle) {
6062 HeapFree(GetProcessHeap(), 0, patch->mem);
6063 HeapFree(GetProcessHeap(), 0, patch);
6065 return WINED3D_OK;
6068 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6070 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6071 FIXME("(%p) : Stub\n", This);
6072 return WINED3D_OK;
6075 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6077 int i;
6078 struct WineD3DRectPatch *patch;
6079 struct list *e;
6080 TRACE("(%p) Handle(%d)\n", This, Handle);
6082 i = PATCHMAP_HASHFUNC(Handle);
6083 LIST_FOR_EACH(e, &This->patches[i]) {
6084 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6085 if(patch->Handle == Handle) {
6086 TRACE("Deleting patch %p\n", patch);
6087 list_remove(&patch->entry);
6088 HeapFree(GetProcessHeap(), 0, patch->mem);
6089 HeapFree(GetProcessHeap(), 0, patch);
6090 return WINED3D_OK;
6094 /* TODO: Write a test for the return value */
6095 FIXME("Attempt to destroy nonexistent patch\n");
6096 return WINED3DERR_INVALIDCALL;
6099 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6100 HRESULT hr;
6101 IWineD3DSwapChain *swapchain;
6103 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6104 if (SUCCEEDED(hr)) {
6105 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6106 return swapchain;
6109 return NULL;
6112 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6114 IWineD3DSwapChain *swapchain;
6116 swapchain = get_swapchain(surface);
6117 if (swapchain) {
6118 GLenum buffer;
6120 TRACE("Surface %p is onscreen\n", surface);
6122 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6123 ENTER_GL();
6124 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6125 buffer = surface_get_gl_buffer(surface, swapchain);
6126 glDrawBuffer(buffer);
6127 checkGLcall("glDrawBuffer()");
6128 } else {
6129 TRACE("Surface %p is offscreen\n", surface);
6131 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6132 ENTER_GL();
6133 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6134 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6135 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6136 checkGLcall("glFramebufferRenderbufferEXT");
6139 if (rect) {
6140 glEnable(GL_SCISSOR_TEST);
6141 if(!swapchain) {
6142 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6143 } else {
6144 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6145 rect->x2 - rect->x1, rect->y2 - rect->y1);
6147 checkGLcall("glScissor");
6148 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6149 } else {
6150 glDisable(GL_SCISSOR_TEST);
6152 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6154 glDisable(GL_BLEND);
6155 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6157 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6158 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6160 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6161 glClear(GL_COLOR_BUFFER_BIT);
6162 checkGLcall("glClear");
6164 if (This->activeContext->current_fbo) {
6165 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6166 } else {
6167 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6168 checkGLcall("glBindFramebuffer()");
6171 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6172 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6173 glDrawBuffer(GL_BACK);
6174 checkGLcall("glDrawBuffer()");
6177 LEAVE_GL();
6180 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6181 unsigned int r, g, b, a;
6182 DWORD ret;
6184 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6185 destfmt == WINED3DFMT_R8G8B8)
6186 return color;
6188 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6190 a = (color & 0xff000000) >> 24;
6191 r = (color & 0x00ff0000) >> 16;
6192 g = (color & 0x0000ff00) >> 8;
6193 b = (color & 0x000000ff) >> 0;
6195 switch(destfmt)
6197 case WINED3DFMT_R5G6B5:
6198 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6199 r = (r * 32) / 256;
6200 g = (g * 64) / 256;
6201 b = (b * 32) / 256;
6202 ret = r << 11;
6203 ret |= g << 5;
6204 ret |= b;
6205 TRACE("Returning %08x\n", ret);
6206 return ret;
6208 case WINED3DFMT_X1R5G5B5:
6209 case WINED3DFMT_A1R5G5B5:
6210 a = (a * 2) / 256;
6211 r = (r * 32) / 256;
6212 g = (g * 32) / 256;
6213 b = (b * 32) / 256;
6214 ret = a << 15;
6215 ret |= r << 10;
6216 ret |= g << 5;
6217 ret |= b << 0;
6218 TRACE("Returning %08x\n", ret);
6219 return ret;
6221 case WINED3DFMT_A8:
6222 TRACE("Returning %08x\n", a);
6223 return a;
6225 case WINED3DFMT_X4R4G4B4:
6226 case WINED3DFMT_A4R4G4B4:
6227 a = (a * 16) / 256;
6228 r = (r * 16) / 256;
6229 g = (g * 16) / 256;
6230 b = (b * 16) / 256;
6231 ret = a << 12;
6232 ret |= r << 8;
6233 ret |= g << 4;
6234 ret |= b << 0;
6235 TRACE("Returning %08x\n", ret);
6236 return ret;
6238 case WINED3DFMT_R3G3B2:
6239 r = (r * 8) / 256;
6240 g = (g * 8) / 256;
6241 b = (b * 4) / 256;
6242 ret = r << 5;
6243 ret |= g << 2;
6244 ret |= b << 0;
6245 TRACE("Returning %08x\n", ret);
6246 return ret;
6248 case WINED3DFMT_X8B8G8R8:
6249 case WINED3DFMT_A8B8G8R8:
6250 ret = a << 24;
6251 ret |= b << 16;
6252 ret |= g << 8;
6253 ret |= r << 0;
6254 TRACE("Returning %08x\n", ret);
6255 return ret;
6257 case WINED3DFMT_A2R10G10B10:
6258 a = (a * 4) / 256;
6259 r = (r * 1024) / 256;
6260 g = (g * 1024) / 256;
6261 b = (b * 1024) / 256;
6262 ret = a << 30;
6263 ret |= r << 20;
6264 ret |= g << 10;
6265 ret |= b << 0;
6266 TRACE("Returning %08x\n", ret);
6267 return ret;
6269 case WINED3DFMT_A2B10G10R10:
6270 a = (a * 4) / 256;
6271 r = (r * 1024) / 256;
6272 g = (g * 1024) / 256;
6273 b = (b * 1024) / 256;
6274 ret = a << 30;
6275 ret |= b << 20;
6276 ret |= g << 10;
6277 ret |= r << 0;
6278 TRACE("Returning %08x\n", ret);
6279 return ret;
6281 default:
6282 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6283 return 0;
6287 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6289 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6290 WINEDDBLTFX BltFx;
6291 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6293 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6294 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6295 return WINED3DERR_INVALIDCALL;
6298 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6299 color_fill_fbo(iface, pSurface, pRect, color);
6300 return WINED3D_OK;
6301 } else {
6302 /* Just forward this to the DirectDraw blitting engine */
6303 memset(&BltFx, 0, sizeof(BltFx));
6304 BltFx.dwSize = sizeof(BltFx);
6305 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6306 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6310 /* rendertarget and depth stencil functions */
6311 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6314 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6315 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6316 return WINED3DERR_INVALIDCALL;
6319 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6320 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6321 /* Note inc ref on returned surface */
6322 if(*ppRenderTarget != NULL)
6323 IWineD3DSurface_AddRef(*ppRenderTarget);
6324 return WINED3D_OK;
6327 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6329 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6330 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6331 IWineD3DSwapChainImpl *Swapchain;
6332 HRESULT hr;
6334 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6336 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6337 if(hr != WINED3D_OK) {
6338 ERR("Can't get the swapchain\n");
6339 return hr;
6342 /* Make sure to release the swapchain */
6343 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6345 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6346 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6347 return WINED3DERR_INVALIDCALL;
6349 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6350 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6351 return WINED3DERR_INVALIDCALL;
6354 if(Swapchain->frontBuffer != Front) {
6355 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6357 if(Swapchain->frontBuffer)
6358 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6359 Swapchain->frontBuffer = Front;
6361 if(Swapchain->frontBuffer) {
6362 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6366 if(Back && !Swapchain->backBuffer) {
6367 /* We need memory for the back buffer array - only one back buffer this way */
6368 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6369 if(!Swapchain->backBuffer) {
6370 ERR("Out of memory\n");
6371 return E_OUTOFMEMORY;
6375 if(Swapchain->backBuffer[0] != Back) {
6376 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6378 /* What to do about the context here in the case of multithreading? Not sure.
6379 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6381 ENTER_GL();
6382 if(!Swapchain->backBuffer[0]) {
6383 /* GL was told to draw to the front buffer at creation,
6384 * undo that
6386 glDrawBuffer(GL_BACK);
6387 checkGLcall("glDrawBuffer(GL_BACK)");
6388 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6389 Swapchain->presentParms.BackBufferCount = 1;
6390 } else if (!Back) {
6391 /* That makes problems - disable for now */
6392 /* glDrawBuffer(GL_FRONT); */
6393 checkGLcall("glDrawBuffer(GL_FRONT)");
6394 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6395 Swapchain->presentParms.BackBufferCount = 0;
6397 LEAVE_GL();
6399 if(Swapchain->backBuffer[0])
6400 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6401 Swapchain->backBuffer[0] = Back;
6403 if(Swapchain->backBuffer[0]) {
6404 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6405 } else {
6406 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6407 Swapchain->backBuffer = NULL;
6412 return WINED3D_OK;
6415 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6417 *ppZStencilSurface = This->stencilBufferTarget;
6418 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6420 if(*ppZStencilSurface != NULL) {
6421 /* Note inc ref on returned surface */
6422 IWineD3DSurface_AddRef(*ppZStencilSurface);
6423 return WINED3D_OK;
6424 } else {
6425 return WINED3DERR_NOTFOUND;
6429 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6430 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6432 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6433 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6434 GLenum gl_filter;
6435 POINT offset = {0, 0};
6437 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6438 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6439 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6440 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6442 switch (filter) {
6443 case WINED3DTEXF_LINEAR:
6444 gl_filter = GL_LINEAR;
6445 break;
6447 default:
6448 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6449 case WINED3DTEXF_NONE:
6450 case WINED3DTEXF_POINT:
6451 gl_filter = GL_NEAREST;
6452 break;
6455 /* Attach src surface to src fbo */
6456 src_swapchain = get_swapchain(src_surface);
6457 if (src_swapchain) {
6458 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6460 TRACE("Source surface %p is onscreen\n", src_surface);
6461 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6462 /* Make sure the drawable is up to date. In the offscreen case
6463 * attach_surface_fbo() implicitly takes care of this. */
6464 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6466 if(buffer == GL_FRONT) {
6467 RECT windowsize;
6468 UINT h;
6469 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6470 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6471 h = windowsize.bottom - windowsize.top;
6472 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6473 src_rect->y1 = offset.y + h - src_rect->y1;
6474 src_rect->y2 = offset.y + h - src_rect->y2;
6475 } else {
6476 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6477 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6480 ENTER_GL();
6481 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6482 glReadBuffer(buffer);
6483 checkGLcall("glReadBuffer()");
6484 } else {
6485 TRACE("Source surface %p is offscreen\n", src_surface);
6486 ENTER_GL();
6487 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6488 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6489 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6490 checkGLcall("glReadBuffer()");
6491 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6492 checkGLcall("glFramebufferRenderbufferEXT");
6494 LEAVE_GL();
6496 /* Attach dst surface to dst fbo */
6497 dst_swapchain = get_swapchain(dst_surface);
6498 if (dst_swapchain) {
6499 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6501 TRACE("Destination surface %p is onscreen\n", dst_surface);
6502 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6503 /* Make sure the drawable is up to date. In the offscreen case
6504 * attach_surface_fbo() implicitly takes care of this. */
6505 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6507 if(buffer == GL_FRONT) {
6508 RECT windowsize;
6509 UINT h;
6510 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6511 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6512 h = windowsize.bottom - windowsize.top;
6513 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6514 dst_rect->y1 = offset.y + h - dst_rect->y1;
6515 dst_rect->y2 = offset.y + h - dst_rect->y2;
6516 } else {
6517 /* Screen coords = window coords, surface height = window height */
6518 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6519 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6522 ENTER_GL();
6523 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6524 glDrawBuffer(buffer);
6525 checkGLcall("glDrawBuffer()");
6526 } else {
6527 TRACE("Destination surface %p is offscreen\n", dst_surface);
6529 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6530 if(!src_swapchain) {
6531 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6534 ENTER_GL();
6535 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6536 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6537 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6538 checkGLcall("glDrawBuffer()");
6539 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6540 checkGLcall("glFramebufferRenderbufferEXT");
6542 glDisable(GL_SCISSOR_TEST);
6543 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6545 if (flip) {
6546 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6547 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6548 checkGLcall("glBlitFramebuffer()");
6549 } else {
6550 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6551 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6552 checkGLcall("glBlitFramebuffer()");
6555 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6557 if (This->activeContext->current_fbo) {
6558 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6559 } else {
6560 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6561 checkGLcall("glBindFramebuffer()");
6564 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6565 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6566 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6567 glDrawBuffer(GL_BACK);
6568 checkGLcall("glDrawBuffer()");
6570 LEAVE_GL();
6573 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6575 WINED3DVIEWPORT viewport;
6577 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6579 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6580 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6581 This, RenderTargetIndex, GL_LIMITS(buffers));
6582 return WINED3DERR_INVALIDCALL;
6585 /* MSDN says that null disables the render target
6586 but a device must always be associated with a render target
6587 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6589 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6590 FIXME("Trying to set render target 0 to NULL\n");
6591 return WINED3DERR_INVALIDCALL;
6593 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6594 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);
6595 return WINED3DERR_INVALIDCALL;
6598 /* If we are trying to set what we already have, don't bother */
6599 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6600 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6601 return WINED3D_OK;
6603 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6604 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6605 This->render_targets[RenderTargetIndex] = pRenderTarget;
6607 /* Render target 0 is special */
6608 if(RenderTargetIndex == 0) {
6609 /* Finally, reset the viewport as the MSDN states. */
6610 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6611 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6612 viewport.X = 0;
6613 viewport.Y = 0;
6614 viewport.MaxZ = 1.0f;
6615 viewport.MinZ = 0.0f;
6616 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6617 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6618 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6620 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6622 return WINED3D_OK;
6625 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6627 HRESULT hr = WINED3D_OK;
6628 IWineD3DSurface *tmp;
6630 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6632 if (pNewZStencil == This->stencilBufferTarget) {
6633 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6634 } else {
6635 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6636 * depending on the renter target implementation being used.
6637 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6638 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6639 * stencil buffer and incur an extra memory overhead
6640 ******************************************************/
6642 if (This->stencilBufferTarget) {
6643 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6644 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6645 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6646 } else {
6647 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6648 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6649 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6653 tmp = This->stencilBufferTarget;
6654 This->stencilBufferTarget = pNewZStencil;
6655 /* should we be calling the parent or the wined3d surface? */
6656 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6657 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6658 hr = WINED3D_OK;
6660 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6661 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6662 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6663 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6664 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6668 return hr;
6671 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6672 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6674 /* TODO: the use of Impl is deprecated. */
6675 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6676 WINED3DLOCKED_RECT lockedRect;
6678 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6680 /* some basic validation checks */
6681 if(This->cursorTexture) {
6682 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6683 ENTER_GL();
6684 glDeleteTextures(1, &This->cursorTexture);
6685 LEAVE_GL();
6686 This->cursorTexture = 0;
6689 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6690 This->haveHardwareCursor = TRUE;
6691 else
6692 This->haveHardwareCursor = FALSE;
6694 if(pCursorBitmap) {
6695 WINED3DLOCKED_RECT rect;
6697 /* MSDN: Cursor must be A8R8G8B8 */
6698 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6699 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6700 return WINED3DERR_INVALIDCALL;
6703 /* MSDN: Cursor must be smaller than the display mode */
6704 if(pSur->currentDesc.Width > This->ddraw_width ||
6705 pSur->currentDesc.Height > This->ddraw_height) {
6706 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);
6707 return WINED3DERR_INVALIDCALL;
6710 if (!This->haveHardwareCursor) {
6711 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6713 /* Do not store the surface's pointer because the application may
6714 * release it after setting the cursor image. Windows doesn't
6715 * addref the set surface, so we can't do this either without
6716 * creating circular refcount dependencies. Copy out the gl texture
6717 * instead.
6719 This->cursorWidth = pSur->currentDesc.Width;
6720 This->cursorHeight = pSur->currentDesc.Height;
6721 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6723 const GlPixelFormatDesc *glDesc;
6724 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6725 char *mem, *bits = (char *)rect.pBits;
6726 GLint intfmt = glDesc->glInternal;
6727 GLint format = glDesc->glFormat;
6728 GLint type = glDesc->glType;
6729 INT height = This->cursorHeight;
6730 INT width = This->cursorWidth;
6731 INT bpp = tableEntry->bpp;
6732 INT i, sampler;
6734 /* Reformat the texture memory (pitch and width can be
6735 * different) */
6736 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6737 for(i = 0; i < height; i++)
6738 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6739 IWineD3DSurface_UnlockRect(pCursorBitmap);
6740 ENTER_GL();
6742 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6743 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6744 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6747 /* Make sure that a proper texture unit is selected */
6748 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6749 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6750 checkGLcall("glActiveTextureARB");
6752 sampler = This->rev_tex_unit_map[0];
6753 if (sampler != -1) {
6754 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6756 /* Create a new cursor texture */
6757 glGenTextures(1, &This->cursorTexture);
6758 checkGLcall("glGenTextures");
6759 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6760 checkGLcall("glBindTexture");
6761 /* Copy the bitmap memory into the cursor texture */
6762 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6763 HeapFree(GetProcessHeap(), 0, mem);
6764 checkGLcall("glTexImage2D");
6766 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6767 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6768 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6771 LEAVE_GL();
6773 else
6775 FIXME("A cursor texture was not returned.\n");
6776 This->cursorTexture = 0;
6779 else
6781 /* Draw a hardware cursor */
6782 ICONINFO cursorInfo;
6783 HCURSOR cursor;
6784 /* Create and clear maskBits because it is not needed for
6785 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6786 * chunks. */
6787 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6788 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6789 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6790 WINED3DLOCK_NO_DIRTY_UPDATE |
6791 WINED3DLOCK_READONLY
6793 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6794 pSur->currentDesc.Height);
6796 cursorInfo.fIcon = FALSE;
6797 cursorInfo.xHotspot = XHotSpot;
6798 cursorInfo.yHotspot = YHotSpot;
6799 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6800 pSur->currentDesc.Height, 1,
6801 1, &maskBits);
6802 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6803 pSur->currentDesc.Height, 1,
6804 32, lockedRect.pBits);
6805 IWineD3DSurface_UnlockRect(pCursorBitmap);
6806 /* Create our cursor and clean up. */
6807 cursor = CreateIconIndirect(&cursorInfo);
6808 SetCursor(cursor);
6809 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6810 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6811 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6812 This->hardwareCursor = cursor;
6813 HeapFree(GetProcessHeap(), 0, maskBits);
6817 This->xHotSpot = XHotSpot;
6818 This->yHotSpot = YHotSpot;
6819 return WINED3D_OK;
6822 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6824 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6826 This->xScreenSpace = XScreenSpace;
6827 This->yScreenSpace = YScreenSpace;
6829 return;
6833 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6835 BOOL oldVisible = This->bCursorVisible;
6836 POINT pt;
6838 TRACE("(%p) : visible(%d)\n", This, bShow);
6841 * When ShowCursor is first called it should make the cursor appear at the OS's last
6842 * known cursor position. Because of this, some applications just repetitively call
6843 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6845 GetCursorPos(&pt);
6846 This->xScreenSpace = pt.x;
6847 This->yScreenSpace = pt.y;
6849 if (This->haveHardwareCursor) {
6850 This->bCursorVisible = bShow;
6851 if (bShow)
6852 SetCursor(This->hardwareCursor);
6853 else
6854 SetCursor(NULL);
6856 else
6858 if (This->cursorTexture)
6859 This->bCursorVisible = bShow;
6862 return oldVisible;
6865 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6867 IWineD3DResourceImpl *resource;
6868 TRACE("(%p) : state (%u)\n", This, This->state);
6870 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6871 switch (This->state) {
6872 case WINED3D_OK:
6873 return WINED3D_OK;
6874 case WINED3DERR_DEVICELOST:
6876 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6877 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6878 return WINED3DERR_DEVICENOTRESET;
6880 return WINED3DERR_DEVICELOST;
6882 case WINED3DERR_DRIVERINTERNALERROR:
6883 return WINED3DERR_DRIVERINTERNALERROR;
6886 /* Unknown state */
6887 return WINED3DERR_DRIVERINTERNALERROR;
6891 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6893 /** FIXME: Resource tracking needs to be done,
6894 * The closes we can do to this is set the priorities of all managed textures low
6895 * and then reset them.
6896 ***********************************************************/
6897 FIXME("(%p) : stub\n", This);
6898 return WINED3D_OK;
6901 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6902 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6904 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6905 if(surface->Flags & SFLAG_DIBSECTION) {
6906 /* Release the DC */
6907 SelectObject(surface->hDC, surface->dib.holdbitmap);
6908 DeleteDC(surface->hDC);
6909 /* Release the DIB section */
6910 DeleteObject(surface->dib.DIBsection);
6911 surface->dib.bitmap_data = NULL;
6912 surface->resource.allocatedMemory = NULL;
6913 surface->Flags &= ~SFLAG_DIBSECTION;
6915 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6916 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6917 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6918 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6919 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6920 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6921 } else {
6922 surface->pow2Width = surface->pow2Height = 1;
6923 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6924 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6926 surface->glRect.left = 0;
6927 surface->glRect.top = 0;
6928 surface->glRect.right = surface->pow2Width;
6929 surface->glRect.bottom = surface->pow2Height;
6931 if(surface->glDescription.textureName) {
6932 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6933 ENTER_GL();
6934 glDeleteTextures(1, &surface->glDescription.textureName);
6935 LEAVE_GL();
6936 surface->glDescription.textureName = 0;
6937 surface->Flags &= ~SFLAG_CLIENT;
6939 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6940 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6941 surface->Flags |= SFLAG_NONPOW2;
6942 } else {
6943 surface->Flags &= ~SFLAG_NONPOW2;
6945 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6946 surface->resource.allocatedMemory = NULL;
6947 surface->resource.heapMemory = NULL;
6948 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6949 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6950 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6951 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6952 } else {
6953 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6957 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6958 TRACE("Unloading resource %p\n", resource);
6959 IWineD3DResource_UnLoad(resource);
6960 IWineD3DResource_Release(resource);
6961 return S_OK;
6964 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
6965 UINT i, count;
6966 WINED3DDISPLAYMODE m;
6967 HRESULT hr;
6969 /* All Windowed modes are supported, as is leaving the current mode */
6970 if(pp->Windowed) return TRUE;
6971 if(!pp->BackBufferWidth) return TRUE;
6972 if(!pp->BackBufferHeight) return TRUE;
6974 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6975 for(i = 0; i < count; i++) {
6976 memset(&m, 0, sizeof(m));
6977 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6978 if(FAILED(hr)) {
6979 ERR("EnumAdapterModes failed\n");
6981 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6982 /* Mode found, it is supported */
6983 return TRUE;
6986 /* Mode not found -> not supported */
6987 return FALSE;
6990 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6992 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6993 UINT i;
6994 IWineD3DBaseShaderImpl *shader;
6996 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6997 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6998 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7001 ENTER_GL();
7002 if(This->depth_blt_texture) {
7003 glDeleteTextures(1, &This->depth_blt_texture);
7004 This->depth_blt_texture = 0;
7006 if (This->depth_blt_rb) {
7007 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7008 This->depth_blt_rb = 0;
7009 This->depth_blt_rb_w = 0;
7010 This->depth_blt_rb_h = 0;
7012 This->blitter->free_private(iface);
7013 This->frag_pipe->free_private(iface);
7014 This->shader_backend->shader_free_private(iface);
7016 for (i = 0; i < GL_LIMITS(textures); i++) {
7017 /* Textures are recreated below */
7018 glDeleteTextures(1, &This->dummyTextureName[i]);
7019 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7020 This->dummyTextureName[i] = 0;
7022 LEAVE_GL();
7024 while(This->numContexts) {
7025 DestroyContext(This, This->contexts[0]);
7027 This->activeContext = NULL;
7028 HeapFree(GetProcessHeap(), 0, swapchain->context);
7029 swapchain->context = NULL;
7030 swapchain->num_contexts = 0;
7033 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7035 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7036 HRESULT hr;
7037 IWineD3DSurfaceImpl *target;
7039 /* Recreate the primary swapchain's context */
7040 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7041 if(swapchain->backBuffer) {
7042 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7043 } else {
7044 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7046 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7047 &swapchain->presentParms);
7048 swapchain->num_contexts = 1;
7049 This->activeContext = swapchain->context[0];
7051 create_dummy_textures(This);
7053 hr = This->shader_backend->shader_alloc_private(iface);
7054 if(FAILED(hr)) {
7055 ERR("Failed to recreate shader private data\n");
7056 goto err_out;
7058 hr = This->frag_pipe->alloc_private(iface);
7059 if(FAILED(hr)) {
7060 TRACE("Fragment pipeline private data couldn't be allocated\n");
7061 goto err_out;
7063 hr = This->blitter->alloc_private(iface);
7064 if(FAILED(hr)) {
7065 TRACE("Blitter private data couldn't be allocated\n");
7066 goto err_out;
7069 return WINED3D_OK;
7071 err_out:
7072 This->blitter->free_private(iface);
7073 This->frag_pipe->free_private(iface);
7074 This->shader_backend->shader_free_private(iface);
7075 return hr;
7078 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7080 IWineD3DSwapChainImpl *swapchain;
7081 HRESULT hr;
7082 BOOL DisplayModeChanged = FALSE;
7083 WINED3DDISPLAYMODE mode;
7084 TRACE("(%p)\n", This);
7086 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7087 if(FAILED(hr)) {
7088 ERR("Failed to get the first implicit swapchain\n");
7089 return hr;
7092 if(!is_display_mode_supported(This, pPresentationParameters)) {
7093 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7094 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7095 pPresentationParameters->BackBufferHeight);
7096 return WINED3DERR_INVALIDCALL;
7099 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7100 * on an existing gl context, so there's no real need for recreation.
7102 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7104 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7106 TRACE("New params:\n");
7107 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7108 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7109 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7110 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7111 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7112 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7113 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7114 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7115 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7116 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7117 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7118 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7119 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7121 /* No special treatment of these parameters. Just store them */
7122 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7123 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7124 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7125 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7127 /* What to do about these? */
7128 if(pPresentationParameters->BackBufferCount != 0 &&
7129 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7130 ERR("Cannot change the back buffer count yet\n");
7132 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7133 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7134 ERR("Cannot change the back buffer format yet\n");
7136 if(pPresentationParameters->hDeviceWindow != NULL &&
7137 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7138 ERR("Cannot change the device window yet\n");
7140 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7141 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7142 return WINED3DERR_INVALIDCALL;
7145 /* Reset the depth stencil */
7146 if (pPresentationParameters->EnableAutoDepthStencil)
7147 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7148 else
7149 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7151 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7153 if(pPresentationParameters->Windowed) {
7154 mode.Width = swapchain->orig_width;
7155 mode.Height = swapchain->orig_height;
7156 mode.RefreshRate = 0;
7157 mode.Format = swapchain->presentParms.BackBufferFormat;
7158 } else {
7159 mode.Width = pPresentationParameters->BackBufferWidth;
7160 mode.Height = pPresentationParameters->BackBufferHeight;
7161 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7162 mode.Format = swapchain->presentParms.BackBufferFormat;
7165 /* Should Width == 800 && Height == 0 set 800x600? */
7166 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7167 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7168 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7170 WINED3DVIEWPORT vp;
7171 int i;
7173 vp.X = 0;
7174 vp.Y = 0;
7175 vp.Width = pPresentationParameters->BackBufferWidth;
7176 vp.Height = pPresentationParameters->BackBufferHeight;
7177 vp.MinZ = 0;
7178 vp.MaxZ = 1;
7180 if(!pPresentationParameters->Windowed) {
7181 DisplayModeChanged = TRUE;
7183 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7184 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7186 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7187 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7188 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7190 if(This->auto_depth_stencil_buffer) {
7191 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7195 /* Now set the new viewport */
7196 IWineD3DDevice_SetViewport(iface, &vp);
7199 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7200 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7201 DisplayModeChanged) {
7203 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7205 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7206 if(swapchain->presentParms.Windowed) {
7207 /* switch from windowed to fs */
7208 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7209 pPresentationParameters->BackBufferWidth,
7210 pPresentationParameters->BackBufferHeight);
7211 } else {
7212 /* Fullscreen -> fullscreen mode change */
7213 MoveWindow(swapchain->win_handle, 0, 0,
7214 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7215 TRUE);
7217 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7218 /* Fullscreen -> windowed switch */
7219 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7221 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7222 } else if(!pPresentationParameters->Windowed) {
7223 DWORD style = This->style, exStyle = This->exStyle;
7224 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7225 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7226 * Reset to clear up their mess. Guild Wars also loses the device during that.
7228 This->style = 0;
7229 This->exStyle = 0;
7230 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7231 pPresentationParameters->BackBufferWidth,
7232 pPresentationParameters->BackBufferHeight);
7233 This->style = style;
7234 This->exStyle = exStyle;
7237 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7238 if(FAILED(hr)) {
7239 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7242 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7243 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7245 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7246 * first use
7248 return hr;
7251 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7253 /** FIXME: always true at the moment **/
7254 if(!bEnableDialogs) {
7255 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7257 return WINED3D_OK;
7261 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7263 TRACE("(%p) : pParameters %p\n", This, pParameters);
7265 *pParameters = This->createParms;
7266 return WINED3D_OK;
7269 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7270 IWineD3DSwapChain *swapchain;
7272 TRACE("Relaying to swapchain\n");
7274 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7275 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7276 IWineD3DSwapChain_Release(swapchain);
7278 return;
7281 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7282 IWineD3DSwapChain *swapchain;
7284 TRACE("Relaying to swapchain\n");
7286 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7287 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7288 IWineD3DSwapChain_Release(swapchain);
7290 return;
7294 /** ********************************************************
7295 * Notification functions
7296 ** ********************************************************/
7297 /** This function must be called in the release of a resource when ref == 0,
7298 * the contents of resource must still be correct,
7299 * any handles to other resource held by the caller must be closed
7300 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7301 *****************************************************/
7302 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7305 TRACE("(%p) : Adding Resource %p\n", This, resource);
7306 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7309 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7310 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7312 TRACE("(%p) : Removing resource %p\n", This, resource);
7314 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7318 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7320 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7321 int counter;
7323 TRACE("(%p) : resource %p\n", This, resource);
7325 context_resource_released(iface, resource, type);
7327 switch (type) {
7328 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7329 case WINED3DRTYPE_SURFACE: {
7330 unsigned int i;
7332 /* Cleanup any FBO attachments if d3d is enabled */
7333 if(This->d3d_initialized) {
7334 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7335 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7337 TRACE("Last active render target destroyed\n");
7338 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7339 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7340 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7341 * and the lastActiveRenderTarget member shouldn't matter
7343 if(swapchain) {
7344 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7345 TRACE("Activating primary back buffer\n");
7346 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7347 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7348 /* Single buffering environment */
7349 TRACE("Activating primary front buffer\n");
7350 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7351 } else {
7352 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7353 /* Implicit render target destroyed, that means the device is being destroyed
7354 * whatever we set here, it shouldn't matter
7356 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7358 } else {
7359 /* May happen during ddraw uninitialization */
7360 TRACE("Render target set, but swapchain does not exist!\n");
7361 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7365 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7366 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7367 This->render_targets[i] = NULL;
7370 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7371 This->stencilBufferTarget = NULL;
7375 break;
7377 case WINED3DRTYPE_TEXTURE:
7378 case WINED3DRTYPE_CUBETEXTURE:
7379 case WINED3DRTYPE_VOLUMETEXTURE:
7380 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7381 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7382 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7383 This->stateBlock->textures[counter] = NULL;
7385 if (This->updateStateBlock != This->stateBlock ){
7386 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7387 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7388 This->updateStateBlock->textures[counter] = NULL;
7392 break;
7393 case WINED3DRTYPE_VOLUME:
7394 /* TODO: nothing really? */
7395 break;
7396 case WINED3DRTYPE_VERTEXBUFFER:
7397 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7399 int streamNumber;
7400 TRACE("Cleaning up stream pointers\n");
7402 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7403 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7404 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7406 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7407 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7408 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7409 This->updateStateBlock->streamSource[streamNumber] = 0;
7410 /* Set changed flag? */
7413 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) */
7414 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7415 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7416 This->stateBlock->streamSource[streamNumber] = 0;
7421 break;
7422 case WINED3DRTYPE_INDEXBUFFER:
7423 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7424 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7425 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7426 This->updateStateBlock->pIndexData = NULL;
7429 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7430 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7431 This->stateBlock->pIndexData = NULL;
7435 break;
7436 default:
7437 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7438 break;
7442 /* Remove the resource from the resourceStore */
7443 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7445 TRACE("Resource released\n");
7449 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7451 IWineD3DResourceImpl *resource, *cursor;
7452 HRESULT ret;
7453 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7455 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7456 TRACE("enumerating resource %p\n", resource);
7457 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7458 ret = pCallback((IWineD3DResource *) resource, pData);
7459 if(ret == S_FALSE) {
7460 TRACE("Canceling enumeration\n");
7461 break;
7464 return WINED3D_OK;
7467 /**********************************************************
7468 * IWineD3DDevice VTbl follows
7469 **********************************************************/
7471 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7473 /*** IUnknown methods ***/
7474 IWineD3DDeviceImpl_QueryInterface,
7475 IWineD3DDeviceImpl_AddRef,
7476 IWineD3DDeviceImpl_Release,
7477 /*** IWineD3DDevice methods ***/
7478 IWineD3DDeviceImpl_GetParent,
7479 /*** Creation methods**/
7480 IWineD3DDeviceImpl_CreateVertexBuffer,
7481 IWineD3DDeviceImpl_CreateIndexBuffer,
7482 IWineD3DDeviceImpl_CreateStateBlock,
7483 IWineD3DDeviceImpl_CreateSurface,
7484 IWineD3DDeviceImpl_CreateTexture,
7485 IWineD3DDeviceImpl_CreateVolumeTexture,
7486 IWineD3DDeviceImpl_CreateVolume,
7487 IWineD3DDeviceImpl_CreateCubeTexture,
7488 IWineD3DDeviceImpl_CreateQuery,
7489 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7490 IWineD3DDeviceImpl_CreateVertexDeclaration,
7491 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7492 IWineD3DDeviceImpl_CreateVertexShader,
7493 IWineD3DDeviceImpl_CreatePixelShader,
7494 IWineD3DDeviceImpl_CreatePalette,
7495 /*** Odd functions **/
7496 IWineD3DDeviceImpl_Init3D,
7497 IWineD3DDeviceImpl_InitGDI,
7498 IWineD3DDeviceImpl_Uninit3D,
7499 IWineD3DDeviceImpl_UninitGDI,
7500 IWineD3DDeviceImpl_SetMultithreaded,
7501 IWineD3DDeviceImpl_EvictManagedResources,
7502 IWineD3DDeviceImpl_GetAvailableTextureMem,
7503 IWineD3DDeviceImpl_GetBackBuffer,
7504 IWineD3DDeviceImpl_GetCreationParameters,
7505 IWineD3DDeviceImpl_GetDeviceCaps,
7506 IWineD3DDeviceImpl_GetDirect3D,
7507 IWineD3DDeviceImpl_GetDisplayMode,
7508 IWineD3DDeviceImpl_SetDisplayMode,
7509 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7510 IWineD3DDeviceImpl_GetRasterStatus,
7511 IWineD3DDeviceImpl_GetSwapChain,
7512 IWineD3DDeviceImpl_Reset,
7513 IWineD3DDeviceImpl_SetDialogBoxMode,
7514 IWineD3DDeviceImpl_SetCursorProperties,
7515 IWineD3DDeviceImpl_SetCursorPosition,
7516 IWineD3DDeviceImpl_ShowCursor,
7517 IWineD3DDeviceImpl_TestCooperativeLevel,
7518 /*** Getters and setters **/
7519 IWineD3DDeviceImpl_SetClipPlane,
7520 IWineD3DDeviceImpl_GetClipPlane,
7521 IWineD3DDeviceImpl_SetClipStatus,
7522 IWineD3DDeviceImpl_GetClipStatus,
7523 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7524 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7525 IWineD3DDeviceImpl_SetDepthStencilSurface,
7526 IWineD3DDeviceImpl_GetDepthStencilSurface,
7527 IWineD3DDeviceImpl_SetFVF,
7528 IWineD3DDeviceImpl_GetFVF,
7529 IWineD3DDeviceImpl_SetGammaRamp,
7530 IWineD3DDeviceImpl_GetGammaRamp,
7531 IWineD3DDeviceImpl_SetIndices,
7532 IWineD3DDeviceImpl_GetIndices,
7533 IWineD3DDeviceImpl_SetBaseVertexIndex,
7534 IWineD3DDeviceImpl_GetBaseVertexIndex,
7535 IWineD3DDeviceImpl_SetLight,
7536 IWineD3DDeviceImpl_GetLight,
7537 IWineD3DDeviceImpl_SetLightEnable,
7538 IWineD3DDeviceImpl_GetLightEnable,
7539 IWineD3DDeviceImpl_SetMaterial,
7540 IWineD3DDeviceImpl_GetMaterial,
7541 IWineD3DDeviceImpl_SetNPatchMode,
7542 IWineD3DDeviceImpl_GetNPatchMode,
7543 IWineD3DDeviceImpl_SetPaletteEntries,
7544 IWineD3DDeviceImpl_GetPaletteEntries,
7545 IWineD3DDeviceImpl_SetPixelShader,
7546 IWineD3DDeviceImpl_GetPixelShader,
7547 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7548 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7549 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7550 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7551 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7552 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7553 IWineD3DDeviceImpl_SetRenderState,
7554 IWineD3DDeviceImpl_GetRenderState,
7555 IWineD3DDeviceImpl_SetRenderTarget,
7556 IWineD3DDeviceImpl_GetRenderTarget,
7557 IWineD3DDeviceImpl_SetFrontBackBuffers,
7558 IWineD3DDeviceImpl_SetSamplerState,
7559 IWineD3DDeviceImpl_GetSamplerState,
7560 IWineD3DDeviceImpl_SetScissorRect,
7561 IWineD3DDeviceImpl_GetScissorRect,
7562 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7563 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7564 IWineD3DDeviceImpl_SetStreamSource,
7565 IWineD3DDeviceImpl_GetStreamSource,
7566 IWineD3DDeviceImpl_SetStreamSourceFreq,
7567 IWineD3DDeviceImpl_GetStreamSourceFreq,
7568 IWineD3DDeviceImpl_SetTexture,
7569 IWineD3DDeviceImpl_GetTexture,
7570 IWineD3DDeviceImpl_SetTextureStageState,
7571 IWineD3DDeviceImpl_GetTextureStageState,
7572 IWineD3DDeviceImpl_SetTransform,
7573 IWineD3DDeviceImpl_GetTransform,
7574 IWineD3DDeviceImpl_SetVertexDeclaration,
7575 IWineD3DDeviceImpl_GetVertexDeclaration,
7576 IWineD3DDeviceImpl_SetVertexShader,
7577 IWineD3DDeviceImpl_GetVertexShader,
7578 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7579 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7580 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7581 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7582 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7583 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7584 IWineD3DDeviceImpl_SetViewport,
7585 IWineD3DDeviceImpl_GetViewport,
7586 IWineD3DDeviceImpl_MultiplyTransform,
7587 IWineD3DDeviceImpl_ValidateDevice,
7588 IWineD3DDeviceImpl_ProcessVertices,
7589 /*** State block ***/
7590 IWineD3DDeviceImpl_BeginStateBlock,
7591 IWineD3DDeviceImpl_EndStateBlock,
7592 /*** Scene management ***/
7593 IWineD3DDeviceImpl_BeginScene,
7594 IWineD3DDeviceImpl_EndScene,
7595 IWineD3DDeviceImpl_Present,
7596 IWineD3DDeviceImpl_Clear,
7597 /*** Drawing ***/
7598 IWineD3DDeviceImpl_DrawPrimitive,
7599 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7600 IWineD3DDeviceImpl_DrawPrimitiveUP,
7601 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7602 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7603 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7604 IWineD3DDeviceImpl_DrawRectPatch,
7605 IWineD3DDeviceImpl_DrawTriPatch,
7606 IWineD3DDeviceImpl_DeletePatch,
7607 IWineD3DDeviceImpl_ColorFill,
7608 IWineD3DDeviceImpl_UpdateTexture,
7609 IWineD3DDeviceImpl_UpdateSurface,
7610 IWineD3DDeviceImpl_GetFrontBufferData,
7611 /*** object tracking ***/
7612 IWineD3DDeviceImpl_ResourceReleased,
7613 IWineD3DDeviceImpl_EnumResources
7616 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7618 /*** IUnknown methods ***/
7619 IWineD3DDeviceImpl_QueryInterface,
7620 IWineD3DDeviceImpl_AddRef,
7621 IWineD3DDeviceImpl_Release,
7622 /*** IWineD3DDevice methods ***/
7623 IWineD3DDeviceImpl_GetParent,
7624 /*** Creation methods**/
7625 IWineD3DDeviceImpl_CreateVertexBuffer,
7626 IWineD3DDeviceImpl_CreateIndexBuffer,
7627 IWineD3DDeviceImpl_CreateStateBlock,
7628 IWineD3DDeviceImpl_CreateSurface,
7629 IWineD3DDeviceImpl_CreateTexture,
7630 IWineD3DDeviceImpl_CreateVolumeTexture,
7631 IWineD3DDeviceImpl_CreateVolume,
7632 IWineD3DDeviceImpl_CreateCubeTexture,
7633 IWineD3DDeviceImpl_CreateQuery,
7634 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7635 IWineD3DDeviceImpl_CreateVertexDeclaration,
7636 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7637 IWineD3DDeviceImpl_CreateVertexShader,
7638 IWineD3DDeviceImpl_CreatePixelShader,
7639 IWineD3DDeviceImpl_CreatePalette,
7640 /*** Odd functions **/
7641 IWineD3DDeviceImpl_Init3D,
7642 IWineD3DDeviceImpl_InitGDI,
7643 IWineD3DDeviceImpl_Uninit3D,
7644 IWineD3DDeviceImpl_UninitGDI,
7645 IWineD3DDeviceImpl_SetMultithreaded,
7646 IWineD3DDeviceImpl_EvictManagedResources,
7647 IWineD3DDeviceImpl_GetAvailableTextureMem,
7648 IWineD3DDeviceImpl_GetBackBuffer,
7649 IWineD3DDeviceImpl_GetCreationParameters,
7650 IWineD3DDeviceImpl_GetDeviceCaps,
7651 IWineD3DDeviceImpl_GetDirect3D,
7652 IWineD3DDeviceImpl_GetDisplayMode,
7653 IWineD3DDeviceImpl_SetDisplayMode,
7654 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7655 IWineD3DDeviceImpl_GetRasterStatus,
7656 IWineD3DDeviceImpl_GetSwapChain,
7657 IWineD3DDeviceImpl_Reset,
7658 IWineD3DDeviceImpl_SetDialogBoxMode,
7659 IWineD3DDeviceImpl_SetCursorProperties,
7660 IWineD3DDeviceImpl_SetCursorPosition,
7661 IWineD3DDeviceImpl_ShowCursor,
7662 IWineD3DDeviceImpl_TestCooperativeLevel,
7663 /*** Getters and setters **/
7664 IWineD3DDeviceImpl_SetClipPlane,
7665 IWineD3DDeviceImpl_GetClipPlane,
7666 IWineD3DDeviceImpl_SetClipStatus,
7667 IWineD3DDeviceImpl_GetClipStatus,
7668 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7669 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7670 IWineD3DDeviceImpl_SetDepthStencilSurface,
7671 IWineD3DDeviceImpl_GetDepthStencilSurface,
7672 IWineD3DDeviceImpl_SetFVF,
7673 IWineD3DDeviceImpl_GetFVF,
7674 IWineD3DDeviceImpl_SetGammaRamp,
7675 IWineD3DDeviceImpl_GetGammaRamp,
7676 IWineD3DDeviceImpl_SetIndices,
7677 IWineD3DDeviceImpl_GetIndices,
7678 IWineD3DDeviceImpl_SetBaseVertexIndex,
7679 IWineD3DDeviceImpl_GetBaseVertexIndex,
7680 IWineD3DDeviceImpl_SetLight,
7681 IWineD3DDeviceImpl_GetLight,
7682 IWineD3DDeviceImpl_SetLightEnable,
7683 IWineD3DDeviceImpl_GetLightEnable,
7684 IWineD3DDeviceImpl_SetMaterial,
7685 IWineD3DDeviceImpl_GetMaterial,
7686 IWineD3DDeviceImpl_SetNPatchMode,
7687 IWineD3DDeviceImpl_GetNPatchMode,
7688 IWineD3DDeviceImpl_SetPaletteEntries,
7689 IWineD3DDeviceImpl_GetPaletteEntries,
7690 IWineD3DDeviceImpl_SetPixelShader,
7691 IWineD3DDeviceImpl_GetPixelShader,
7692 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7693 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7694 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7695 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7696 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7697 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7698 IWineD3DDeviceImpl_SetRenderState,
7699 IWineD3DDeviceImpl_GetRenderState,
7700 IWineD3DDeviceImpl_SetRenderTarget,
7701 IWineD3DDeviceImpl_GetRenderTarget,
7702 IWineD3DDeviceImpl_SetFrontBackBuffers,
7703 IWineD3DDeviceImpl_SetSamplerState,
7704 IWineD3DDeviceImpl_GetSamplerState,
7705 IWineD3DDeviceImpl_SetScissorRect,
7706 IWineD3DDeviceImpl_GetScissorRect,
7707 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7708 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7709 IWineD3DDeviceImpl_SetStreamSource,
7710 IWineD3DDeviceImpl_GetStreamSource,
7711 IWineD3DDeviceImpl_SetStreamSourceFreq,
7712 IWineD3DDeviceImpl_GetStreamSourceFreq,
7713 IWineD3DDeviceImpl_SetTexture,
7714 IWineD3DDeviceImpl_GetTexture,
7715 IWineD3DDeviceImpl_SetTextureStageState,
7716 IWineD3DDeviceImpl_GetTextureStageState,
7717 IWineD3DDeviceImpl_SetTransform,
7718 IWineD3DDeviceImpl_GetTransform,
7719 IWineD3DDeviceImpl_SetVertexDeclaration,
7720 IWineD3DDeviceImpl_GetVertexDeclaration,
7721 IWineD3DDeviceImpl_SetVertexShader,
7722 IWineD3DDeviceImpl_GetVertexShader,
7723 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7724 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7725 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7726 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7727 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7728 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7729 IWineD3DDeviceImpl_SetViewport,
7730 IWineD3DDeviceImpl_GetViewport,
7731 IWineD3DDeviceImpl_MultiplyTransform,
7732 IWineD3DDeviceImpl_ValidateDevice,
7733 IWineD3DDeviceImpl_ProcessVertices,
7734 /*** State block ***/
7735 IWineD3DDeviceImpl_BeginStateBlock,
7736 IWineD3DDeviceImpl_EndStateBlock,
7737 /*** Scene management ***/
7738 IWineD3DDeviceImpl_BeginScene,
7739 IWineD3DDeviceImpl_EndScene,
7740 IWineD3DDeviceImpl_Present,
7741 IWineD3DDeviceImpl_Clear,
7742 /*** Drawing ***/
7743 IWineD3DDeviceImpl_DrawPrimitive,
7744 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7745 IWineD3DDeviceImpl_DrawPrimitiveUP,
7746 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7747 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7748 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7749 IWineD3DDeviceImpl_DrawRectPatch,
7750 IWineD3DDeviceImpl_DrawTriPatch,
7751 IWineD3DDeviceImpl_DeletePatch,
7752 IWineD3DDeviceImpl_ColorFill,
7753 IWineD3DDeviceImpl_UpdateTexture,
7754 IWineD3DDeviceImpl_UpdateSurface,
7755 IWineD3DDeviceImpl_GetFrontBufferData,
7756 /*** object tracking ***/
7757 IWineD3DDeviceImpl_ResourceReleased,
7758 IWineD3DDeviceImpl_EnumResources
7761 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7762 WINED3DRS_ALPHABLENDENABLE ,
7763 WINED3DRS_ALPHAFUNC ,
7764 WINED3DRS_ALPHAREF ,
7765 WINED3DRS_ALPHATESTENABLE ,
7766 WINED3DRS_BLENDOP ,
7767 WINED3DRS_COLORWRITEENABLE ,
7768 WINED3DRS_DESTBLEND ,
7769 WINED3DRS_DITHERENABLE ,
7770 WINED3DRS_FILLMODE ,
7771 WINED3DRS_FOGDENSITY ,
7772 WINED3DRS_FOGEND ,
7773 WINED3DRS_FOGSTART ,
7774 WINED3DRS_LASTPIXEL ,
7775 WINED3DRS_SHADEMODE ,
7776 WINED3DRS_SRCBLEND ,
7777 WINED3DRS_STENCILENABLE ,
7778 WINED3DRS_STENCILFAIL ,
7779 WINED3DRS_STENCILFUNC ,
7780 WINED3DRS_STENCILMASK ,
7781 WINED3DRS_STENCILPASS ,
7782 WINED3DRS_STENCILREF ,
7783 WINED3DRS_STENCILWRITEMASK ,
7784 WINED3DRS_STENCILZFAIL ,
7785 WINED3DRS_TEXTUREFACTOR ,
7786 WINED3DRS_WRAP0 ,
7787 WINED3DRS_WRAP1 ,
7788 WINED3DRS_WRAP2 ,
7789 WINED3DRS_WRAP3 ,
7790 WINED3DRS_WRAP4 ,
7791 WINED3DRS_WRAP5 ,
7792 WINED3DRS_WRAP6 ,
7793 WINED3DRS_WRAP7 ,
7794 WINED3DRS_ZENABLE ,
7795 WINED3DRS_ZFUNC ,
7796 WINED3DRS_ZWRITEENABLE
7799 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7800 WINED3DTSS_ADDRESSW ,
7801 WINED3DTSS_ALPHAARG0 ,
7802 WINED3DTSS_ALPHAARG1 ,
7803 WINED3DTSS_ALPHAARG2 ,
7804 WINED3DTSS_ALPHAOP ,
7805 WINED3DTSS_BUMPENVLOFFSET ,
7806 WINED3DTSS_BUMPENVLSCALE ,
7807 WINED3DTSS_BUMPENVMAT00 ,
7808 WINED3DTSS_BUMPENVMAT01 ,
7809 WINED3DTSS_BUMPENVMAT10 ,
7810 WINED3DTSS_BUMPENVMAT11 ,
7811 WINED3DTSS_COLORARG0 ,
7812 WINED3DTSS_COLORARG1 ,
7813 WINED3DTSS_COLORARG2 ,
7814 WINED3DTSS_COLOROP ,
7815 WINED3DTSS_RESULTARG ,
7816 WINED3DTSS_TEXCOORDINDEX ,
7817 WINED3DTSS_TEXTURETRANSFORMFLAGS
7820 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7821 WINED3DSAMP_ADDRESSU ,
7822 WINED3DSAMP_ADDRESSV ,
7823 WINED3DSAMP_ADDRESSW ,
7824 WINED3DSAMP_BORDERCOLOR ,
7825 WINED3DSAMP_MAGFILTER ,
7826 WINED3DSAMP_MINFILTER ,
7827 WINED3DSAMP_MIPFILTER ,
7828 WINED3DSAMP_MIPMAPLODBIAS ,
7829 WINED3DSAMP_MAXMIPLEVEL ,
7830 WINED3DSAMP_MAXANISOTROPY ,
7831 WINED3DSAMP_SRGBTEXTURE ,
7832 WINED3DSAMP_ELEMENTINDEX
7835 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7836 WINED3DRS_AMBIENT ,
7837 WINED3DRS_AMBIENTMATERIALSOURCE ,
7838 WINED3DRS_CLIPPING ,
7839 WINED3DRS_CLIPPLANEENABLE ,
7840 WINED3DRS_COLORVERTEX ,
7841 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7842 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7843 WINED3DRS_FOGDENSITY ,
7844 WINED3DRS_FOGEND ,
7845 WINED3DRS_FOGSTART ,
7846 WINED3DRS_FOGTABLEMODE ,
7847 WINED3DRS_FOGVERTEXMODE ,
7848 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7849 WINED3DRS_LIGHTING ,
7850 WINED3DRS_LOCALVIEWER ,
7851 WINED3DRS_MULTISAMPLEANTIALIAS ,
7852 WINED3DRS_MULTISAMPLEMASK ,
7853 WINED3DRS_NORMALIZENORMALS ,
7854 WINED3DRS_PATCHEDGESTYLE ,
7855 WINED3DRS_POINTSCALE_A ,
7856 WINED3DRS_POINTSCALE_B ,
7857 WINED3DRS_POINTSCALE_C ,
7858 WINED3DRS_POINTSCALEENABLE ,
7859 WINED3DRS_POINTSIZE ,
7860 WINED3DRS_POINTSIZE_MAX ,
7861 WINED3DRS_POINTSIZE_MIN ,
7862 WINED3DRS_POINTSPRITEENABLE ,
7863 WINED3DRS_RANGEFOGENABLE ,
7864 WINED3DRS_SPECULARMATERIALSOURCE ,
7865 WINED3DRS_TWEENFACTOR ,
7866 WINED3DRS_VERTEXBLEND ,
7867 WINED3DRS_CULLMODE ,
7868 WINED3DRS_FOGCOLOR
7871 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7872 WINED3DTSS_TEXCOORDINDEX ,
7873 WINED3DTSS_TEXTURETRANSFORMFLAGS
7876 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7877 WINED3DSAMP_DMAPOFFSET
7880 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7881 DWORD rep = This->StateTable[state].representative;
7882 DWORD idx;
7883 BYTE shift;
7884 UINT i;
7885 WineD3DContext *context;
7887 if(!rep) return;
7888 for(i = 0; i < This->numContexts; i++) {
7889 context = This->contexts[i];
7890 if(isStateDirty(context, rep)) continue;
7892 context->dirtyArray[context->numDirtyEntries++] = rep;
7893 idx = rep >> 5;
7894 shift = rep & 0x1f;
7895 context->isStateDirty[idx] |= (1 << shift);
7899 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7900 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7901 /* The drawable size of a pbuffer render target is the current pbuffer size
7903 *width = dev->pbufferWidth;
7904 *height = dev->pbufferHeight;
7907 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7908 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7910 *width = This->pow2Width;
7911 *height = This->pow2Height;
7914 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7915 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7916 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7917 * current context's drawable, which is the size of the back buffer of the swapchain
7918 * the active context belongs to. The back buffer of the swapchain is stored as the
7919 * surface the context belongs to.
7921 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7922 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;