wined3d: Fix window rewrite regression.
[wine/wine-kai.git] / dlls / wined3d / device.c
blobd247d65761db1fa913cafe5143b36a1d962f9de0
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 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
99 *pp##type = NULL; \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 WineD3DAdapterChangeGLRam(This, _size); \
104 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
108 *pp##type = NULL; \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
139 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
140 if (IsEqualGUID(riid, &IID_IUnknown)
141 || IsEqualGUID(riid, &IID_IWineD3DBase)
142 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
143 IUnknown_AddRef(iface);
144 *ppobj = This;
145 return S_OK;
147 *ppobj = NULL;
148 return E_NOINTERFACE;
151 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 ULONG refCount = InterlockedIncrement(&This->ref);
155 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
156 return refCount;
159 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 ULONG refCount = InterlockedDecrement(&This->ref);
163 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
165 if (!refCount) {
166 /* TODO: Clean up all the surfaces and textures! */
167 /* NOTE: You must release the parent if the object was created via a callback
168 ** ***************************/
170 if (!list_empty(&This->resources)) {
171 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
172 dumpResources(&This->resources);
175 if(This->contexts) ERR("Context array not freed!\n");
176 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
177 This->haveHardwareCursor = FALSE;
179 IWineD3D_Release(This->wineD3D);
180 This->wineD3D = NULL;
181 HeapFree(GetProcessHeap(), 0, This);
182 TRACE("Freed device %p\n", This);
183 This = NULL;
185 return refCount;
188 /**********************************************************
189 * IWineD3DDevice implementation follows
190 **********************************************************/
191 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
193 *pParent = This->parent;
194 IUnknown_AddRef(This->parent);
195 return WINED3D_OK;
198 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
199 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
200 IUnknown *parent) {
201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
202 IWineD3DVertexBufferImpl *object;
203 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
204 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
205 BOOL conv;
207 if(Size == 0) {
208 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
209 *ppVertexBuffer = NULL;
210 return WINED3DERR_INVALIDCALL;
211 } else if(Pool == WINED3DPOOL_SCRATCH) {
212 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
213 * anyway, SCRATCH vertex buffers aren't usable anywhere
215 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
216 *ppVertexBuffer = NULL;
217 return WINED3DERR_INVALIDCALL;
220 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
222 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);
223 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
225 object->fvf = FVF;
227 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
228 * drawStridedFast (half-life 2).
230 * Basically converting the vertices in the buffer is quite expensive, and observations
231 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
232 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
234 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
235 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
236 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
237 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
238 * dx7 apps.
239 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
240 * more. In this call we can convert dx7 buffers too.
242 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
243 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
244 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
245 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
246 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
247 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
248 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
249 } else if(dxVersion <= 7 && conv) {
250 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
251 } else {
252 object->Flags |= VBFLAG_CREATEVBO;
254 return WINED3D_OK;
257 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
258 GLenum error, glUsage;
259 TRACE("Creating VBO for Index Buffer %p\n", object);
261 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
262 * restored on the next draw
264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
266 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
267 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
268 ENTER_GL();
270 while(glGetError());
272 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
273 error = glGetError();
274 if(error != GL_NO_ERROR || object->vbo == 0) {
275 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
276 goto out;
279 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
280 error = glGetError();
281 if(error != GL_NO_ERROR) {
282 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
283 goto out;
286 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
287 * copy no readback will be needed
289 glUsage = GL_STATIC_DRAW_ARB;
290 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
291 error = glGetError();
292 if(error != GL_NO_ERROR) {
293 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
294 goto out;
296 LEAVE_GL();
297 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
298 return;
300 out:
301 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
302 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
303 LEAVE_GL();
304 object->vbo = 0;
307 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
308 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
309 HANDLE *sharedHandle, IUnknown *parent) {
310 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
311 IWineD3DIndexBufferImpl *object;
312 TRACE("(%p) Creating index buffer\n", This);
314 /* Allocate the storage for the device */
315 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
317 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
318 CreateIndexBufferVBO(This, object);
321 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
322 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
323 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
325 return WINED3D_OK;
328 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
331 IWineD3DStateBlockImpl *object;
332 int i, j;
333 HRESULT temp_result;
335 D3DCREATEOBJECTINSTANCE(object, StateBlock)
336 object->blockType = Type;
338 for(i = 0; i < LIGHTMAP_SIZE; i++) {
339 list_init(&object->lightMap[i]);
342 /* Special case - Used during initialization to produce a placeholder stateblock
343 so other functions called can update a state block */
344 if (Type == WINED3DSBT_INIT) {
345 /* Don't bother increasing the reference count otherwise a device will never
346 be freed due to circular dependencies */
347 return WINED3D_OK;
350 temp_result = allocate_shader_constants(object);
351 if (WINED3D_OK != temp_result)
352 return temp_result;
354 /* Otherwise, might as well set the whole state block to the appropriate values */
355 if (This->stateBlock != NULL)
356 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
357 else
358 memset(object->streamFreq, 1, sizeof(object->streamFreq));
360 /* Reset the ref and type after kludging it */
361 object->wineD3DDevice = This;
362 object->ref = 1;
363 object->blockType = Type;
365 TRACE("Updating changed flags appropriate for type %d\n", Type);
367 if (Type == WINED3DSBT_ALL) {
369 TRACE("ALL => Pretend everything has changed\n");
370 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
372 /* Lights are not part of the changed / set structure */
373 for(j = 0; j < LIGHTMAP_SIZE; j++) {
374 struct list *e;
375 LIST_FOR_EACH(e, &object->lightMap[j]) {
376 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
377 light->changed = TRUE;
378 light->enabledChanged = TRUE;
381 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
382 object->contained_render_states[j - 1] = j;
384 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
385 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
386 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
387 object->contained_transform_states[j - 1] = j;
389 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
390 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
391 object->contained_vs_consts_f[j] = j;
393 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
394 for(j = 0; j < MAX_CONST_I; j++) {
395 object->contained_vs_consts_i[j] = j;
397 object->num_contained_vs_consts_i = MAX_CONST_I;
398 for(j = 0; j < MAX_CONST_B; j++) {
399 object->contained_vs_consts_b[j] = j;
401 object->num_contained_vs_consts_b = MAX_CONST_B;
402 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
403 object->contained_ps_consts_f[j] = j;
405 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
406 for(j = 0; j < MAX_CONST_I; j++) {
407 object->contained_ps_consts_i[j] = j;
409 object->num_contained_ps_consts_i = MAX_CONST_I;
410 for(j = 0; j < MAX_CONST_B; j++) {
411 object->contained_ps_consts_b[j] = j;
413 object->num_contained_ps_consts_b = MAX_CONST_B;
414 for(i = 0; i < MAX_TEXTURES; i++) {
415 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
416 object->contained_tss_states[object->num_contained_tss_states].stage = i;
417 object->contained_tss_states[object->num_contained_tss_states].state = j;
418 object->num_contained_tss_states++;
421 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
422 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
423 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
424 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
425 object->num_contained_sampler_states++;
429 for(i = 0; i < MAX_STREAMS; i++) {
430 if(object->streamSource[i]) {
431 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
434 if(object->pIndexData) {
435 IWineD3DIndexBuffer_AddRef(object->pIndexData);
437 if(object->vertexShader) {
438 IWineD3DVertexShader_AddRef(object->vertexShader);
440 if(object->pixelShader) {
441 IWineD3DPixelShader_AddRef(object->pixelShader);
444 } else if (Type == WINED3DSBT_PIXELSTATE) {
446 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
447 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
449 object->changed.pixelShader = TRUE;
451 /* Pixel Shader Constants */
452 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
453 object->contained_ps_consts_f[i] = i;
454 object->changed.pixelShaderConstantsF[i] = TRUE;
456 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
457 for (i = 0; i < MAX_CONST_B; ++i) {
458 object->contained_ps_consts_b[i] = i;
459 object->changed.pixelShaderConstantsB[i] = TRUE;
461 object->num_contained_ps_consts_b = MAX_CONST_B;
462 for (i = 0; i < MAX_CONST_I; ++i) {
463 object->contained_ps_consts_i[i] = i;
464 object->changed.pixelShaderConstantsI[i] = TRUE;
466 object->num_contained_ps_consts_i = MAX_CONST_I;
468 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
469 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
470 object->contained_render_states[i] = SavedPixelStates_R[i];
472 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
473 for (j = 0; j < MAX_TEXTURES; j++) {
474 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
475 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
476 object->contained_tss_states[object->num_contained_tss_states].stage = j;
477 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
478 object->num_contained_tss_states++;
481 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
482 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
483 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
484 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
485 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
486 object->num_contained_sampler_states++;
489 if(object->pixelShader) {
490 IWineD3DPixelShader_AddRef(object->pixelShader);
493 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
494 * on them. This makes releasing the buffer easier
496 for(i = 0; i < MAX_STREAMS; i++) {
497 object->streamSource[i] = NULL;
499 object->pIndexData = NULL;
500 object->vertexShader = NULL;
502 } else if (Type == WINED3DSBT_VERTEXSTATE) {
504 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
505 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
507 object->changed.vertexShader = TRUE;
509 /* Vertex Shader Constants */
510 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
511 object->changed.vertexShaderConstantsF[i] = TRUE;
512 object->contained_vs_consts_f[i] = i;
514 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
515 for (i = 0; i < MAX_CONST_B; ++i) {
516 object->changed.vertexShaderConstantsB[i] = TRUE;
517 object->contained_vs_consts_b[i] = i;
519 object->num_contained_vs_consts_b = MAX_CONST_B;
520 for (i = 0; i < MAX_CONST_I; ++i) {
521 object->changed.vertexShaderConstantsI[i] = TRUE;
522 object->contained_vs_consts_i[i] = i;
524 object->num_contained_vs_consts_i = MAX_CONST_I;
525 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
526 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
527 object->contained_render_states[i] = SavedVertexStates_R[i];
529 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
530 for (j = 0; j < MAX_TEXTURES; j++) {
531 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
532 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
533 object->contained_tss_states[object->num_contained_tss_states].stage = j;
534 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
535 object->num_contained_tss_states++;
538 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
539 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
540 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
541 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
542 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
543 object->num_contained_sampler_states++;
547 for(j = 0; j < LIGHTMAP_SIZE; j++) {
548 struct list *e;
549 LIST_FOR_EACH(e, &object->lightMap[j]) {
550 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
551 light->changed = TRUE;
552 light->enabledChanged = TRUE;
556 for(i = 0; i < MAX_STREAMS; i++) {
557 if(object->streamSource[i]) {
558 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
561 if(object->vertexShader) {
562 IWineD3DVertexShader_AddRef(object->vertexShader);
564 object->pIndexData = NULL;
565 object->pixelShader = NULL;
566 } else {
567 FIXME("Unrecognized state block type %d\n", Type);
570 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
571 return WINED3D_OK;
574 /* ************************************
575 MSDN:
576 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
578 Discard
579 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
581 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
583 ******************************** */
585 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) {
586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
587 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
588 unsigned int Size = 1;
589 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
590 TRACE("(%p) Create surface\n",This);
592 /** FIXME: Check ranges on the inputs are valid
593 * MSDN
594 * MultisampleQuality
595 * [in] Quality level. The valid range is between zero and one less than the level
596 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
597 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
598 * values of paired render targets, depth stencil surfaces, and the MultiSample type
599 * must all match.
600 *******************************/
604 * TODO: Discard MSDN
605 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
607 * If this flag is set, the contents of the depth stencil buffer will be
608 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
609 * with a different depth surface.
611 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
612 ***************************/
614 if(MultisampleQuality > 0) {
615 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
616 MultisampleQuality=0;
619 /** FIXME: Check that the format is supported
620 * by the device.
621 *******************************/
623 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
624 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
625 * space!
626 *********************************/
627 if (WINED3DFMT_UNKNOWN == Format) {
628 Size = 0;
629 } else if (Format == WINED3DFMT_DXT1) {
630 /* DXT1 is half byte per pixel */
631 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
633 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
634 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
635 Format == WINED3DFMT_ATI2N) {
636 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
637 } else {
638 /* The pitch is a multiple of 4 bytes */
639 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
640 Size *= Height;
643 /** Create and initialise the surface resource **/
644 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
645 /* "Standalone" surface */
646 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
648 object->currentDesc.Width = Width;
649 object->currentDesc.Height = Height;
650 object->currentDesc.MultiSampleType = MultiSample;
651 object->currentDesc.MultiSampleQuality = MultisampleQuality;
652 object->glDescription.level = Level;
653 list_init(&object->overlays);
655 /* Flags */
656 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
657 object->Flags |= Discard ? SFLAG_DISCARD : 0;
658 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
659 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
662 if (WINED3DFMT_UNKNOWN != Format) {
663 object->bytesPerPixel = tableEntry->bpp;
664 } else {
665 object->bytesPerPixel = 0;
668 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
670 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
672 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
673 * this function is too deep to need to care about things like this.
674 * Levels need to be checked too, and possibly Type since they all affect what can be done.
675 * ****************************************/
676 switch(Pool) {
677 case WINED3DPOOL_SCRATCH:
678 if(!Lockable)
679 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
680 "which are mutually exclusive, setting lockable to TRUE\n");
681 Lockable = TRUE;
682 break;
683 case WINED3DPOOL_SYSTEMMEM:
684 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
685 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
686 case WINED3DPOOL_MANAGED:
687 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
688 "Usage of DYNAMIC which are mutually exclusive, not doing "
689 "anything just telling you.\n");
690 break;
691 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
692 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
693 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
694 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
695 break;
696 default:
697 FIXME("(%p) Unknown pool %d\n", This, Pool);
698 break;
701 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
702 FIXME("Trying to create a render target that isn't in the default pool\n");
705 /* mark the texture as dirty so that it gets loaded first time around*/
706 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
707 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
708 This, Width, Height, Format, debug_d3dformat(Format),
709 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
711 /* Look at the implementation and set the correct Vtable */
712 switch(Impl) {
713 case SURFACE_OPENGL:
714 /* Check if a 3D adapter is available when creating gl surfaces */
715 if(!This->adapter) {
716 ERR("OpenGL surfaces are not available without opengl\n");
717 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
718 HeapFree(GetProcessHeap(), 0, object);
719 return WINED3DERR_NOTAVAILABLE;
721 break;
723 case SURFACE_GDI:
724 object->lpVtbl = &IWineGDISurface_Vtbl;
725 break;
727 default:
728 /* To be sure to catch this */
729 ERR("Unknown requested surface implementation %d!\n", Impl);
730 IWineD3DSurface_Release((IWineD3DSurface *) object);
731 return WINED3DERR_INVALIDCALL;
734 list_init(&object->renderbuffers);
736 /* Call the private setup routine */
737 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
741 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
742 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
743 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
744 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
747 IWineD3DTextureImpl *object;
748 unsigned int i;
749 UINT tmpW;
750 UINT tmpH;
751 HRESULT hr;
752 unsigned int pow2Width;
753 unsigned int pow2Height;
754 const GlPixelFormatDesc *glDesc;
755 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
757 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
758 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
759 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
761 /* TODO: It should only be possible to create textures for formats
762 that are reported as supported */
763 if (WINED3DFMT_UNKNOWN >= Format) {
764 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
765 return WINED3DERR_INVALIDCALL;
768 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
769 D3DINITIALIZEBASETEXTURE(object->baseTexture);
770 object->width = Width;
771 object->height = Height;
773 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
774 object->baseTexture.minMipLookup = &minMipLookup;
775 object->baseTexture.magLookup = &magLookup;
776 } else {
777 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
778 object->baseTexture.magLookup = &magLookup_noFilter;
781 /** Non-power2 support **/
782 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
783 pow2Width = Width;
784 pow2Height = Height;
785 } else {
786 /* Find the nearest pow2 match */
787 pow2Width = pow2Height = 1;
788 while (pow2Width < Width) pow2Width <<= 1;
789 while (pow2Height < Height) pow2Height <<= 1;
791 if(pow2Width != Width || pow2Height != Height) {
792 if(Levels > 1) {
793 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
794 HeapFree(GetProcessHeap(), 0, object);
795 *ppTexture = NULL;
796 return WINED3DERR_INVALIDCALL;
797 } else {
798 Levels = 1;
803 /** FIXME: add support for real non-power-two if it's provided by the video card **/
804 /* Precalculated scaling for 'faked' non power of two texture coords.
805 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
806 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
807 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
809 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
810 object->baseTexture.pow2Matrix[0] = 1.0;
811 object->baseTexture.pow2Matrix[5] = 1.0;
812 object->baseTexture.pow2Matrix[10] = 1.0;
813 object->baseTexture.pow2Matrix[15] = 1.0;
814 object->target = GL_TEXTURE_2D;
815 object->cond_np2 = TRUE;
816 pow2Width = Width;
817 pow2Height = Height;
818 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
819 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
820 (Width != pow2Width || Height != pow2Height) &&
821 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
823 object->baseTexture.pow2Matrix[0] = (float)Width;
824 object->baseTexture.pow2Matrix[5] = (float)Height;
825 object->baseTexture.pow2Matrix[10] = 1.0;
826 object->baseTexture.pow2Matrix[15] = 1.0;
827 object->target = GL_TEXTURE_RECTANGLE_ARB;
828 object->cond_np2 = TRUE;
829 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
830 } else {
831 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
832 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
833 object->baseTexture.pow2Matrix[10] = 1.0;
834 object->baseTexture.pow2Matrix[15] = 1.0;
835 object->target = GL_TEXTURE_2D;
836 object->cond_np2 = FALSE;
838 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
840 /* Calculate levels for mip mapping */
841 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
842 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
843 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
844 return WINED3DERR_INVALIDCALL;
846 if(Levels > 1) {
847 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
848 return WINED3DERR_INVALIDCALL;
850 object->baseTexture.levels = 1;
851 } else if (Levels == 0) {
852 TRACE("calculating levels %d\n", object->baseTexture.levels);
853 object->baseTexture.levels++;
854 tmpW = Width;
855 tmpH = Height;
856 while (tmpW > 1 || tmpH > 1) {
857 tmpW = max(1, tmpW >> 1);
858 tmpH = max(1, tmpH >> 1);
859 object->baseTexture.levels++;
861 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
864 /* Generate all the surfaces */
865 tmpW = Width;
866 tmpH = Height;
867 for (i = 0; i < object->baseTexture.levels; i++)
869 /* use the callback to create the texture surface */
870 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
871 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
872 FIXME("Failed to create surface %p\n", object);
873 /* clean up */
874 object->surfaces[i] = NULL;
875 IWineD3DTexture_Release((IWineD3DTexture *)object);
877 *ppTexture = NULL;
878 return hr;
881 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
882 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
883 /* calculate the next mipmap level */
884 tmpW = max(1, tmpW >> 1);
885 tmpH = max(1, tmpH >> 1);
887 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
889 TRACE("(%p) : Created texture %p\n", This, object);
890 return WINED3D_OK;
893 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
894 UINT Width, UINT Height, UINT Depth,
895 UINT Levels, DWORD Usage,
896 WINED3DFORMAT Format, WINED3DPOOL Pool,
897 IWineD3DVolumeTexture **ppVolumeTexture,
898 HANDLE *pSharedHandle, IUnknown *parent,
899 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
902 IWineD3DVolumeTextureImpl *object;
903 unsigned int i;
904 UINT tmpW;
905 UINT tmpH;
906 UINT tmpD;
907 const GlPixelFormatDesc *glDesc;
909 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
911 /* TODO: It should only be possible to create textures for formats
912 that are reported as supported */
913 if (WINED3DFMT_UNKNOWN >= Format) {
914 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
915 return WINED3DERR_INVALIDCALL;
917 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
918 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
919 return WINED3DERR_INVALIDCALL;
922 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
923 D3DINITIALIZEBASETEXTURE(object->baseTexture);
925 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
926 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
928 object->width = Width;
929 object->height = Height;
930 object->depth = Depth;
932 /* Is NP2 support for volumes needed? */
933 object->baseTexture.pow2Matrix[ 0] = 1.0;
934 object->baseTexture.pow2Matrix[ 5] = 1.0;
935 object->baseTexture.pow2Matrix[10] = 1.0;
936 object->baseTexture.pow2Matrix[15] = 1.0;
938 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
939 object->baseTexture.minMipLookup = &minMipLookup;
940 object->baseTexture.magLookup = &magLookup;
941 } else {
942 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
943 object->baseTexture.magLookup = &magLookup_noFilter;
946 /* Calculate levels for mip mapping */
947 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
948 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
949 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
950 return WINED3DERR_INVALIDCALL;
952 if(Levels > 1) {
953 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
954 return WINED3DERR_INVALIDCALL;
956 Levels = 1;
957 } else if (Levels == 0) {
958 object->baseTexture.levels++;
959 tmpW = Width;
960 tmpH = Height;
961 tmpD = Depth;
962 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
963 tmpW = max(1, tmpW >> 1);
964 tmpH = max(1, tmpH >> 1);
965 tmpD = max(1, tmpD >> 1);
966 object->baseTexture.levels++;
968 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
971 /* Generate all the surfaces */
972 tmpW = Width;
973 tmpH = Height;
974 tmpD = Depth;
976 for (i = 0; i < object->baseTexture.levels; i++)
978 HRESULT hr;
979 /* Create the volume */
980 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
981 &object->volumes[i], pSharedHandle);
983 if(FAILED(hr)) {
984 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
985 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
986 *ppVolumeTexture = NULL;
987 return hr;
990 /* Set its container to this object */
991 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
993 /* calculate the next mipmap level */
994 tmpW = max(1, tmpW >> 1);
995 tmpH = max(1, tmpH >> 1);
996 tmpD = max(1, tmpD >> 1);
998 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1000 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1001 TRACE("(%p) : Created volume texture %p\n", This, object);
1002 return WINED3D_OK;
1005 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1006 UINT Width, UINT Height, UINT Depth,
1007 DWORD Usage,
1008 WINED3DFORMAT Format, WINED3DPOOL Pool,
1009 IWineD3DVolume** ppVolume,
1010 HANDLE* pSharedHandle, IUnknown *parent) {
1012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1013 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1014 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1016 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1017 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1018 return WINED3DERR_INVALIDCALL;
1021 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1023 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1024 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1026 object->currentDesc.Width = Width;
1027 object->currentDesc.Height = Height;
1028 object->currentDesc.Depth = Depth;
1029 object->bytesPerPixel = formatDesc->bpp;
1031 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1032 object->lockable = TRUE;
1033 object->locked = FALSE;
1034 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1035 object->dirty = TRUE;
1037 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1040 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1041 UINT Levels, DWORD Usage,
1042 WINED3DFORMAT Format, WINED3DPOOL Pool,
1043 IWineD3DCubeTexture **ppCubeTexture,
1044 HANDLE *pSharedHandle, IUnknown *parent,
1045 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1048 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1049 unsigned int i, j;
1050 UINT tmpW;
1051 HRESULT hr;
1052 unsigned int pow2EdgeLength = EdgeLength;
1053 const GlPixelFormatDesc *glDesc;
1054 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1056 /* TODO: It should only be possible to create textures for formats
1057 that are reported as supported */
1058 if (WINED3DFMT_UNKNOWN >= Format) {
1059 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1060 return WINED3DERR_INVALIDCALL;
1063 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1064 WARN("(%p) : Tried to create not supported cube texture\n", This);
1065 return WINED3DERR_INVALIDCALL;
1068 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1069 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1071 TRACE("(%p) Create Cube Texture\n", This);
1073 /** Non-power2 support **/
1075 /* Find the nearest pow2 match */
1076 pow2EdgeLength = 1;
1077 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1079 object->edgeLength = EdgeLength;
1080 /* TODO: support for native non-power 2 */
1081 /* Precalculated scaling for 'faked' non power of two texture coords */
1082 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1083 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1084 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1085 object->baseTexture.pow2Matrix[15] = 1.0;
1087 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1088 object->baseTexture.minMipLookup = &minMipLookup;
1089 object->baseTexture.magLookup = &magLookup;
1090 } else {
1091 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
1092 object->baseTexture.magLookup = &magLookup_noFilter;
1095 /* Calculate levels for mip mapping */
1096 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1097 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1098 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1099 HeapFree(GetProcessHeap(), 0, object);
1100 *ppCubeTexture = NULL;
1102 return WINED3DERR_INVALIDCALL;
1104 if(Levels > 1) {
1105 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1106 HeapFree(GetProcessHeap(), 0, object);
1107 *ppCubeTexture = NULL;
1109 return WINED3DERR_INVALIDCALL;
1111 Levels = 1;
1112 } else if (Levels == 0) {
1113 object->baseTexture.levels++;
1114 tmpW = EdgeLength;
1115 while (tmpW > 1) {
1116 tmpW = max(1, tmpW >> 1);
1117 object->baseTexture.levels++;
1119 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1122 /* Generate all the surfaces */
1123 tmpW = EdgeLength;
1124 for (i = 0; i < object->baseTexture.levels; i++) {
1126 /* Create the 6 faces */
1127 for (j = 0; j < 6; j++) {
1129 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1130 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1132 if(hr!= WINED3D_OK) {
1133 /* clean up */
1134 int k;
1135 int l;
1136 for (l = 0; l < j; l++) {
1137 IWineD3DSurface_Release(object->surfaces[l][i]);
1139 for (k = 0; k < i; k++) {
1140 for (l = 0; l < 6; l++) {
1141 IWineD3DSurface_Release(object->surfaces[l][k]);
1145 FIXME("(%p) Failed to create surface\n",object);
1146 HeapFree(GetProcessHeap(),0,object);
1147 *ppCubeTexture = NULL;
1148 return hr;
1150 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1151 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1153 tmpW = max(1, tmpW >> 1);
1155 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1157 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1158 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1159 return WINED3D_OK;
1162 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1164 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1165 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1166 const IWineD3DQueryVtbl *vtable;
1168 /* Just a check to see if we support this type of query */
1169 switch(Type) {
1170 case WINED3DQUERYTYPE_OCCLUSION:
1171 TRACE("(%p) occlusion query\n", This);
1172 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1173 hr = WINED3D_OK;
1174 else
1175 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1177 vtable = &IWineD3DOcclusionQuery_Vtbl;
1178 break;
1180 case WINED3DQUERYTYPE_EVENT:
1181 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1182 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1183 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1185 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1187 vtable = &IWineD3DEventQuery_Vtbl;
1188 hr = WINED3D_OK;
1189 break;
1191 case WINED3DQUERYTYPE_VCACHE:
1192 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1193 case WINED3DQUERYTYPE_VERTEXSTATS:
1194 case WINED3DQUERYTYPE_TIMESTAMP:
1195 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1196 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1197 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1198 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1199 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1200 case WINED3DQUERYTYPE_PIXELTIMINGS:
1201 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1202 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1203 default:
1204 /* Use the base Query vtable until we have a special one for each query */
1205 vtable = &IWineD3DQuery_Vtbl;
1206 FIXME("(%p) Unhandled query type %d\n", This, Type);
1208 if(NULL == ppQuery || hr != WINED3D_OK) {
1209 return hr;
1212 D3DCREATEOBJECTINSTANCE(object, Query)
1213 object->lpVtbl = vtable;
1214 object->type = Type;
1215 object->state = QUERY_CREATED;
1216 /* allocated the 'extended' data based on the type of query requested */
1217 switch(Type){
1218 case WINED3DQUERYTYPE_OCCLUSION:
1219 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1220 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1222 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1223 TRACE("(%p) Allocating data for an occlusion query\n", This);
1224 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1225 break;
1227 case WINED3DQUERYTYPE_EVENT:
1228 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1229 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1231 if(GL_SUPPORT(APPLE_FENCE)) {
1232 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1233 checkGLcall("glGenFencesAPPLE");
1234 } else if(GL_SUPPORT(NV_FENCE)) {
1235 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1236 checkGLcall("glGenFencesNV");
1238 break;
1240 case WINED3DQUERYTYPE_VCACHE:
1241 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1242 case WINED3DQUERYTYPE_VERTEXSTATS:
1243 case WINED3DQUERYTYPE_TIMESTAMP:
1244 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1245 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1246 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1247 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1248 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1249 case WINED3DQUERYTYPE_PIXELTIMINGS:
1250 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1251 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1252 default:
1253 object->extendedData = 0;
1254 FIXME("(%p) Unhandled query type %d\n",This , Type);
1256 TRACE("(%p) : Created Query %p\n", This, object);
1257 return WINED3D_OK;
1260 /*****************************************************************************
1261 * IWineD3DDeviceImpl_SetupFullscreenWindow
1263 * Helper function that modifies a HWND's Style and ExStyle for proper
1264 * fullscreen use.
1266 * Params:
1267 * iface: Pointer to the IWineD3DDevice interface
1268 * window: Window to setup
1270 *****************************************************************************/
1271 static LONG fullscreen_style(LONG orig_style) {
1272 LONG style = orig_style;
1273 style &= ~WS_CAPTION;
1274 style &= ~WS_THICKFRAME;
1276 /* Make sure the window is managed, otherwise we won't get keyboard input */
1277 style |= WS_POPUP | WS_SYSMENU;
1279 return style;
1282 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1283 LONG exStyle = orig_exStyle;
1285 /* Filter out window decorations */
1286 exStyle &= ~WS_EX_WINDOWEDGE;
1287 exStyle &= ~WS_EX_CLIENTEDGE;
1289 return exStyle;
1292 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1295 LONG style, exStyle;
1296 /* Don't do anything if an original style is stored.
1297 * That shouldn't happen
1299 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1300 if (This->style || This->exStyle) {
1301 ERR("(%p): Want to change the window parameters of HWND %p, but "
1302 "another style is stored for restoration afterwards\n", This, window);
1305 /* Get the parameters and save them */
1306 style = GetWindowLongW(window, GWL_STYLE);
1307 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1308 This->style = style;
1309 This->exStyle = exStyle;
1311 style = fullscreen_style(style);
1312 exStyle = fullscreen_exStyle(exStyle);
1314 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1315 This->style, This->exStyle, style, exStyle);
1317 SetWindowLongW(window, GWL_STYLE, style);
1318 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1320 /* Inform the window about the update. */
1321 SetWindowPos(window, HWND_TOP, 0, 0,
1322 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1325 /*****************************************************************************
1326 * IWineD3DDeviceImpl_RestoreWindow
1328 * Helper function that restores a windows' properties when taking it out
1329 * of fullscreen mode
1331 * Params:
1332 * iface: Pointer to the IWineD3DDevice interface
1333 * window: Window to setup
1335 *****************************************************************************/
1336 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1338 LONG style, exStyle;
1340 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1341 * switch, do nothing
1343 if (!This->style && !This->exStyle) return;
1345 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1346 This, window, This->style, This->exStyle);
1348 style = GetWindowLongW(window, GWL_STYLE);
1349 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1351 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1352 * Some applications change it before calling Reset() when switching between windowed and
1353 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1355 if(style == fullscreen_style(This->style) &&
1356 exStyle == fullscreen_style(This->exStyle)) {
1357 SetWindowLongW(window, GWL_STYLE, This->style);
1358 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1361 /* Delete the old values */
1362 This->style = 0;
1363 This->exStyle = 0;
1365 /* Inform the window about the update */
1366 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1367 0, 0, 0, 0, /* Pos, Size, ignored */
1368 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1371 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1372 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1373 IUnknown* parent,
1374 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1375 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil,
1376 WINED3DSURFTYPE surface_type) {
1377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1379 HDC hDc;
1380 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1381 HRESULT hr = WINED3D_OK;
1382 IUnknown *bufferParent;
1383 BOOL displaymode_set = FALSE;
1384 WINED3DDISPLAYMODE Mode;
1385 const StaticPixelFormatDesc *formatDesc;
1387 TRACE("(%p) : Created Additional Swap Chain\n", This);
1389 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1390 * does a device hold a reference to a swap chain giving them a lifetime of the device
1391 * or does the swap chain notify the device of its destruction.
1392 *******************************/
1394 /* Check the params */
1395 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1396 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1397 return WINED3DERR_INVALIDCALL;
1398 } else if (pPresentationParameters->BackBufferCount > 1) {
1399 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");
1402 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1403 switch(surface_type) {
1404 case SURFACE_GDI:
1405 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1406 break;
1407 case SURFACE_OPENGL:
1408 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1409 break;
1410 case SURFACE_UNKNOWN:
1411 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1412 return WINED3DERR_INVALIDCALL;
1415 /*********************
1416 * Lookup the window Handle and the relating X window handle
1417 ********************/
1419 /* Setup hwnd we are using, plus which display this equates to */
1420 object->win_handle = pPresentationParameters->hDeviceWindow;
1421 if (!object->win_handle) {
1422 object->win_handle = This->createParms.hFocusWindow;
1424 if(!pPresentationParameters->Windowed && object->win_handle) {
1425 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1426 pPresentationParameters->BackBufferWidth,
1427 pPresentationParameters->BackBufferHeight);
1430 hDc = GetDC(object->win_handle);
1431 TRACE("Using hDc %p\n", hDc);
1433 if (NULL == hDc) {
1434 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1435 return WINED3DERR_NOTAVAILABLE;
1438 /* Get info on the current display setup */
1439 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1440 object->orig_width = Mode.Width;
1441 object->orig_height = Mode.Height;
1442 object->orig_fmt = Mode.Format;
1443 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1445 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1446 * then the corresponding dimension of the client area of the hDeviceWindow
1447 * (or the focus window, if hDeviceWindow is NULL) is taken.
1448 **********************/
1450 if (pPresentationParameters->Windowed &&
1451 ((pPresentationParameters->BackBufferWidth == 0) ||
1452 (pPresentationParameters->BackBufferHeight == 0) ||
1453 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1455 RECT Rect;
1456 GetClientRect(object->win_handle, &Rect);
1458 if (pPresentationParameters->BackBufferWidth == 0) {
1459 pPresentationParameters->BackBufferWidth = Rect.right;
1460 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1462 if (pPresentationParameters->BackBufferHeight == 0) {
1463 pPresentationParameters->BackBufferHeight = Rect.bottom;
1464 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1466 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1467 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1468 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1472 /* Put the correct figures in the presentation parameters */
1473 TRACE("Copying across presentation parameters\n");
1474 object->presentParms = *pPresentationParameters;
1476 TRACE("calling rendertarget CB\n");
1477 hr = D3DCB_CreateRenderTarget(This->parent,
1478 parent,
1479 object->presentParms.BackBufferWidth,
1480 object->presentParms.BackBufferHeight,
1481 object->presentParms.BackBufferFormat,
1482 object->presentParms.MultiSampleType,
1483 object->presentParms.MultiSampleQuality,
1484 TRUE /* Lockable */,
1485 &object->frontBuffer,
1486 NULL /* pShared (always null)*/);
1487 if (object->frontBuffer != NULL) {
1488 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1489 if(surface_type == SURFACE_OPENGL) {
1490 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1492 } else {
1493 ERR("Failed to create the front buffer\n");
1494 goto error;
1497 /*********************
1498 * Windowed / Fullscreen
1499 *******************/
1502 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1503 * so we should really check to see if there is a fullscreen swapchain already
1504 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1505 **************************************/
1507 if (!pPresentationParameters->Windowed) {
1508 WINED3DDISPLAYMODE mode;
1511 /* Change the display settings */
1512 mode.Width = pPresentationParameters->BackBufferWidth;
1513 mode.Height = pPresentationParameters->BackBufferHeight;
1514 mode.Format = pPresentationParameters->BackBufferFormat;
1515 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1517 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1518 displaymode_set = TRUE;
1522 * Create an opengl context for the display visual
1523 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1524 * use different properties after that point in time. FIXME: How to handle when requested format
1525 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1526 * it chooses is identical to the one already being used!
1527 **********************************/
1528 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1530 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1531 if(!object->context)
1532 return E_OUTOFMEMORY;
1533 object->num_contexts = 1;
1535 if(surface_type == SURFACE_OPENGL) {
1536 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1537 if (!object->context[0]) {
1538 ERR("Failed to create a new context\n");
1539 hr = WINED3DERR_NOTAVAILABLE;
1540 goto error;
1541 } else {
1542 TRACE("Context created (HWND=%p, glContext=%p)\n",
1543 object->win_handle, object->context[0]->glCtx);
1547 /*********************
1548 * Create the back, front and stencil buffers
1549 *******************/
1550 if(object->presentParms.BackBufferCount > 0) {
1551 int i;
1553 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1554 if(!object->backBuffer) {
1555 ERR("Out of memory\n");
1556 hr = E_OUTOFMEMORY;
1557 goto error;
1560 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1561 TRACE("calling rendertarget CB\n");
1562 hr = D3DCB_CreateRenderTarget(This->parent,
1563 parent,
1564 object->presentParms.BackBufferWidth,
1565 object->presentParms.BackBufferHeight,
1566 object->presentParms.BackBufferFormat,
1567 object->presentParms.MultiSampleType,
1568 object->presentParms.MultiSampleQuality,
1569 TRUE /* Lockable */,
1570 &object->backBuffer[i],
1571 NULL /* pShared (always null)*/);
1572 if(hr == WINED3D_OK && object->backBuffer[i]) {
1573 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1574 } else {
1575 ERR("Cannot create new back buffer\n");
1576 goto error;
1578 if(surface_type == SURFACE_OPENGL) {
1579 ENTER_GL();
1580 glDrawBuffer(GL_BACK);
1581 checkGLcall("glDrawBuffer(GL_BACK)");
1582 LEAVE_GL();
1585 } else {
1586 object->backBuffer = NULL;
1588 /* Single buffering - draw to front buffer */
1589 if(surface_type == SURFACE_OPENGL) {
1590 ENTER_GL();
1591 glDrawBuffer(GL_FRONT);
1592 checkGLcall("glDrawBuffer(GL_FRONT)");
1593 LEAVE_GL();
1597 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1598 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK && surface_type == SURFACE_OPENGL) {
1599 TRACE("Creating depth stencil buffer\n");
1600 if (This->auto_depth_stencil_buffer == NULL ) {
1601 hr = D3DCB_CreateDepthStencil(This->parent,
1602 parent,
1603 object->presentParms.BackBufferWidth,
1604 object->presentParms.BackBufferHeight,
1605 object->presentParms.AutoDepthStencilFormat,
1606 object->presentParms.MultiSampleType,
1607 object->presentParms.MultiSampleQuality,
1608 FALSE /* FIXME: Discard */,
1609 &This->auto_depth_stencil_buffer,
1610 NULL /* pShared (always null)*/ );
1611 if (This->auto_depth_stencil_buffer != NULL)
1612 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1615 /** TODO: A check on width, height and multisample types
1616 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1617 ****************************/
1618 object->wantsDepthStencilBuffer = TRUE;
1619 } else {
1620 object->wantsDepthStencilBuffer = FALSE;
1623 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1625 TRACE("Created swapchain %p\n", object);
1626 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1627 return WINED3D_OK;
1629 error:
1630 if (displaymode_set) {
1631 DEVMODEW devmode;
1632 RECT clip_rc;
1634 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1635 ClipCursor(NULL);
1637 /* Change the display settings */
1638 memset(&devmode, 0, sizeof(devmode));
1639 devmode.dmSize = sizeof(devmode);
1640 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1641 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1642 devmode.dmPelsWidth = object->orig_width;
1643 devmode.dmPelsHeight = object->orig_height;
1644 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1647 if (object->backBuffer) {
1648 int i;
1649 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1650 if(object->backBuffer[i]) {
1651 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1652 IUnknown_Release(bufferParent); /* once for the get parent */
1653 if (IUnknown_Release(bufferParent) > 0) {
1654 FIXME("(%p) Something's still holding the back buffer\n",This);
1658 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1659 object->backBuffer = NULL;
1661 if(object->context[0])
1662 DestroyContext(This, object->context[0]);
1663 if(object->frontBuffer) {
1664 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1665 IUnknown_Release(bufferParent); /* once for the get parent */
1666 if (IUnknown_Release(bufferParent) > 0) {
1667 FIXME("(%p) Something's still holding the front buffer\n",This);
1670 HeapFree(GetProcessHeap(), 0, object);
1671 return hr;
1674 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1675 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1677 TRACE("(%p)\n", This);
1679 return This->NumberOfSwapChains;
1682 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1684 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1686 if(iSwapChain < This->NumberOfSwapChains) {
1687 *pSwapChain = This->swapchains[iSwapChain];
1688 IWineD3DSwapChain_AddRef(*pSwapChain);
1689 TRACE("(%p) returning %p\n", This, *pSwapChain);
1690 return WINED3D_OK;
1691 } else {
1692 TRACE("Swapchain out of range\n");
1693 *pSwapChain = NULL;
1694 return WINED3DERR_INVALIDCALL;
1698 /*****
1699 * Vertex Declaration
1700 *****/
1701 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1702 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1704 IWineD3DVertexDeclarationImpl *object = NULL;
1705 HRESULT hr = WINED3D_OK;
1707 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1708 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1710 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1712 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1713 if(FAILED(hr)) {
1714 *ppVertexDeclaration = NULL;
1715 HeapFree(GetProcessHeap(), 0, object);
1718 return hr;
1721 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1722 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1724 unsigned int idx, idx2;
1725 unsigned int offset;
1726 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1727 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1728 BOOL has_blend_idx = has_blend &&
1729 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1730 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1731 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1732 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1733 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1734 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1735 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1737 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1738 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1740 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1741 WINED3DVERTEXELEMENT *elements = NULL;
1743 unsigned int size;
1744 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1745 if (has_blend_idx) num_blends--;
1747 /* Compute declaration size */
1748 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1749 has_psize + has_diffuse + has_specular + num_textures + 1;
1751 /* convert the declaration */
1752 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1753 if (!elements)
1754 return 0;
1756 elements[size-1] = end_element;
1757 idx = 0;
1758 if (has_pos) {
1759 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1760 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1761 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1763 else {
1764 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1765 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1767 elements[idx].UsageIndex = 0;
1768 idx++;
1770 if (has_blend && (num_blends > 0)) {
1771 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1772 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1773 else
1774 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1775 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1776 elements[idx].UsageIndex = 0;
1777 idx++;
1779 if (has_blend_idx) {
1780 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1781 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1782 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1783 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1784 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1785 else
1786 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1787 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1788 elements[idx].UsageIndex = 0;
1789 idx++;
1791 if (has_normal) {
1792 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1793 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1794 elements[idx].UsageIndex = 0;
1795 idx++;
1797 if (has_psize) {
1798 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1799 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1800 elements[idx].UsageIndex = 0;
1801 idx++;
1803 if (has_diffuse) {
1804 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1805 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1806 elements[idx].UsageIndex = 0;
1807 idx++;
1809 if (has_specular) {
1810 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1811 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1812 elements[idx].UsageIndex = 1;
1813 idx++;
1815 for (idx2 = 0; idx2 < num_textures; idx2++) {
1816 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1817 switch (numcoords) {
1818 case WINED3DFVF_TEXTUREFORMAT1:
1819 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1820 break;
1821 case WINED3DFVF_TEXTUREFORMAT2:
1822 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1823 break;
1824 case WINED3DFVF_TEXTUREFORMAT3:
1825 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1826 break;
1827 case WINED3DFVF_TEXTUREFORMAT4:
1828 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1829 break;
1831 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1832 elements[idx].UsageIndex = idx2;
1833 idx++;
1836 /* Now compute offsets, and initialize the rest of the fields */
1837 for (idx = 0, offset = 0; idx < size-1; idx++) {
1838 elements[idx].Stream = 0;
1839 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1840 elements[idx].Offset = offset;
1841 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1844 *ppVertexElements = elements;
1845 return size;
1848 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1849 WINED3DVERTEXELEMENT* elements = NULL;
1850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1851 unsigned int size;
1852 DWORD hr;
1854 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1855 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1857 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1858 HeapFree(GetProcessHeap(), 0, elements);
1859 if (hr != S_OK) return hr;
1861 return WINED3D_OK;
1864 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1866 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1867 HRESULT hr = WINED3D_OK;
1868 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1869 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1871 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1873 if (vertex_declaration) {
1874 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1877 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1879 if (WINED3D_OK != hr) {
1880 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1881 IWineD3DVertexShader_Release(*ppVertexShader);
1882 return WINED3DERR_INVALIDCALL;
1884 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1886 return WINED3D_OK;
1889 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1891 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1892 HRESULT hr = WINED3D_OK;
1894 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1895 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1896 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1897 if (WINED3D_OK == hr) {
1898 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1899 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1900 } else {
1901 WARN("(%p) : Failed to create pixel shader\n", This);
1904 return hr;
1907 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1909 IWineD3DPaletteImpl *object;
1910 HRESULT hr;
1911 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1913 /* Create the new object */
1914 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1915 if(!object) {
1916 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1917 return E_OUTOFMEMORY;
1920 object->lpVtbl = &IWineD3DPalette_Vtbl;
1921 object->ref = 1;
1922 object->Flags = Flags;
1923 object->parent = Parent;
1924 object->wineD3DDevice = This;
1925 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1927 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1929 if(!object->hpal) {
1930 HeapFree( GetProcessHeap(), 0, object);
1931 return E_OUTOFMEMORY;
1934 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1935 if(FAILED(hr)) {
1936 IWineD3DPalette_Release((IWineD3DPalette *) object);
1937 return hr;
1940 *Palette = (IWineD3DPalette *) object;
1942 return WINED3D_OK;
1945 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1946 HBITMAP hbm;
1947 BITMAP bm;
1948 HRESULT hr;
1949 HDC dcb = NULL, dcs = NULL;
1950 WINEDDCOLORKEY colorkey;
1952 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1953 if(hbm)
1955 GetObjectA(hbm, sizeof(BITMAP), &bm);
1956 dcb = CreateCompatibleDC(NULL);
1957 if(!dcb) goto out;
1958 SelectObject(dcb, hbm);
1960 else
1962 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1963 * couldn't be loaded
1965 memset(&bm, 0, sizeof(bm));
1966 bm.bmWidth = 32;
1967 bm.bmHeight = 32;
1970 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1971 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1972 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1973 if(FAILED(hr)) {
1974 ERR("Wine logo requested, but failed to create surface\n");
1975 goto out;
1978 if(dcb) {
1979 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1980 if(FAILED(hr)) goto out;
1981 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1982 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1984 colorkey.dwColorSpaceLowValue = 0;
1985 colorkey.dwColorSpaceHighValue = 0;
1986 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1987 } else {
1988 /* Fill the surface with a white color to show that wined3d is there */
1989 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1992 out:
1993 if(dcb) {
1994 DeleteDC(dcb);
1996 if(hbm) {
1997 DeleteObject(hbm);
1999 return;
2002 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2003 unsigned int i;
2004 /* Under DirectX you can have texture stage operations even if no texture is
2005 bound, whereas opengl will only do texture operations when a valid texture is
2006 bound. We emulate this by creating dummy textures and binding them to each
2007 texture stage, but disable all stages by default. Hence if a stage is enabled
2008 then the default texture will kick in until replaced by a SetTexture call */
2009 ENTER_GL();
2011 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2012 /* The dummy texture does not have client storage backing */
2013 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2014 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2016 for (i = 0; i < GL_LIMITS(textures); i++) {
2017 GLubyte white = 255;
2019 /* Make appropriate texture active */
2020 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2021 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2022 checkGLcall("glActiveTextureARB");
2023 } else if (i > 0) {
2024 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2027 /* Generate an opengl texture name */
2028 glGenTextures(1, &This->dummyTextureName[i]);
2029 checkGLcall("glGenTextures");
2030 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2032 /* Generate a dummy 2d texture (not using 1d because they cause many
2033 * DRI drivers fall back to sw) */
2034 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2035 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2036 checkGLcall("glBindTexture");
2038 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2039 checkGLcall("glTexImage2D");
2041 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2042 /* Reenable because if supported it is enabled by default */
2043 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2044 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2047 LEAVE_GL();
2050 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2052 IWineD3DSwapChainImpl *swapchain = NULL;
2053 HRESULT hr;
2054 DWORD state;
2055 unsigned int i;
2057 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2058 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2059 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2061 /* TODO: Test if OpenGL is compiled in and loaded */
2063 TRACE("(%p) : Creating stateblock\n", This);
2064 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2065 hr = IWineD3DDevice_CreateStateBlock(iface,
2066 WINED3DSBT_INIT,
2067 (IWineD3DStateBlock **)&This->stateBlock,
2068 NULL);
2069 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2070 WARN("Failed to create stateblock\n");
2071 goto err_out;
2073 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2074 This->updateStateBlock = This->stateBlock;
2075 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2077 hr = allocate_shader_constants(This->updateStateBlock);
2078 if (WINED3D_OK != hr) {
2079 goto err_out;
2082 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2083 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2085 This->NumberOfPalettes = 1;
2086 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2087 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2088 ERR("Out of memory!\n");
2089 goto err_out;
2091 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2092 if(!This->palettes[0]) {
2093 ERR("Out of memory!\n");
2094 goto err_out;
2096 for (i = 0; i < 256; ++i) {
2097 This->palettes[0][i].peRed = 0xFF;
2098 This->palettes[0][i].peGreen = 0xFF;
2099 This->palettes[0][i].peBlue = 0xFF;
2100 This->palettes[0][i].peFlags = 0xFF;
2102 This->currentPalette = 0;
2104 /* Initialize the texture unit mapping to a 1:1 mapping */
2105 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2106 if (state < GL_LIMITS(fragment_samplers)) {
2107 This->texUnitMap[state] = state;
2108 This->rev_tex_unit_map[state] = state;
2109 } else {
2110 This->texUnitMap[state] = -1;
2111 This->rev_tex_unit_map[state] = -1;
2115 /* Setup the implicit swapchain */
2116 TRACE("Creating implicit swapchain\n");
2117 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2118 if (FAILED(hr) || !swapchain) {
2119 WARN("Failed to create implicit swapchain\n");
2120 goto err_out;
2123 This->NumberOfSwapChains = 1;
2124 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2125 if(!This->swapchains) {
2126 ERR("Out of memory!\n");
2127 goto err_out;
2129 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2131 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2132 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2133 This->render_targets[0] = swapchain->backBuffer[0];
2134 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2136 else {
2137 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2138 This->render_targets[0] = swapchain->frontBuffer;
2139 This->lastActiveRenderTarget = swapchain->frontBuffer;
2141 IWineD3DSurface_AddRef(This->render_targets[0]);
2142 This->activeContext = swapchain->context[0];
2143 This->lastThread = GetCurrentThreadId();
2145 /* Depth Stencil support */
2146 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2147 if (NULL != This->stencilBufferTarget) {
2148 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2151 hr = This->shader_backend->shader_alloc_private(iface);
2152 if(FAILED(hr)) {
2153 TRACE("Shader private data couldn't be allocated\n");
2154 goto err_out;
2156 hr = This->frag_pipe->alloc_private(iface);
2157 if(FAILED(hr)) {
2158 TRACE("Fragment pipeline private data couldn't be allocated\n");
2159 goto err_out;
2161 hr = This->blitter->alloc_private(iface);
2162 if(FAILED(hr)) {
2163 TRACE("Blitter private data couldn't be allocated\n");
2164 goto err_out;
2167 /* Set up some starting GL setup */
2169 /* Setup all the devices defaults */
2170 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2171 create_dummy_textures(This);
2173 ENTER_GL();
2175 #if 0
2176 IWineD3DImpl_CheckGraphicsMemory();
2177 #endif
2179 { /* Set a default viewport */
2180 WINED3DVIEWPORT vp;
2181 vp.X = 0;
2182 vp.Y = 0;
2183 vp.Width = pPresentationParameters->BackBufferWidth;
2184 vp.Height = pPresentationParameters->BackBufferHeight;
2185 vp.MinZ = 0.0f;
2186 vp.MaxZ = 1.0f;
2187 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2190 /* Initialize the current view state */
2191 This->view_ident = 1;
2192 This->contexts[0]->last_was_rhw = 0;
2193 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2194 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2196 switch(wined3d_settings.offscreen_rendering_mode) {
2197 case ORM_FBO:
2198 case ORM_PBUFFER:
2199 This->offscreenBuffer = GL_BACK;
2200 break;
2202 case ORM_BACKBUFFER:
2204 if(This->activeContext->aux_buffers > 0) {
2205 TRACE("Using auxilliary buffer for offscreen rendering\n");
2206 This->offscreenBuffer = GL_AUX0;
2207 } else {
2208 TRACE("Using back buffer for offscreen rendering\n");
2209 This->offscreenBuffer = GL_BACK;
2214 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2215 LEAVE_GL();
2217 /* Clear the screen */
2218 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2219 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2220 0x00, 1.0, 0);
2222 This->d3d_initialized = TRUE;
2224 if(wined3d_settings.logo) {
2225 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2227 This->highest_dirty_ps_const = 0;
2228 This->highest_dirty_vs_const = 0;
2229 return WINED3D_OK;
2231 err_out:
2232 HeapFree(GetProcessHeap(), 0, This->render_targets);
2233 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2234 HeapFree(GetProcessHeap(), 0, This->swapchains);
2235 This->NumberOfSwapChains = 0;
2236 if(This->palettes) {
2237 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2238 HeapFree(GetProcessHeap(), 0, This->palettes);
2240 This->NumberOfPalettes = 0;
2241 if(swapchain) {
2242 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2244 if(This->stateBlock) {
2245 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2246 This->stateBlock = NULL;
2248 if (This->blit_priv) {
2249 This->blitter->free_private(iface);
2251 if (This->fragment_priv) {
2252 This->frag_pipe->free_private(iface);
2254 if (This->shader_priv) {
2255 This->shader_backend->shader_free_private(iface);
2257 return hr;
2260 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2262 IWineD3DSwapChainImpl *swapchain = NULL;
2263 HRESULT hr;
2265 /* Setup the implicit swapchain */
2266 TRACE("Creating implicit swapchain\n");
2267 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2268 if (FAILED(hr) || !swapchain) {
2269 WARN("Failed to create implicit swapchain\n");
2270 goto err_out;
2273 This->NumberOfSwapChains = 1;
2274 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2275 if(!This->swapchains) {
2276 ERR("Out of memory!\n");
2277 goto err_out;
2279 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2280 return WINED3D_OK;
2282 err_out:
2283 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2284 return hr;
2287 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2289 int sampler;
2290 UINT i;
2291 TRACE("(%p)\n", This);
2293 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2295 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2296 * it was created. Thus make sure a context is active for the glDelete* calls
2298 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2300 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2302 TRACE("Deleting high order patches\n");
2303 for(i = 0; i < PATCHMAP_SIZE; i++) {
2304 struct list *e1, *e2;
2305 struct WineD3DRectPatch *patch;
2306 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2307 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2308 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2312 /* Delete the palette conversion shader if it is around */
2313 if(This->paletteConversionShader) {
2314 ENTER_GL();
2315 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2316 LEAVE_GL();
2317 This->paletteConversionShader = 0;
2320 /* Delete the pbuffer context if there is any */
2321 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2323 /* Delete the mouse cursor texture */
2324 if(This->cursorTexture) {
2325 ENTER_GL();
2326 glDeleteTextures(1, &This->cursorTexture);
2327 LEAVE_GL();
2328 This->cursorTexture = 0;
2331 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2332 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2334 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2335 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2338 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2339 * private data, it might contain opengl pointers
2341 if(This->depth_blt_texture) {
2342 glDeleteTextures(1, &This->depth_blt_texture);
2343 This->depth_blt_texture = 0;
2345 if (This->depth_blt_rb) {
2346 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2347 This->depth_blt_rb = 0;
2348 This->depth_blt_rb_w = 0;
2349 This->depth_blt_rb_h = 0;
2352 /* Release the update stateblock */
2353 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2354 if(This->updateStateBlock != This->stateBlock)
2355 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2357 This->updateStateBlock = NULL;
2359 { /* because were not doing proper internal refcounts releasing the primary state block
2360 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2361 to set this->stateBlock = NULL; first */
2362 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2363 This->stateBlock = NULL;
2365 /* Release the stateblock */
2366 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2367 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2371 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2372 This->blitter->free_private(iface);
2373 This->frag_pipe->free_private(iface);
2374 This->shader_backend->shader_free_private(iface);
2376 /* Release the buffers (with sanity checks)*/
2377 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2378 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2379 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2380 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2382 This->stencilBufferTarget = NULL;
2384 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2385 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2386 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2388 TRACE("Setting rendertarget to NULL\n");
2389 This->render_targets[0] = NULL;
2391 if (This->auto_depth_stencil_buffer) {
2392 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2393 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2395 This->auto_depth_stencil_buffer = NULL;
2398 for(i=0; i < This->NumberOfSwapChains; i++) {
2399 TRACE("Releasing the implicit swapchain %d\n", i);
2400 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2401 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2405 HeapFree(GetProcessHeap(), 0, This->swapchains);
2406 This->swapchains = NULL;
2407 This->NumberOfSwapChains = 0;
2409 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2410 HeapFree(GetProcessHeap(), 0, This->palettes);
2411 This->palettes = NULL;
2412 This->NumberOfPalettes = 0;
2414 HeapFree(GetProcessHeap(), 0, This->render_targets);
2415 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2416 This->render_targets = NULL;
2417 This->draw_buffers = NULL;
2419 This->d3d_initialized = FALSE;
2420 return WINED3D_OK;
2423 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2425 unsigned int i;
2427 for(i=0; i < This->NumberOfSwapChains; i++) {
2428 TRACE("Releasing the implicit swapchain %d\n", i);
2429 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2430 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2434 HeapFree(GetProcessHeap(), 0, This->swapchains);
2435 This->swapchains = NULL;
2436 This->NumberOfSwapChains = 0;
2437 return WINED3D_OK;
2440 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2441 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2442 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2444 * There is no way to deactivate thread safety once it is enabled.
2446 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2449 /*For now just store the flag(needed in case of ddraw) */
2450 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2452 return;
2455 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2456 DEVMODEW devmode;
2457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2458 LONG ret;
2459 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2460 RECT clip_rc;
2462 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2464 /* Resize the screen even without a window:
2465 * The app could have unset it with SetCooperativeLevel, but not called
2466 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2467 * but we don't have any hwnd
2470 memset(&devmode, 0, sizeof(devmode));
2471 devmode.dmSize = sizeof(devmode);
2472 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2473 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2474 devmode.dmPelsWidth = pMode->Width;
2475 devmode.dmPelsHeight = pMode->Height;
2477 devmode.dmDisplayFrequency = pMode->RefreshRate;
2478 if (pMode->RefreshRate != 0) {
2479 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2482 /* Only change the mode if necessary */
2483 if( (This->ddraw_width == pMode->Width) &&
2484 (This->ddraw_height == pMode->Height) &&
2485 (This->ddraw_format == pMode->Format) &&
2486 (pMode->RefreshRate == 0) ) {
2487 return WINED3D_OK;
2490 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2491 if (ret != DISP_CHANGE_SUCCESSFUL) {
2492 if(devmode.dmDisplayFrequency != 0) {
2493 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2494 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2495 devmode.dmDisplayFrequency = 0;
2496 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2498 if(ret != DISP_CHANGE_SUCCESSFUL) {
2499 return WINED3DERR_NOTAVAILABLE;
2503 /* Store the new values */
2504 This->ddraw_width = pMode->Width;
2505 This->ddraw_height = pMode->Height;
2506 This->ddraw_format = pMode->Format;
2508 /* And finally clip mouse to our screen */
2509 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2510 ClipCursor(&clip_rc);
2512 return WINED3D_OK;
2515 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2517 *ppD3D= This->wineD3D;
2518 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2519 IWineD3D_AddRef(*ppD3D);
2520 return WINED3D_OK;
2523 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2526 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2527 (This->adapter->TextureRam/(1024*1024)),
2528 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2529 /* return simulated texture memory left */
2530 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2535 /*****
2536 * Get / Set FVF
2537 *****/
2538 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2541 /* Update the current state block */
2542 This->updateStateBlock->changed.fvf = TRUE;
2544 if(This->updateStateBlock->fvf == fvf) {
2545 TRACE("Application is setting the old fvf over, nothing to do\n");
2546 return WINED3D_OK;
2549 This->updateStateBlock->fvf = fvf;
2550 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2551 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2552 return WINED3D_OK;
2556 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2558 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2559 *pfvf = This->stateBlock->fvf;
2560 return WINED3D_OK;
2563 /*****
2564 * Get / Set Stream Source
2565 *****/
2566 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2568 IWineD3DVertexBuffer *oldSrc;
2570 if (StreamNumber >= MAX_STREAMS) {
2571 WARN("Stream out of range %d\n", StreamNumber);
2572 return WINED3DERR_INVALIDCALL;
2573 } else if(OffsetInBytes & 0x3) {
2574 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2575 return WINED3DERR_INVALIDCALL;
2578 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2579 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2581 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2583 if(oldSrc == pStreamData &&
2584 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2585 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2586 TRACE("Application is setting the old values over, nothing to do\n");
2587 return WINED3D_OK;
2590 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2591 if (pStreamData) {
2592 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2593 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2596 /* Handle recording of state blocks */
2597 if (This->isRecordingState) {
2598 TRACE("Recording... not performing anything\n");
2599 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2600 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2601 return WINED3D_OK;
2604 /* Need to do a getParent and pass the references up */
2605 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2606 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2607 so for now, just count internally */
2608 if (pStreamData != NULL) {
2609 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2610 InterlockedIncrement(&vbImpl->bindCount);
2611 IWineD3DVertexBuffer_AddRef(pStreamData);
2613 if (oldSrc != NULL) {
2614 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2615 IWineD3DVertexBuffer_Release(oldSrc);
2618 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2620 return WINED3D_OK;
2623 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2626 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2627 This->stateBlock->streamSource[StreamNumber],
2628 This->stateBlock->streamOffset[StreamNumber],
2629 This->stateBlock->streamStride[StreamNumber]);
2631 if (StreamNumber >= MAX_STREAMS) {
2632 WARN("Stream out of range %d\n", StreamNumber);
2633 return WINED3DERR_INVALIDCALL;
2635 *pStream = This->stateBlock->streamSource[StreamNumber];
2636 *pStride = This->stateBlock->streamStride[StreamNumber];
2637 if (pOffset) {
2638 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2641 if (*pStream != NULL) {
2642 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2644 return WINED3D_OK;
2647 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2649 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2650 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2652 /* Verify input at least in d3d9 this is invalid*/
2653 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2654 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2655 return WINED3DERR_INVALIDCALL;
2657 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2658 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2659 return WINED3DERR_INVALIDCALL;
2661 if( Divider == 0 ){
2662 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2663 return WINED3DERR_INVALIDCALL;
2666 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2667 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2669 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2670 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2672 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2673 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2674 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2677 return WINED3D_OK;
2680 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2683 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2684 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2686 TRACE("(%p) : returning %d\n", This, *Divider);
2688 return WINED3D_OK;
2691 /*****
2692 * Get / Set & Multiply Transform
2693 *****/
2694 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2695 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2697 /* Most of this routine, comments included copied from ddraw tree initially: */
2698 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2700 /* Handle recording of state blocks */
2701 if (This->isRecordingState) {
2702 TRACE("Recording... not performing anything\n");
2703 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2704 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2705 return WINED3D_OK;
2709 * If the new matrix is the same as the current one,
2710 * we cut off any further processing. this seems to be a reasonable
2711 * optimization because as was noticed, some apps (warcraft3 for example)
2712 * tend towards setting the same matrix repeatedly for some reason.
2714 * From here on we assume that the new matrix is different, wherever it matters.
2716 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2717 TRACE("The app is setting the same matrix over again\n");
2718 return WINED3D_OK;
2719 } else {
2720 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2724 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2725 where ViewMat = Camera space, WorldMat = world space.
2727 In OpenGL, camera and world space is combined into GL_MODELVIEW
2728 matrix. The Projection matrix stay projection matrix.
2731 /* Capture the times we can just ignore the change for now */
2732 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2733 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2734 /* Handled by the state manager */
2737 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2738 return WINED3D_OK;
2741 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2743 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2744 *pMatrix = This->stateBlock->transforms[State];
2745 return WINED3D_OK;
2748 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2749 WINED3DMATRIX *mat = NULL;
2750 WINED3DMATRIX temp;
2752 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2753 * below means it will be recorded in a state block change, but it
2754 * works regardless where it is recorded.
2755 * If this is found to be wrong, change to StateBlock.
2757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2758 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2760 if (State < HIGHEST_TRANSFORMSTATE)
2762 mat = &This->updateStateBlock->transforms[State];
2763 } else {
2764 FIXME("Unhandled transform state!!\n");
2767 multiply_matrix(&temp, mat, pMatrix);
2769 /* Apply change via set transform - will reapply to eg. lights this way */
2770 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2773 /*****
2774 * Get / Set Light
2775 *****/
2776 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2777 you can reference any indexes you want as long as that number max are enabled at any
2778 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2779 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2780 but when recording, just build a chain pretty much of commands to be replayed. */
2782 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2783 float rho;
2784 PLIGHTINFOEL *object = NULL;
2785 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2786 struct list *e;
2788 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2789 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2791 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2792 * the gl driver.
2794 if(!pLight) {
2795 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2796 return WINED3DERR_INVALIDCALL;
2799 switch(pLight->Type) {
2800 case WINED3DLIGHT_POINT:
2801 case WINED3DLIGHT_SPOT:
2802 case WINED3DLIGHT_PARALLELPOINT:
2803 case WINED3DLIGHT_GLSPOT:
2804 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2805 * most wanted
2807 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2808 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2809 return WINED3DERR_INVALIDCALL;
2811 break;
2813 case WINED3DLIGHT_DIRECTIONAL:
2814 /* Ignores attenuation */
2815 break;
2817 default:
2818 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2819 return WINED3DERR_INVALIDCALL;
2822 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2823 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2824 if(object->OriginalIndex == Index) break;
2825 object = NULL;
2828 if(!object) {
2829 TRACE("Adding new light\n");
2830 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2831 if(!object) {
2832 ERR("Out of memory error when allocating a light\n");
2833 return E_OUTOFMEMORY;
2835 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2836 object->glIndex = -1;
2837 object->OriginalIndex = Index;
2838 object->changed = TRUE;
2841 /* Initialize the object */
2842 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,
2843 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2844 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2845 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2846 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2847 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2848 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2850 /* Save away the information */
2851 object->OriginalParms = *pLight;
2853 switch (pLight->Type) {
2854 case WINED3DLIGHT_POINT:
2855 /* Position */
2856 object->lightPosn[0] = pLight->Position.x;
2857 object->lightPosn[1] = pLight->Position.y;
2858 object->lightPosn[2] = pLight->Position.z;
2859 object->lightPosn[3] = 1.0f;
2860 object->cutoff = 180.0f;
2861 /* FIXME: Range */
2862 break;
2864 case WINED3DLIGHT_DIRECTIONAL:
2865 /* Direction */
2866 object->lightPosn[0] = -pLight->Direction.x;
2867 object->lightPosn[1] = -pLight->Direction.y;
2868 object->lightPosn[2] = -pLight->Direction.z;
2869 object->lightPosn[3] = 0.0;
2870 object->exponent = 0.0f;
2871 object->cutoff = 180.0f;
2872 break;
2874 case WINED3DLIGHT_SPOT:
2875 /* Position */
2876 object->lightPosn[0] = pLight->Position.x;
2877 object->lightPosn[1] = pLight->Position.y;
2878 object->lightPosn[2] = pLight->Position.z;
2879 object->lightPosn[3] = 1.0;
2881 /* Direction */
2882 object->lightDirn[0] = pLight->Direction.x;
2883 object->lightDirn[1] = pLight->Direction.y;
2884 object->lightDirn[2] = pLight->Direction.z;
2885 object->lightDirn[3] = 1.0;
2888 * opengl-ish and d3d-ish spot lights use too different models for the
2889 * light "intensity" as a function of the angle towards the main light direction,
2890 * so we only can approximate very roughly.
2891 * however spot lights are rather rarely used in games (if ever used at all).
2892 * furthermore if still used, probably nobody pays attention to such details.
2894 if (pLight->Falloff == 0) {
2895 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2896 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2897 * will always be 1.0 for both of them, and we don't have to care for the
2898 * rest of the rather complex calculation
2900 object->exponent = 0;
2901 } else {
2902 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2903 if (rho < 0.0001) rho = 0.0001f;
2904 object->exponent = -0.3/log(cos(rho/2));
2906 if (object->exponent > 128.0) {
2907 object->exponent = 128.0;
2909 object->cutoff = pLight->Phi*90/M_PI;
2911 /* FIXME: Range */
2912 break;
2914 default:
2915 FIXME("Unrecognized light type %d\n", pLight->Type);
2918 /* Update the live definitions if the light is currently assigned a glIndex */
2919 if (object->glIndex != -1 && !This->isRecordingState) {
2920 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2922 return WINED3D_OK;
2925 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2926 PLIGHTINFOEL *lightInfo = NULL;
2927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2928 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2929 struct list *e;
2930 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2932 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2933 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2934 if(lightInfo->OriginalIndex == Index) break;
2935 lightInfo = NULL;
2938 if (lightInfo == NULL) {
2939 TRACE("Light information requested but light not defined\n");
2940 return WINED3DERR_INVALIDCALL;
2943 *pLight = lightInfo->OriginalParms;
2944 return WINED3D_OK;
2947 /*****
2948 * Get / Set Light Enable
2949 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2950 *****/
2951 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2952 PLIGHTINFOEL *lightInfo = NULL;
2953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2954 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2955 struct list *e;
2956 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2958 /* Tests show true = 128...not clear why */
2959 Enable = Enable? 128: 0;
2961 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2962 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2963 if(lightInfo->OriginalIndex == Index) break;
2964 lightInfo = NULL;
2966 TRACE("Found light: %p\n", lightInfo);
2968 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2969 if (lightInfo == NULL) {
2971 TRACE("Light enabled requested but light not defined, so defining one!\n");
2972 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2974 /* Search for it again! Should be fairly quick as near head of list */
2975 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2976 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2977 if(lightInfo->OriginalIndex == Index) break;
2978 lightInfo = NULL;
2980 if (lightInfo == NULL) {
2981 FIXME("Adding default lights has failed dismally\n");
2982 return WINED3DERR_INVALIDCALL;
2986 lightInfo->enabledChanged = TRUE;
2987 if(!Enable) {
2988 if(lightInfo->glIndex != -1) {
2989 if(!This->isRecordingState) {
2990 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2993 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2994 lightInfo->glIndex = -1;
2995 } else {
2996 TRACE("Light already disabled, nothing to do\n");
2998 lightInfo->enabled = FALSE;
2999 } else {
3000 lightInfo->enabled = TRUE;
3001 if (lightInfo->glIndex != -1) {
3002 /* nop */
3003 TRACE("Nothing to do as light was enabled\n");
3004 } else {
3005 int i;
3006 /* Find a free gl light */
3007 for(i = 0; i < This->maxConcurrentLights; i++) {
3008 if(This->stateBlock->activeLights[i] == NULL) {
3009 This->stateBlock->activeLights[i] = lightInfo;
3010 lightInfo->glIndex = i;
3011 break;
3014 if(lightInfo->glIndex == -1) {
3015 /* Our tests show that Windows returns D3D_OK in this situation, even with
3016 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3017 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3018 * as well for those lights.
3020 * TODO: Test how this affects rendering
3022 FIXME("Too many concurrently active lights\n");
3023 return WINED3D_OK;
3026 /* i == lightInfo->glIndex */
3027 if(!This->isRecordingState) {
3028 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3033 return WINED3D_OK;
3036 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3038 PLIGHTINFOEL *lightInfo = NULL;
3039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3040 struct list *e;
3041 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3042 TRACE("(%p) : for idx(%d)\n", This, Index);
3044 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3045 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3046 if(lightInfo->OriginalIndex == Index) break;
3047 lightInfo = NULL;
3050 if (lightInfo == NULL) {
3051 TRACE("Light enabled state requested but light not defined\n");
3052 return WINED3DERR_INVALIDCALL;
3054 /* true is 128 according to SetLightEnable */
3055 *pEnable = lightInfo->enabled ? 128 : 0;
3056 return WINED3D_OK;
3059 /*****
3060 * Get / Set Clip Planes
3061 *****/
3062 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3064 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3066 /* Validate Index */
3067 if (Index >= GL_LIMITS(clipplanes)) {
3068 TRACE("Application has requested clipplane this device doesn't support\n");
3069 return WINED3DERR_INVALIDCALL;
3072 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3074 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3075 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3076 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3077 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3078 TRACE("Application is setting old values over, nothing to do\n");
3079 return WINED3D_OK;
3082 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3083 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3084 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3085 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3087 /* Handle recording of state blocks */
3088 if (This->isRecordingState) {
3089 TRACE("Recording... not performing anything\n");
3090 return WINED3D_OK;
3093 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3095 return WINED3D_OK;
3098 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3100 TRACE("(%p) : for idx %d\n", This, Index);
3102 /* Validate Index */
3103 if (Index >= GL_LIMITS(clipplanes)) {
3104 TRACE("Application has requested clipplane this device doesn't support\n");
3105 return WINED3DERR_INVALIDCALL;
3108 pPlane[0] = This->stateBlock->clipplane[Index][0];
3109 pPlane[1] = This->stateBlock->clipplane[Index][1];
3110 pPlane[2] = This->stateBlock->clipplane[Index][2];
3111 pPlane[3] = This->stateBlock->clipplane[Index][3];
3112 return WINED3D_OK;
3115 /*****
3116 * Get / Set Clip Plane Status
3117 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3118 *****/
3119 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3121 FIXME("(%p) : stub\n", This);
3122 if (NULL == pClipStatus) {
3123 return WINED3DERR_INVALIDCALL;
3125 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3126 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3127 return WINED3D_OK;
3130 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3132 FIXME("(%p) : stub\n", This);
3133 if (NULL == pClipStatus) {
3134 return WINED3DERR_INVALIDCALL;
3136 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3137 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3138 return WINED3D_OK;
3141 /*****
3142 * Get / Set Material
3143 *****/
3144 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3147 if (!pMaterial) return WINED3DERR_INVALIDCALL;
3149 This->updateStateBlock->changed.material = TRUE;
3150 This->updateStateBlock->material = *pMaterial;
3152 /* Handle recording of state blocks */
3153 if (This->isRecordingState) {
3154 TRACE("Recording... not performing anything\n");
3155 return WINED3D_OK;
3158 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3159 return WINED3D_OK;
3162 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3164 *pMaterial = This->updateStateBlock->material;
3165 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3166 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3167 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3168 pMaterial->Ambient.b, pMaterial->Ambient.a);
3169 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3170 pMaterial->Specular.b, pMaterial->Specular.a);
3171 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3172 pMaterial->Emissive.b, pMaterial->Emissive.a);
3173 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3175 return WINED3D_OK;
3178 /*****
3179 * Get / Set Indices
3180 *****/
3181 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3183 IWineD3DIndexBuffer *oldIdxs;
3185 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3186 oldIdxs = This->updateStateBlock->pIndexData;
3188 This->updateStateBlock->changed.indices = TRUE;
3189 This->updateStateBlock->pIndexData = pIndexData;
3191 /* Handle recording of state blocks */
3192 if (This->isRecordingState) {
3193 TRACE("Recording... not performing anything\n");
3194 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3195 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3196 return WINED3D_OK;
3199 if(oldIdxs != pIndexData) {
3200 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3201 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3202 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3204 return WINED3D_OK;
3207 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3210 *ppIndexData = This->stateBlock->pIndexData;
3212 /* up ref count on ppindexdata */
3213 if (*ppIndexData) {
3214 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3215 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3216 }else{
3217 TRACE("(%p) No index data set\n", This);
3219 TRACE("Returning %p\n", *ppIndexData);
3221 return WINED3D_OK;
3224 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3225 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3227 TRACE("(%p)->(%d)\n", This, BaseIndex);
3229 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3230 TRACE("Application is setting the old value over, nothing to do\n");
3231 return WINED3D_OK;
3234 This->updateStateBlock->baseVertexIndex = BaseIndex;
3236 if (This->isRecordingState) {
3237 TRACE("Recording... not performing anything\n");
3238 return WINED3D_OK;
3240 /* The base vertex index affects the stream sources */
3241 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3242 return WINED3D_OK;
3245 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3247 TRACE("(%p) : base_index %p\n", This, base_index);
3249 *base_index = This->stateBlock->baseVertexIndex;
3251 TRACE("Returning %u\n", *base_index);
3253 return WINED3D_OK;
3256 /*****
3257 * Get / Set Viewports
3258 *****/
3259 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3262 TRACE("(%p)\n", This);
3263 This->updateStateBlock->changed.viewport = TRUE;
3264 This->updateStateBlock->viewport = *pViewport;
3266 /* Handle recording of state blocks */
3267 if (This->isRecordingState) {
3268 TRACE("Recording... not performing anything\n");
3269 return WINED3D_OK;
3272 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3273 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3275 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3276 return WINED3D_OK;
3280 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3282 TRACE("(%p)\n", This);
3283 *pViewport = This->stateBlock->viewport;
3284 return WINED3D_OK;
3287 /*****
3288 * Get / Set Render States
3289 * TODO: Verify against dx9 definitions
3290 *****/
3291 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3294 DWORD oldValue = This->stateBlock->renderState[State];
3296 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3298 This->updateStateBlock->changed.renderState[State] = TRUE;
3299 This->updateStateBlock->renderState[State] = Value;
3301 /* Handle recording of state blocks */
3302 if (This->isRecordingState) {
3303 TRACE("Recording... not performing anything\n");
3304 return WINED3D_OK;
3307 /* Compared here and not before the assignment to allow proper stateblock recording */
3308 if(Value == oldValue) {
3309 TRACE("Application is setting the old value over, nothing to do\n");
3310 } else {
3311 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3314 return WINED3D_OK;
3317 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3319 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3320 *pValue = This->stateBlock->renderState[State];
3321 return WINED3D_OK;
3324 /*****
3325 * Get / Set Sampler States
3326 * TODO: Verify against dx9 definitions
3327 *****/
3329 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3331 DWORD oldValue;
3333 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3334 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3336 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3337 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3340 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3341 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3342 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3345 * SetSampler is designed to allow for more than the standard up to 8 textures
3346 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3347 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3349 * http://developer.nvidia.com/object/General_FAQ.html#t6
3351 * There are two new settings for GForce
3352 * the sampler one:
3353 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3354 * and the texture one:
3355 * GL_MAX_TEXTURE_COORDS_ARB.
3356 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3357 ******************/
3359 oldValue = This->stateBlock->samplerState[Sampler][Type];
3360 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3361 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3363 /* Handle recording of state blocks */
3364 if (This->isRecordingState) {
3365 TRACE("Recording... not performing anything\n");
3366 return WINED3D_OK;
3369 if(oldValue == Value) {
3370 TRACE("Application is setting the old value over, nothing to do\n");
3371 return WINED3D_OK;
3374 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3376 return WINED3D_OK;
3379 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3382 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3383 This, Sampler, debug_d3dsamplerstate(Type), Type);
3385 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3386 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3389 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3390 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3391 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3393 *Value = This->stateBlock->samplerState[Sampler][Type];
3394 TRACE("(%p) : Returning %#x\n", This, *Value);
3396 return WINED3D_OK;
3399 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3402 This->updateStateBlock->changed.scissorRect = TRUE;
3403 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3404 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3405 return WINED3D_OK;
3407 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3409 if(This->isRecordingState) {
3410 TRACE("Recording... not performing anything\n");
3411 return WINED3D_OK;
3414 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3416 return WINED3D_OK;
3419 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3422 *pRect = This->updateStateBlock->scissorRect;
3423 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3424 return WINED3D_OK;
3427 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3429 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3431 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3433 This->updateStateBlock->vertexDecl = pDecl;
3434 This->updateStateBlock->changed.vertexDecl = TRUE;
3436 if (This->isRecordingState) {
3437 TRACE("Recording... not performing anything\n");
3438 return WINED3D_OK;
3439 } else if(pDecl == oldDecl) {
3440 /* Checked after the assignment to allow proper stateblock recording */
3441 TRACE("Application is setting the old declaration over, nothing to do\n");
3442 return WINED3D_OK;
3445 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3446 return WINED3D_OK;
3449 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3452 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3454 *ppDecl = This->stateBlock->vertexDecl;
3455 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3456 return WINED3D_OK;
3459 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3461 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3463 This->updateStateBlock->vertexShader = pShader;
3464 This->updateStateBlock->changed.vertexShader = TRUE;
3466 if (This->isRecordingState) {
3467 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3468 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3469 TRACE("Recording... not performing anything\n");
3470 return WINED3D_OK;
3471 } else if(oldShader == pShader) {
3472 /* Checked here to allow proper stateblock recording */
3473 TRACE("App is setting the old shader over, nothing to do\n");
3474 return WINED3D_OK;
3477 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3478 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3479 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3481 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3483 return WINED3D_OK;
3486 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3489 if (NULL == ppShader) {
3490 return WINED3DERR_INVALIDCALL;
3492 *ppShader = This->stateBlock->vertexShader;
3493 if( NULL != *ppShader)
3494 IWineD3DVertexShader_AddRef(*ppShader);
3496 TRACE("(%p) : returning %p\n", This, *ppShader);
3497 return WINED3D_OK;
3500 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3501 IWineD3DDevice *iface,
3502 UINT start,
3503 CONST BOOL *srcData,
3504 UINT count) {
3506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3507 int i, cnt = min(count, MAX_CONST_B - start);
3509 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3510 iface, srcData, start, count);
3512 if (srcData == NULL || cnt < 0)
3513 return WINED3DERR_INVALIDCALL;
3515 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3516 for (i = 0; i < cnt; i++)
3517 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3519 for (i = start; i < cnt + start; ++i) {
3520 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3523 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3525 return WINED3D_OK;
3528 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3529 IWineD3DDevice *iface,
3530 UINT start,
3531 BOOL *dstData,
3532 UINT count) {
3534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3535 int cnt = min(count, MAX_CONST_B - start);
3537 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3538 iface, dstData, start, count);
3540 if (dstData == NULL || cnt < 0)
3541 return WINED3DERR_INVALIDCALL;
3543 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3544 return WINED3D_OK;
3547 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3548 IWineD3DDevice *iface,
3549 UINT start,
3550 CONST int *srcData,
3551 UINT count) {
3553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3554 int i, cnt = min(count, MAX_CONST_I - start);
3556 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3557 iface, srcData, start, count);
3559 if (srcData == NULL || cnt < 0)
3560 return WINED3DERR_INVALIDCALL;
3562 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3563 for (i = 0; i < cnt; i++)
3564 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3565 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3567 for (i = start; i < cnt + start; ++i) {
3568 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3571 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3573 return WINED3D_OK;
3576 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3577 IWineD3DDevice *iface,
3578 UINT start,
3579 int *dstData,
3580 UINT count) {
3582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3583 int cnt = min(count, MAX_CONST_I - start);
3585 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3586 iface, dstData, start, count);
3588 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3589 return WINED3DERR_INVALIDCALL;
3591 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3592 return WINED3D_OK;
3595 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3596 IWineD3DDevice *iface,
3597 UINT start,
3598 CONST float *srcData,
3599 UINT count) {
3601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3602 int i;
3604 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3605 iface, srcData, start, count);
3607 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3608 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3609 return WINED3DERR_INVALIDCALL;
3611 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3612 if(TRACE_ON(d3d)) {
3613 for (i = 0; i < count; i++)
3614 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3615 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3618 for (i = start; i < count + start; ++i) {
3619 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3620 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3621 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3622 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3623 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3625 ptr->idx[ptr->count++] = i;
3626 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3630 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3632 return WINED3D_OK;
3635 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3636 IWineD3DDevice *iface,
3637 UINT start,
3638 CONST float *srcData,
3639 UINT count) {
3641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3642 int i;
3644 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3645 iface, srcData, start, count);
3647 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3648 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3649 return WINED3DERR_INVALIDCALL;
3651 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3652 if(TRACE_ON(d3d)) {
3653 for (i = 0; i < count; i++)
3654 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3655 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3658 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3659 * context. On a context switch the old context will be fully dirtified
3661 memset(This->activeContext->vshader_const_dirty + start, 1,
3662 sizeof(*This->activeContext->vshader_const_dirty) * count);
3663 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3665 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3667 return WINED3D_OK;
3670 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3671 IWineD3DDevice *iface,
3672 UINT start,
3673 float *dstData,
3674 UINT count) {
3676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3677 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3679 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3680 iface, dstData, start, count);
3682 if (dstData == NULL || cnt < 0)
3683 return WINED3DERR_INVALIDCALL;
3685 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3686 return WINED3D_OK;
3689 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3690 DWORD i;
3691 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3692 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3696 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3697 int i = This->rev_tex_unit_map[unit];
3698 int j = This->texUnitMap[stage];
3700 This->texUnitMap[stage] = unit;
3701 if (i != -1 && i != stage) {
3702 This->texUnitMap[i] = -1;
3705 This->rev_tex_unit_map[unit] = stage;
3706 if (j != -1 && j != unit) {
3707 This->rev_tex_unit_map[j] = -1;
3711 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3712 int i;
3714 for (i = 0; i < MAX_TEXTURES; ++i) {
3715 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3716 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3717 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3718 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3719 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3720 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3721 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3722 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3724 if (color_op == WINED3DTOP_DISABLE) {
3725 /* Not used, and disable higher stages */
3726 while (i < MAX_TEXTURES) {
3727 This->fixed_function_usage_map[i] = FALSE;
3728 ++i;
3730 break;
3733 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3734 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3735 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3736 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3737 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3738 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3739 This->fixed_function_usage_map[i] = TRUE;
3740 } else {
3741 This->fixed_function_usage_map[i] = FALSE;
3744 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3745 This->fixed_function_usage_map[i+1] = TRUE;
3750 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3751 int i, tex;
3753 device_update_fixed_function_usage_map(This);
3755 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3756 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3757 if (!This->fixed_function_usage_map[i]) continue;
3759 if (This->texUnitMap[i] != i) {
3760 device_map_stage(This, i, i);
3761 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3762 markTextureStagesDirty(This, i);
3765 return;
3768 /* Now work out the mapping */
3769 tex = 0;
3770 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3771 if (!This->fixed_function_usage_map[i]) continue;
3773 if (This->texUnitMap[i] != tex) {
3774 device_map_stage(This, i, tex);
3775 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3776 markTextureStagesDirty(This, i);
3779 ++tex;
3783 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3784 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3785 int i;
3787 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3788 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3789 device_map_stage(This, i, i);
3790 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3791 if (i < MAX_TEXTURES) {
3792 markTextureStagesDirty(This, i);
3798 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3799 int current_mapping = This->rev_tex_unit_map[unit];
3801 if (current_mapping == -1) {
3802 /* Not currently used */
3803 return TRUE;
3806 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3807 /* Used by a fragment sampler */
3809 if (!pshader_sampler_tokens) {
3810 /* No pixel shader, check fixed function */
3811 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3814 /* Pixel shader, check the shader's sampler map */
3815 return !pshader_sampler_tokens[current_mapping];
3818 /* Used by a vertex sampler */
3819 return !vshader_sampler_tokens[current_mapping];
3822 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3823 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3824 DWORD *pshader_sampler_tokens = NULL;
3825 int start = GL_LIMITS(combined_samplers) - 1;
3826 int i;
3828 if (ps) {
3829 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3831 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3832 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3833 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3836 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3837 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3838 if (vshader_sampler_tokens[i]) {
3839 if (This->texUnitMap[vsampler_idx] != -1) {
3840 /* Already mapped somewhere */
3841 continue;
3844 while (start >= 0) {
3845 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3846 device_map_stage(This, vsampler_idx, start);
3847 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3849 --start;
3850 break;
3853 --start;
3859 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3860 BOOL vs = use_vs(This);
3861 BOOL ps = use_ps(This);
3863 * Rules are:
3864 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3865 * that would be really messy and require shader recompilation
3866 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3867 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3869 if (ps) {
3870 device_map_psamplers(This);
3871 } else {
3872 device_map_fixed_function_samplers(This);
3875 if (vs) {
3876 device_map_vsamplers(This, ps);
3880 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3882 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3883 This->updateStateBlock->pixelShader = pShader;
3884 This->updateStateBlock->changed.pixelShader = TRUE;
3886 /* Handle recording of state blocks */
3887 if (This->isRecordingState) {
3888 TRACE("Recording... not performing anything\n");
3891 if (This->isRecordingState) {
3892 TRACE("Recording... not performing anything\n");
3893 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3894 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3895 return WINED3D_OK;
3898 if(pShader == oldShader) {
3899 TRACE("App is setting the old pixel shader over, nothing to do\n");
3900 return WINED3D_OK;
3903 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3904 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3906 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3907 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3909 return WINED3D_OK;
3912 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3915 if (NULL == ppShader) {
3916 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3917 return WINED3DERR_INVALIDCALL;
3920 *ppShader = This->stateBlock->pixelShader;
3921 if (NULL != *ppShader) {
3922 IWineD3DPixelShader_AddRef(*ppShader);
3924 TRACE("(%p) : returning %p\n", This, *ppShader);
3925 return WINED3D_OK;
3928 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3929 IWineD3DDevice *iface,
3930 UINT start,
3931 CONST BOOL *srcData,
3932 UINT count) {
3934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3935 int i, cnt = min(count, MAX_CONST_B - start);
3937 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3938 iface, srcData, start, count);
3940 if (srcData == NULL || cnt < 0)
3941 return WINED3DERR_INVALIDCALL;
3943 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3944 for (i = 0; i < cnt; i++)
3945 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3947 for (i = start; i < cnt + start; ++i) {
3948 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3951 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3953 return WINED3D_OK;
3956 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3957 IWineD3DDevice *iface,
3958 UINT start,
3959 BOOL *dstData,
3960 UINT count) {
3962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3963 int cnt = min(count, MAX_CONST_B - start);
3965 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3966 iface, dstData, start, count);
3968 if (dstData == NULL || cnt < 0)
3969 return WINED3DERR_INVALIDCALL;
3971 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3972 return WINED3D_OK;
3975 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3976 IWineD3DDevice *iface,
3977 UINT start,
3978 CONST int *srcData,
3979 UINT count) {
3981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3982 int i, cnt = min(count, MAX_CONST_I - start);
3984 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3985 iface, srcData, start, count);
3987 if (srcData == NULL || cnt < 0)
3988 return WINED3DERR_INVALIDCALL;
3990 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3991 for (i = 0; i < cnt; i++)
3992 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3993 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3995 for (i = start; i < cnt + start; ++i) {
3996 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3999 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4001 return WINED3D_OK;
4004 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4005 IWineD3DDevice *iface,
4006 UINT start,
4007 int *dstData,
4008 UINT count) {
4010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4011 int cnt = min(count, MAX_CONST_I - start);
4013 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4014 iface, dstData, start, count);
4016 if (dstData == NULL || cnt < 0)
4017 return WINED3DERR_INVALIDCALL;
4019 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4020 return WINED3D_OK;
4023 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4024 IWineD3DDevice *iface,
4025 UINT start,
4026 CONST float *srcData,
4027 UINT count) {
4029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4030 int i;
4032 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4033 iface, srcData, start, count);
4035 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4036 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4037 return WINED3DERR_INVALIDCALL;
4039 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4040 if(TRACE_ON(d3d)) {
4041 for (i = 0; i < count; i++)
4042 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4043 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4046 for (i = start; i < count + start; ++i) {
4047 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
4048 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
4049 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
4050 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
4051 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
4053 ptr->idx[ptr->count++] = i;
4054 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4058 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4060 return WINED3D_OK;
4063 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4064 IWineD3DDevice *iface,
4065 UINT start,
4066 CONST float *srcData,
4067 UINT count) {
4069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4070 int i;
4072 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4073 iface, srcData, start, count);
4075 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4076 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4077 return WINED3DERR_INVALIDCALL;
4079 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4080 if(TRACE_ON(d3d)) {
4081 for (i = 0; i < count; i++)
4082 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4083 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4086 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4087 * context. On a context switch the old context will be fully dirtified
4089 memset(This->activeContext->pshader_const_dirty + start, 1,
4090 sizeof(*This->activeContext->pshader_const_dirty) * count);
4091 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4093 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4095 return WINED3D_OK;
4098 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4099 IWineD3DDevice *iface,
4100 UINT start,
4101 float *dstData,
4102 UINT count) {
4104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4105 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4107 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4108 iface, dstData, start, count);
4110 if (dstData == NULL || cnt < 0)
4111 return WINED3DERR_INVALIDCALL;
4113 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4114 return WINED3D_OK;
4117 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4118 static HRESULT
4119 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4120 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4121 unsigned int i;
4122 DWORD DestFVF = dest->fvf;
4123 WINED3DVIEWPORT vp;
4124 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4125 BOOL doClip;
4126 int numTextures;
4128 if (lpStrideData->u.s.normal.lpData) {
4129 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4132 if (lpStrideData->u.s.position.lpData == NULL) {
4133 ERR("Source has no position mask\n");
4134 return WINED3DERR_INVALIDCALL;
4137 /* We might access VBOs from this code, so hold the lock */
4138 ENTER_GL();
4140 if (dest->resource.allocatedMemory == NULL) {
4141 /* This may happen if we do direct locking into a vbo. Unlikely,
4142 * but theoretically possible(ddraw processvertices test)
4144 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4145 if(!dest->resource.allocatedMemory) {
4146 LEAVE_GL();
4147 ERR("Out of memory\n");
4148 return E_OUTOFMEMORY;
4150 if(dest->vbo) {
4151 void *src;
4152 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4153 checkGLcall("glBindBufferARB");
4154 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4155 if(src) {
4156 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4158 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4159 checkGLcall("glUnmapBufferARB");
4163 /* Get a pointer into the destination vbo(create one if none exists) and
4164 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4166 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4167 dest->Flags |= VBFLAG_CREATEVBO;
4168 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4171 if(dest->vbo) {
4172 unsigned char extrabytes = 0;
4173 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4174 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4175 * this may write 4 extra bytes beyond the area that should be written
4177 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4178 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4179 if(!dest_conv_addr) {
4180 ERR("Out of memory\n");
4181 /* Continue without storing converted vertices */
4183 dest_conv = dest_conv_addr;
4186 /* Should I clip?
4187 * a) WINED3DRS_CLIPPING is enabled
4188 * b) WINED3DVOP_CLIP is passed
4190 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4191 static BOOL warned = FALSE;
4193 * The clipping code is not quite correct. Some things need
4194 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4195 * so disable clipping for now.
4196 * (The graphics in Half-Life are broken, and my processvertices
4197 * test crashes with IDirect3DDevice3)
4198 doClip = TRUE;
4200 doClip = FALSE;
4201 if(!warned) {
4202 warned = TRUE;
4203 FIXME("Clipping is broken and disabled for now\n");
4205 } else doClip = FALSE;
4206 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4208 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4209 WINED3DTS_VIEW,
4210 &view_mat);
4211 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4212 WINED3DTS_PROJECTION,
4213 &proj_mat);
4214 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4215 WINED3DTS_WORLDMATRIX(0),
4216 &world_mat);
4218 TRACE("View mat:\n");
4219 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);
4220 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);
4221 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);
4222 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);
4224 TRACE("Proj mat:\n");
4225 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);
4226 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);
4227 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);
4228 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);
4230 TRACE("World mat:\n");
4231 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);
4232 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);
4233 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);
4234 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);
4236 /* Get the viewport */
4237 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4238 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4239 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4241 multiply_matrix(&mat,&view_mat,&world_mat);
4242 multiply_matrix(&mat,&proj_mat,&mat);
4244 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4246 for (i = 0; i < dwCount; i+= 1) {
4247 unsigned int tex_index;
4249 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4250 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4251 /* The position first */
4252 float *p =
4253 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4254 float x, y, z, rhw;
4255 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4257 /* Multiplication with world, view and projection matrix */
4258 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);
4259 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);
4260 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);
4261 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);
4263 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4265 /* WARNING: The following things are taken from d3d7 and were not yet checked
4266 * against d3d8 or d3d9!
4269 /* Clipping conditions: From msdn
4271 * A vertex is clipped if it does not match the following requirements
4272 * -rhw < x <= rhw
4273 * -rhw < y <= rhw
4274 * 0 < z <= rhw
4275 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4277 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4278 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4282 if( !doClip ||
4283 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4284 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4285 ( rhw > eps ) ) ) {
4287 /* "Normal" viewport transformation (not clipped)
4288 * 1) The values are divided by rhw
4289 * 2) The y axis is negative, so multiply it with -1
4290 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4291 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4292 * 4) Multiply x with Width/2 and add Width/2
4293 * 5) The same for the height
4294 * 6) Add the viewpoint X and Y to the 2D coordinates and
4295 * The minimum Z value to z
4296 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4298 * Well, basically it's simply a linear transformation into viewport
4299 * coordinates
4302 x /= rhw;
4303 y /= rhw;
4304 z /= rhw;
4306 y *= -1;
4308 x *= vp.Width / 2;
4309 y *= vp.Height / 2;
4310 z *= vp.MaxZ - vp.MinZ;
4312 x += vp.Width / 2 + vp.X;
4313 y += vp.Height / 2 + vp.Y;
4314 z += vp.MinZ;
4316 rhw = 1 / rhw;
4317 } else {
4318 /* That vertex got clipped
4319 * Contrary to OpenGL it is not dropped completely, it just
4320 * undergoes a different calculation.
4322 TRACE("Vertex got clipped\n");
4323 x += rhw;
4324 y += rhw;
4326 x /= 2;
4327 y /= 2;
4329 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4330 * outside of the main vertex buffer memory. That needs some more
4331 * investigation...
4335 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4338 ( (float *) dest_ptr)[0] = x;
4339 ( (float *) dest_ptr)[1] = y;
4340 ( (float *) dest_ptr)[2] = z;
4341 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4343 dest_ptr += 3 * sizeof(float);
4345 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4346 dest_ptr += sizeof(float);
4349 if(dest_conv) {
4350 float w = 1 / rhw;
4351 ( (float *) dest_conv)[0] = x * w;
4352 ( (float *) dest_conv)[1] = y * w;
4353 ( (float *) dest_conv)[2] = z * w;
4354 ( (float *) dest_conv)[3] = w;
4356 dest_conv += 3 * sizeof(float);
4358 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4359 dest_conv += sizeof(float);
4363 if (DestFVF & WINED3DFVF_PSIZE) {
4364 dest_ptr += sizeof(DWORD);
4365 if(dest_conv) dest_conv += sizeof(DWORD);
4367 if (DestFVF & WINED3DFVF_NORMAL) {
4368 float *normal =
4369 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4370 /* AFAIK this should go into the lighting information */
4371 FIXME("Didn't expect the destination to have a normal\n");
4372 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4373 if(dest_conv) {
4374 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4378 if (DestFVF & WINED3DFVF_DIFFUSE) {
4379 DWORD *color_d =
4380 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4381 if(!color_d) {
4382 static BOOL warned = FALSE;
4384 if(!warned) {
4385 ERR("No diffuse color in source, but destination has one\n");
4386 warned = TRUE;
4389 *( (DWORD *) dest_ptr) = 0xffffffff;
4390 dest_ptr += sizeof(DWORD);
4392 if(dest_conv) {
4393 *( (DWORD *) dest_conv) = 0xffffffff;
4394 dest_conv += sizeof(DWORD);
4397 else {
4398 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4399 if(dest_conv) {
4400 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4401 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4402 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4403 dest_conv += sizeof(DWORD);
4408 if (DestFVF & WINED3DFVF_SPECULAR) {
4409 /* What's the color value in the feedback buffer? */
4410 DWORD *color_s =
4411 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4412 if(!color_s) {
4413 static BOOL warned = FALSE;
4415 if(!warned) {
4416 ERR("No specular color in source, but destination has one\n");
4417 warned = TRUE;
4420 *( (DWORD *) dest_ptr) = 0xFF000000;
4421 dest_ptr += sizeof(DWORD);
4423 if(dest_conv) {
4424 *( (DWORD *) dest_conv) = 0xFF000000;
4425 dest_conv += sizeof(DWORD);
4428 else {
4429 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4430 if(dest_conv) {
4431 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4432 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4433 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4434 dest_conv += sizeof(DWORD);
4439 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4440 float *tex_coord =
4441 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4442 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4443 if(!tex_coord) {
4444 ERR("No source texture, but destination requests one\n");
4445 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4446 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4448 else {
4449 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4450 if(dest_conv) {
4451 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4457 if(dest_conv) {
4458 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4459 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4460 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4461 dwCount * get_flexible_vertex_size(DestFVF),
4462 dest_conv_addr));
4463 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4464 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4467 LEAVE_GL();
4469 return WINED3D_OK;
4471 #undef copy_and_next
4473 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4475 WineDirect3DVertexStridedData strided;
4476 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4477 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4479 if(pVertexDecl) {
4480 ERR("Output vertex declaration not implemented yet\n");
4483 /* Need any context to write to the vbo. */
4484 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4486 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4487 * control the streamIsUP flag, thus restore it afterwards.
4489 This->stateBlock->streamIsUP = FALSE;
4490 memset(&strided, 0, sizeof(strided));
4491 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4492 This->stateBlock->streamIsUP = streamWasUP;
4494 if(vbo || SrcStartIndex) {
4495 unsigned int i;
4496 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4497 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4499 * Also get the start index in, but only loop over all elements if there's something to add at all.
4501 #define FIXSRC(type) \
4502 if(strided.u.s.type.VBO) { \
4503 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4504 strided.u.s.type.VBO = 0; \
4505 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4506 ENTER_GL(); \
4507 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4508 vb->vbo = 0; \
4509 LEAVE_GL(); \
4511 if(strided.u.s.type.lpData) { \
4512 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4514 FIXSRC(position);
4515 FIXSRC(blendWeights);
4516 FIXSRC(blendMatrixIndices);
4517 FIXSRC(normal);
4518 FIXSRC(pSize);
4519 FIXSRC(diffuse);
4520 FIXSRC(specular);
4521 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4522 FIXSRC(texCoords[i]);
4524 FIXSRC(position2);
4525 FIXSRC(normal2);
4526 FIXSRC(tangent);
4527 FIXSRC(binormal);
4528 FIXSRC(tessFactor);
4529 FIXSRC(fog);
4530 FIXSRC(depth);
4531 FIXSRC(sample);
4532 #undef FIXSRC
4535 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4538 /*****
4539 * Get / Set Texture Stage States
4540 * TODO: Verify against dx9 definitions
4541 *****/
4542 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4544 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4546 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4548 if (Stage >= MAX_TEXTURES) {
4549 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4550 return WINED3D_OK;
4553 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4554 This->updateStateBlock->textureState[Stage][Type] = Value;
4556 if (This->isRecordingState) {
4557 TRACE("Recording... not performing anything\n");
4558 return WINED3D_OK;
4561 /* Checked after the assignments to allow proper stateblock recording */
4562 if(oldValue == Value) {
4563 TRACE("App is setting the old value over, nothing to do\n");
4564 return WINED3D_OK;
4567 if(Stage > This->stateBlock->lowest_disabled_stage &&
4568 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4569 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4570 * Changes in other states are important on disabled stages too
4572 return WINED3D_OK;
4575 if(Type == WINED3DTSS_COLOROP) {
4576 int i;
4578 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4579 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4580 * they have to be disabled
4582 * The current stage is dirtified below.
4584 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4585 TRACE("Additionally dirtifying stage %d\n", i);
4586 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4588 This->stateBlock->lowest_disabled_stage = Stage;
4589 TRACE("New lowest disabled: %d\n", Stage);
4590 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4591 /* Previously disabled stage enabled. Stages above it may need enabling
4592 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4593 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4595 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4598 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4599 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4600 break;
4602 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4603 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4605 This->stateBlock->lowest_disabled_stage = i;
4606 TRACE("New lowest disabled: %d\n", i);
4608 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4609 /* TODO: Built a stage -> texture unit mapping for register combiners */
4613 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4615 return WINED3D_OK;
4618 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4620 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4621 *pValue = This->updateStateBlock->textureState[Stage][Type];
4622 return WINED3D_OK;
4625 /*****
4626 * Get / Set Texture
4627 *****/
4628 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4630 IWineD3DBaseTexture *oldTexture;
4632 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4634 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4635 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4638 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4639 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4640 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4643 oldTexture = This->updateStateBlock->textures[Stage];
4645 if(pTexture != NULL) {
4646 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4648 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4649 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4650 return WINED3DERR_INVALIDCALL;
4652 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4655 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4656 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4658 This->updateStateBlock->changed.textures[Stage] = TRUE;
4659 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4660 This->updateStateBlock->textures[Stage] = pTexture;
4662 /* Handle recording of state blocks */
4663 if (This->isRecordingState) {
4664 TRACE("Recording... not performing anything\n");
4665 return WINED3D_OK;
4668 if(oldTexture == pTexture) {
4669 TRACE("App is setting the same texture again, nothing to do\n");
4670 return WINED3D_OK;
4673 /** NOTE: MSDN says that setTexture increases the reference count,
4674 * and that the application must set the texture back to null (or have a leaky application),
4675 * This means we should pass the refcount up to the parent
4676 *******************************/
4677 if (NULL != This->updateStateBlock->textures[Stage]) {
4678 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4679 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4681 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4682 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4683 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4684 * so the COLOROP and ALPHAOP have to be dirtified.
4686 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4687 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4689 if(bindCount == 1) {
4690 new->baseTexture.sampler = Stage;
4692 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4696 if (NULL != oldTexture) {
4697 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4698 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4700 IWineD3DBaseTexture_Release(oldTexture);
4701 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4702 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4703 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4706 if(bindCount && old->baseTexture.sampler == Stage) {
4707 int i;
4708 /* Have to do a search for the other sampler(s) where the texture is bound to
4709 * Shouldn't happen as long as apps bind a texture only to one stage
4711 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4712 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4713 if(This->updateStateBlock->textures[i] == oldTexture) {
4714 old->baseTexture.sampler = i;
4715 break;
4721 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4723 return WINED3D_OK;
4726 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4729 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4731 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4732 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4735 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4736 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4737 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4740 *ppTexture=This->stateBlock->textures[Stage];
4741 if (*ppTexture)
4742 IWineD3DBaseTexture_AddRef(*ppTexture);
4744 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4746 return WINED3D_OK;
4749 /*****
4750 * Get Back Buffer
4751 *****/
4752 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4753 IWineD3DSurface **ppBackBuffer) {
4754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4755 IWineD3DSwapChain *swapChain;
4756 HRESULT hr;
4758 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4760 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4761 if (hr == WINED3D_OK) {
4762 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4763 IWineD3DSwapChain_Release(swapChain);
4764 } else {
4765 *ppBackBuffer = NULL;
4767 return hr;
4770 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4772 WARN("(%p) : stub, calling idirect3d for now\n", This);
4773 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4776 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4778 IWineD3DSwapChain *swapChain;
4779 HRESULT hr;
4781 if(iSwapChain > 0) {
4782 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4783 if (hr == WINED3D_OK) {
4784 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4785 IWineD3DSwapChain_Release(swapChain);
4786 } else {
4787 FIXME("(%p) Error getting display mode\n", This);
4789 } else {
4790 /* Don't read the real display mode,
4791 but return the stored mode instead. X11 can't change the color
4792 depth, and some apps are pretty angry if they SetDisplayMode from
4793 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4795 Also don't relay to the swapchain because with ddraw it's possible
4796 that there isn't a swapchain at all */
4797 pMode->Width = This->ddraw_width;
4798 pMode->Height = This->ddraw_height;
4799 pMode->Format = This->ddraw_format;
4800 pMode->RefreshRate = 0;
4801 hr = WINED3D_OK;
4804 return hr;
4807 /*****
4808 * Stateblock related functions
4809 *****/
4811 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4813 IWineD3DStateBlockImpl *object;
4814 HRESULT temp_result;
4815 int i;
4817 TRACE("(%p)\n", This);
4819 if (This->isRecordingState) {
4820 return WINED3DERR_INVALIDCALL;
4823 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4824 if (NULL == object ) {
4825 FIXME("(%p)Error allocating memory for stateblock\n", This);
4826 return E_OUTOFMEMORY;
4828 TRACE("(%p) created object %p\n", This, object);
4829 object->wineD3DDevice= This;
4830 /** FIXME: object->parent = parent; **/
4831 object->parent = NULL;
4832 object->blockType = WINED3DSBT_RECORDED;
4833 object->ref = 1;
4834 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4836 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4837 list_init(&object->lightMap[i]);
4840 temp_result = allocate_shader_constants(object);
4841 if (WINED3D_OK != temp_result)
4842 return temp_result;
4844 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4845 This->updateStateBlock = object;
4846 This->isRecordingState = TRUE;
4848 TRACE("(%p) recording stateblock %p\n",This , object);
4849 return WINED3D_OK;
4852 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4854 unsigned int i, j;
4855 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4857 if (!This->isRecordingState) {
4858 FIXME("(%p) not recording! returning error\n", This);
4859 *ppStateBlock = NULL;
4860 return WINED3DERR_INVALIDCALL;
4863 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4864 if(object->changed.renderState[i]) {
4865 object->contained_render_states[object->num_contained_render_states] = i;
4866 object->num_contained_render_states++;
4869 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4870 if(object->changed.transform[i]) {
4871 object->contained_transform_states[object->num_contained_transform_states] = i;
4872 object->num_contained_transform_states++;
4875 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4876 if(object->changed.vertexShaderConstantsF[i]) {
4877 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4878 object->num_contained_vs_consts_f++;
4881 for(i = 0; i < MAX_CONST_I; i++) {
4882 if(object->changed.vertexShaderConstantsI[i]) {
4883 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4884 object->num_contained_vs_consts_i++;
4887 for(i = 0; i < MAX_CONST_B; i++) {
4888 if(object->changed.vertexShaderConstantsB[i]) {
4889 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4890 object->num_contained_vs_consts_b++;
4893 for(i = 0; i < MAX_CONST_I; i++) {
4894 if(object->changed.pixelShaderConstantsI[i]) {
4895 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4896 object->num_contained_ps_consts_i++;
4899 for(i = 0; i < MAX_CONST_B; i++) {
4900 if(object->changed.pixelShaderConstantsB[i]) {
4901 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4902 object->num_contained_ps_consts_b++;
4905 for(i = 0; i < MAX_TEXTURES; i++) {
4906 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4907 if(object->changed.textureState[i][j]) {
4908 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4909 object->contained_tss_states[object->num_contained_tss_states].state = j;
4910 object->num_contained_tss_states++;
4914 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4915 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4916 if(object->changed.samplerState[i][j]) {
4917 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4918 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4919 object->num_contained_sampler_states++;
4924 *ppStateBlock = (IWineD3DStateBlock*) object;
4925 This->isRecordingState = FALSE;
4926 This->updateStateBlock = This->stateBlock;
4927 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4928 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4929 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4930 return WINED3D_OK;
4933 /*****
4934 * Scene related functions
4935 *****/
4936 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4937 /* At the moment we have no need for any functionality at the beginning
4938 of a scene */
4939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4940 TRACE("(%p)\n", This);
4942 if(This->inScene) {
4943 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4944 return WINED3DERR_INVALIDCALL;
4946 This->inScene = TRUE;
4947 return WINED3D_OK;
4950 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4952 TRACE("(%p)\n", This);
4954 if(!This->inScene) {
4955 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4956 return WINED3DERR_INVALIDCALL;
4959 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4960 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4961 glFlush();
4962 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4963 * fails
4966 This->inScene = FALSE;
4967 return WINED3D_OK;
4970 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4971 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4972 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4974 IWineD3DSwapChain *swapChain = NULL;
4975 int i;
4976 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4978 TRACE("(%p) Presenting the frame\n", This);
4980 for(i = 0 ; i < swapchains ; i ++) {
4982 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4983 TRACE("presentinng chain %d, %p\n", i, swapChain);
4984 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4985 IWineD3DSwapChain_Release(swapChain);
4988 return WINED3D_OK;
4991 /* Not called from the VTable (internal subroutine) */
4992 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4993 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4994 float Z, DWORD Stencil) {
4995 GLbitfield glMask = 0;
4996 unsigned int i;
4997 WINED3DRECT curRect;
4998 RECT vp_rect;
4999 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5000 UINT drawable_width, drawable_height;
5001 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5003 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5004 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5005 * for the cleared parts, and the untouched parts.
5007 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5008 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5009 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5010 * checking all this if the dest surface is in the drawable anyway.
5012 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5013 while(1) {
5014 if(vp->X != 0 || vp->Y != 0 ||
5015 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5016 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5017 break;
5019 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5020 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5021 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5022 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5023 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5024 break;
5026 if(Count > 0 && pRects && (
5027 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5028 pRects[0].x2 < target->currentDesc.Width ||
5029 pRects[0].y2 < target->currentDesc.Height)) {
5030 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5031 break;
5033 break;
5037 target->get_drawable_size(target, &drawable_width, &drawable_height);
5039 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5040 ENTER_GL();
5042 /* Only set the values up once, as they are not changing */
5043 if (Flags & WINED3DCLEAR_STENCIL) {
5044 glClearStencil(Stencil);
5045 checkGLcall("glClearStencil");
5046 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5047 glStencilMask(0xFFFFFFFF);
5050 if (Flags & WINED3DCLEAR_ZBUFFER) {
5051 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5052 glDepthMask(GL_TRUE);
5053 glClearDepth(Z);
5054 checkGLcall("glClearDepth");
5055 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5056 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5058 if (vp->X != 0 || vp->Y != 0 ||
5059 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5060 surface_load_ds_location(This->stencilBufferTarget, location);
5062 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5063 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5064 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5065 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5066 surface_load_ds_location(This->stencilBufferTarget, location);
5068 else if (Count > 0 && pRects && (
5069 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5070 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5071 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5072 surface_load_ds_location(This->stencilBufferTarget, location);
5076 if (Flags & WINED3DCLEAR_TARGET) {
5077 TRACE("Clearing screen with glClear to color %x\n", Color);
5078 glClearColor(D3DCOLOR_R(Color),
5079 D3DCOLOR_G(Color),
5080 D3DCOLOR_B(Color),
5081 D3DCOLOR_A(Color));
5082 checkGLcall("glClearColor");
5084 /* Clear ALL colors! */
5085 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5086 glMask = glMask | GL_COLOR_BUFFER_BIT;
5089 vp_rect.left = vp->X;
5090 vp_rect.top = vp->Y;
5091 vp_rect.right = vp->X + vp->Width;
5092 vp_rect.bottom = vp->Y + vp->Height;
5093 if (!(Count > 0 && pRects)) {
5094 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5095 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5097 if(This->render_offscreen) {
5098 glScissor(vp_rect.left, vp_rect.top,
5099 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5100 } else {
5101 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5102 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5104 checkGLcall("glScissor");
5105 glClear(glMask);
5106 checkGLcall("glClear");
5107 } else {
5108 /* Now process each rect in turn */
5109 for (i = 0; i < Count; i++) {
5110 /* Note gl uses lower left, width/height */
5111 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5112 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5113 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5115 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5116 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5117 curRect.x1, (target->currentDesc.Height - curRect.y2),
5118 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5120 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5121 * The rectangle is not cleared, no error is returned, but further rectanlges are
5122 * still cleared if they are valid
5124 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5125 TRACE("Rectangle with negative dimensions, ignoring\n");
5126 continue;
5129 if(This->render_offscreen) {
5130 glScissor(curRect.x1, curRect.y1,
5131 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5132 } else {
5133 glScissor(curRect.x1, drawable_height - curRect.y2,
5134 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5136 checkGLcall("glScissor");
5138 glClear(glMask);
5139 checkGLcall("glClear");
5143 /* Restore the old values (why..?) */
5144 if (Flags & WINED3DCLEAR_STENCIL) {
5145 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5147 if (Flags & WINED3DCLEAR_TARGET) {
5148 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5149 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5150 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5151 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5152 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5154 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5155 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5157 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5158 /* TODO: Move the fbo logic into ModifyLocation() */
5159 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5160 target->Flags |= SFLAG_INTEXTURE;
5163 if (Flags & WINED3DCLEAR_ZBUFFER) {
5164 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5165 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5166 surface_modify_ds_location(This->stencilBufferTarget, location);
5169 LEAVE_GL();
5171 return WINED3D_OK;
5174 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5175 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5177 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5179 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5180 Count, pRects, Flags, Color, Z, Stencil);
5182 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5183 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5184 /* TODO: What about depth stencil buffers without stencil bits? */
5185 return WINED3DERR_INVALIDCALL;
5188 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5191 /*****
5192 * Drawing functions
5193 *****/
5194 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5195 UINT PrimitiveCount) {
5197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5199 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5200 debug_d3dprimitivetype(PrimitiveType),
5201 StartVertex, PrimitiveCount);
5203 if(!This->stateBlock->vertexDecl) {
5204 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5205 return WINED3DERR_INVALIDCALL;
5208 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5209 if(This->stateBlock->streamIsUP) {
5210 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5211 This->stateBlock->streamIsUP = FALSE;
5214 if(This->stateBlock->loadBaseVertexIndex != 0) {
5215 This->stateBlock->loadBaseVertexIndex = 0;
5216 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5218 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5219 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5220 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5221 return WINED3D_OK;
5224 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5225 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5226 WINED3DPRIMITIVETYPE PrimitiveType,
5227 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5230 UINT idxStride = 2;
5231 IWineD3DIndexBuffer *pIB;
5232 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5233 GLuint vbo;
5235 pIB = This->stateBlock->pIndexData;
5236 if (!pIB) {
5237 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5238 * without an index buffer set. (The first time at least...)
5239 * D3D8 simply dies, but I doubt it can do much harm to return
5240 * D3DERR_INVALIDCALL there as well. */
5241 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5242 return WINED3DERR_INVALIDCALL;
5245 if(!This->stateBlock->vertexDecl) {
5246 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5247 return WINED3DERR_INVALIDCALL;
5250 if(This->stateBlock->streamIsUP) {
5251 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5252 This->stateBlock->streamIsUP = FALSE;
5254 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5256 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5257 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5258 minIndex, NumVertices, startIndex, primCount);
5260 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5261 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5262 idxStride = 2;
5263 } else {
5264 idxStride = 4;
5267 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5268 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5269 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5272 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5273 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5275 return WINED3D_OK;
5278 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5279 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5280 UINT VertexStreamZeroStride) {
5281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5282 IWineD3DVertexBuffer *vb;
5284 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5285 debug_d3dprimitivetype(PrimitiveType),
5286 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5288 if(!This->stateBlock->vertexDecl) {
5289 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5290 return WINED3DERR_INVALIDCALL;
5293 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5294 vb = This->stateBlock->streamSource[0];
5295 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5296 if(vb) IWineD3DVertexBuffer_Release(vb);
5297 This->stateBlock->streamOffset[0] = 0;
5298 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5299 This->stateBlock->streamIsUP = TRUE;
5300 This->stateBlock->loadBaseVertexIndex = 0;
5302 /* TODO: Only mark dirty if drawing from a different UP address */
5303 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5305 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5306 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5308 /* MSDN specifies stream zero settings must be set to NULL */
5309 This->stateBlock->streamStride[0] = 0;
5310 This->stateBlock->streamSource[0] = NULL;
5312 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5313 * the new stream sources or use UP drawing again
5315 return WINED3D_OK;
5318 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5319 UINT MinVertexIndex, UINT NumVertices,
5320 UINT PrimitiveCount, CONST void* pIndexData,
5321 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5322 UINT VertexStreamZeroStride) {
5323 int idxStride;
5324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5325 IWineD3DVertexBuffer *vb;
5326 IWineD3DIndexBuffer *ib;
5328 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5329 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5330 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5331 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5333 if(!This->stateBlock->vertexDecl) {
5334 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5335 return WINED3DERR_INVALIDCALL;
5338 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5339 idxStride = 2;
5340 } else {
5341 idxStride = 4;
5344 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5345 vb = This->stateBlock->streamSource[0];
5346 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5347 if(vb) IWineD3DVertexBuffer_Release(vb);
5348 This->stateBlock->streamIsUP = TRUE;
5349 This->stateBlock->streamOffset[0] = 0;
5350 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5352 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5353 This->stateBlock->baseVertexIndex = 0;
5354 This->stateBlock->loadBaseVertexIndex = 0;
5355 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5356 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5357 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5359 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5361 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5362 This->stateBlock->streamSource[0] = NULL;
5363 This->stateBlock->streamStride[0] = 0;
5364 ib = This->stateBlock->pIndexData;
5365 if(ib) {
5366 IWineD3DIndexBuffer_Release(ib);
5367 This->stateBlock->pIndexData = NULL;
5369 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5370 * SetStreamSource to specify a vertex buffer
5373 return WINED3D_OK;
5376 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5379 /* Mark the state dirty until we have nicer tracking
5380 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5381 * that value.
5383 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5384 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5385 This->stateBlock->baseVertexIndex = 0;
5386 This->up_strided = DrawPrimStrideData;
5387 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5388 This->up_strided = NULL;
5389 return WINED3D_OK;
5392 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5394 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5396 /* Mark the state dirty until we have nicer tracking
5397 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5398 * that value.
5400 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5401 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5402 This->stateBlock->streamIsUP = TRUE;
5403 This->stateBlock->baseVertexIndex = 0;
5404 This->up_strided = DrawPrimStrideData;
5405 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5406 This->up_strided = NULL;
5407 return WINED3D_OK;
5410 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5411 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5412 * not callable by the app directly no parameter validation checks are needed here.
5414 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5415 WINED3DLOCKED_BOX src;
5416 WINED3DLOCKED_BOX dst;
5417 HRESULT hr;
5418 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5420 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5421 * dirtification to improve loading performance.
5423 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5424 if(FAILED(hr)) return hr;
5425 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5426 if(FAILED(hr)) {
5427 IWineD3DVolume_UnlockBox(pSourceVolume);
5428 return hr;
5431 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5433 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5434 if(FAILED(hr)) {
5435 IWineD3DVolume_UnlockBox(pSourceVolume);
5436 } else {
5437 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5439 return hr;
5442 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5443 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5445 HRESULT hr = WINED3D_OK;
5446 WINED3DRESOURCETYPE sourceType;
5447 WINED3DRESOURCETYPE destinationType;
5448 int i ,levels;
5450 /* TODO: think about moving the code into IWineD3DBaseTexture */
5452 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5454 /* verify that the source and destination textures aren't NULL */
5455 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5456 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5457 This, pSourceTexture, pDestinationTexture);
5458 hr = WINED3DERR_INVALIDCALL;
5461 if (pSourceTexture == pDestinationTexture) {
5462 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5463 This, pSourceTexture, pDestinationTexture);
5464 hr = WINED3DERR_INVALIDCALL;
5466 /* Verify that the source and destination textures are the same type */
5467 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5468 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5470 if (sourceType != destinationType) {
5471 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5472 This);
5473 hr = WINED3DERR_INVALIDCALL;
5476 /* check that both textures have the identical numbers of levels */
5477 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5478 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5479 hr = WINED3DERR_INVALIDCALL;
5482 if (WINED3D_OK == hr) {
5484 /* Make sure that the destination texture is loaded */
5485 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5487 /* Update every surface level of the texture */
5488 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5490 switch (sourceType) {
5491 case WINED3DRTYPE_TEXTURE:
5493 IWineD3DSurface *srcSurface;
5494 IWineD3DSurface *destSurface;
5496 for (i = 0 ; i < levels ; ++i) {
5497 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5498 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5499 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5500 IWineD3DSurface_Release(srcSurface);
5501 IWineD3DSurface_Release(destSurface);
5502 if (WINED3D_OK != hr) {
5503 WARN("(%p) : Call to update surface failed\n", This);
5504 return hr;
5508 break;
5509 case WINED3DRTYPE_CUBETEXTURE:
5511 IWineD3DSurface *srcSurface;
5512 IWineD3DSurface *destSurface;
5513 WINED3DCUBEMAP_FACES faceType;
5515 for (i = 0 ; i < levels ; ++i) {
5516 /* Update each cube face */
5517 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5518 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5519 if (WINED3D_OK != hr) {
5520 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5521 } else {
5522 TRACE("Got srcSurface %p\n", srcSurface);
5524 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5525 if (WINED3D_OK != hr) {
5526 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5527 } else {
5528 TRACE("Got desrSurface %p\n", destSurface);
5530 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5531 IWineD3DSurface_Release(srcSurface);
5532 IWineD3DSurface_Release(destSurface);
5533 if (WINED3D_OK != hr) {
5534 WARN("(%p) : Call to update surface failed\n", This);
5535 return hr;
5540 break;
5542 case WINED3DRTYPE_VOLUMETEXTURE:
5544 IWineD3DVolume *srcVolume = NULL;
5545 IWineD3DVolume *destVolume = NULL;
5547 for (i = 0 ; i < levels ; ++i) {
5548 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5549 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5550 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5551 IWineD3DVolume_Release(srcVolume);
5552 IWineD3DVolume_Release(destVolume);
5553 if (WINED3D_OK != hr) {
5554 WARN("(%p) : Call to update volume failed\n", This);
5555 return hr;
5559 break;
5561 default:
5562 FIXME("(%p) : Unsupported source and destination type\n", This);
5563 hr = WINED3DERR_INVALIDCALL;
5567 return hr;
5570 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5571 IWineD3DSwapChain *swapChain;
5572 HRESULT hr;
5573 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5574 if(hr == WINED3D_OK) {
5575 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5576 IWineD3DSwapChain_Release(swapChain);
5578 return hr;
5581 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5583 /* return a sensible default */
5584 *pNumPasses = 1;
5585 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5586 FIXME("(%p) : stub\n", This);
5587 return WINED3D_OK;
5590 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5592 int i;
5594 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5595 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5596 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5597 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5602 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5604 int j;
5605 UINT NewSize;
5606 PALETTEENTRY **palettes;
5608 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5610 if (PaletteNumber >= MAX_PALETTES) {
5611 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5612 return WINED3DERR_INVALIDCALL;
5615 if (PaletteNumber >= This->NumberOfPalettes) {
5616 NewSize = This->NumberOfPalettes;
5617 do {
5618 NewSize *= 2;
5619 } while(PaletteNumber >= NewSize);
5620 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5621 if (!palettes) {
5622 ERR("Out of memory!\n");
5623 return E_OUTOFMEMORY;
5625 This->palettes = palettes;
5626 This->NumberOfPalettes = NewSize;
5629 if (!This->palettes[PaletteNumber]) {
5630 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5631 if (!This->palettes[PaletteNumber]) {
5632 ERR("Out of memory!\n");
5633 return E_OUTOFMEMORY;
5637 for (j = 0; j < 256; ++j) {
5638 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5639 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5640 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5641 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5643 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5644 TRACE("(%p) : returning\n", This);
5645 return WINED3D_OK;
5648 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5650 int j;
5651 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5652 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5653 /* What happens in such situation isn't documented; Native seems to silently abort
5654 on such conditions. Return Invalid Call. */
5655 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5656 return WINED3DERR_INVALIDCALL;
5658 for (j = 0; j < 256; ++j) {
5659 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5660 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5661 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5662 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5664 TRACE("(%p) : returning\n", This);
5665 return WINED3D_OK;
5668 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5670 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5671 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5672 (tested with reference rasterizer). Return Invalid Call. */
5673 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5674 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5675 return WINED3DERR_INVALIDCALL;
5677 /*TODO: stateblocks */
5678 if (This->currentPalette != PaletteNumber) {
5679 This->currentPalette = PaletteNumber;
5680 dirtify_p8_texture_samplers(This);
5682 TRACE("(%p) : returning\n", This);
5683 return WINED3D_OK;
5686 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5688 if (PaletteNumber == NULL) {
5689 WARN("(%p) : returning Invalid Call\n", This);
5690 return WINED3DERR_INVALIDCALL;
5692 /*TODO: stateblocks */
5693 *PaletteNumber = This->currentPalette;
5694 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5695 return WINED3D_OK;
5698 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5700 static BOOL showFixmes = TRUE;
5701 if (showFixmes) {
5702 FIXME("(%p) : stub\n", This);
5703 showFixmes = FALSE;
5706 This->softwareVertexProcessing = bSoftware;
5707 return WINED3D_OK;
5711 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5713 static BOOL showFixmes = TRUE;
5714 if (showFixmes) {
5715 FIXME("(%p) : stub\n", This);
5716 showFixmes = FALSE;
5718 return This->softwareVertexProcessing;
5722 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5724 IWineD3DSwapChain *swapChain;
5725 HRESULT hr;
5727 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5729 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5730 if(hr == WINED3D_OK){
5731 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5732 IWineD3DSwapChain_Release(swapChain);
5733 }else{
5734 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5736 return hr;
5740 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5742 static BOOL showfixmes = TRUE;
5743 if(nSegments != 0.0f) {
5744 if( showfixmes) {
5745 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5746 showfixmes = FALSE;
5749 return WINED3D_OK;
5752 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5754 static BOOL showfixmes = TRUE;
5755 if( showfixmes) {
5756 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5757 showfixmes = FALSE;
5759 return 0.0f;
5762 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5764 /** TODO: remove casts to IWineD3DSurfaceImpl
5765 * NOTE: move code to surface to accomplish this
5766 ****************************************/
5767 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5768 int srcWidth, srcHeight;
5769 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5770 WINED3DFORMAT destFormat, srcFormat;
5771 UINT destSize;
5772 int srcLeft, destLeft, destTop;
5773 WINED3DPOOL srcPool, destPool;
5774 int offset = 0;
5775 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5776 glDescriptor *glDescription = NULL;
5777 GLenum dummy;
5778 int sampler;
5779 int bpp;
5780 CONVERT_TYPES convert = NO_CONVERSION;
5782 WINED3DSURFACE_DESC winedesc;
5784 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5785 memset(&winedesc, 0, sizeof(winedesc));
5786 winedesc.Width = &srcSurfaceWidth;
5787 winedesc.Height = &srcSurfaceHeight;
5788 winedesc.Pool = &srcPool;
5789 winedesc.Format = &srcFormat;
5791 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5793 winedesc.Width = &destSurfaceWidth;
5794 winedesc.Height = &destSurfaceHeight;
5795 winedesc.Pool = &destPool;
5796 winedesc.Format = &destFormat;
5797 winedesc.Size = &destSize;
5799 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5801 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5802 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5803 return WINED3DERR_INVALIDCALL;
5806 /* This call loads the opengl surface directly, instead of copying the surface to the
5807 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5808 * copy in sysmem and use regular surface loading.
5810 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5811 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5812 if(convert != NO_CONVERSION) {
5813 return IWineD3DSurface_BltFast(pDestinationSurface,
5814 pDestPoint ? pDestPoint->x : 0,
5815 pDestPoint ? pDestPoint->y : 0,
5816 pSourceSurface, (RECT *) pSourceRect, 0);
5819 if (destFormat == WINED3DFMT_UNKNOWN) {
5820 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5821 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5823 /* Get the update surface description */
5824 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5827 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5829 ENTER_GL();
5831 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5832 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5833 checkGLcall("glActiveTextureARB");
5836 /* Make sure the surface is loaded and up to date */
5837 IWineD3DSurface_PreLoad(pDestinationSurface);
5839 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5841 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5842 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5843 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5844 srcLeft = pSourceRect ? pSourceRect->left : 0;
5845 destLeft = pDestPoint ? pDestPoint->x : 0;
5846 destTop = pDestPoint ? pDestPoint->y : 0;
5849 /* This function doesn't support compressed textures
5850 the pitch is just bytesPerPixel * width */
5851 if(srcWidth != srcSurfaceWidth || srcLeft ){
5852 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5853 offset += srcLeft * pSrcSurface->bytesPerPixel;
5854 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5856 /* TODO DXT formats */
5858 if(pSourceRect != NULL && pSourceRect->top != 0){
5859 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5861 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5862 ,This
5863 ,glDescription->level
5864 ,destLeft
5865 ,destTop
5866 ,srcWidth
5867 ,srcHeight
5868 ,glDescription->glFormat
5869 ,glDescription->glType
5870 ,IWineD3DSurface_GetData(pSourceSurface)
5873 /* Sanity check */
5874 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5876 /* need to lock the surface to get the data */
5877 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5880 /* TODO: Cube and volume support */
5881 if(rowoffset != 0){
5882 /* not a whole row so we have to do it a line at a time */
5883 int j;
5885 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5886 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5888 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5890 glTexSubImage2D(glDescription->target
5891 ,glDescription->level
5892 ,destLeft
5894 ,srcWidth
5896 ,glDescription->glFormat
5897 ,glDescription->glType
5898 ,data /* could be quicker using */
5900 data += rowoffset;
5903 } else { /* Full width, so just write out the whole texture */
5905 if (WINED3DFMT_DXT1 == destFormat ||
5906 WINED3DFMT_DXT2 == destFormat ||
5907 WINED3DFMT_DXT3 == destFormat ||
5908 WINED3DFMT_DXT4 == destFormat ||
5909 WINED3DFMT_DXT5 == destFormat) {
5910 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5911 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5912 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5913 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5914 } if (destFormat != srcFormat) {
5915 FIXME("Updating mixed format compressed texture is not curretly support\n");
5916 } else {
5917 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5918 glDescription->level,
5919 glDescription->glFormatInternal,
5920 srcWidth,
5921 srcHeight,
5923 destSize,
5924 IWineD3DSurface_GetData(pSourceSurface));
5926 } else {
5927 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5931 } else {
5932 glTexSubImage2D(glDescription->target
5933 ,glDescription->level
5934 ,destLeft
5935 ,destTop
5936 ,srcWidth
5937 ,srcHeight
5938 ,glDescription->glFormat
5939 ,glDescription->glType
5940 ,IWineD3DSurface_GetData(pSourceSurface)
5944 checkGLcall("glTexSubImage2D");
5946 LEAVE_GL();
5948 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5949 sampler = This->rev_tex_unit_map[0];
5950 if (sampler != -1) {
5951 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5954 return WINED3D_OK;
5957 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5959 struct WineD3DRectPatch *patch;
5960 unsigned int i;
5961 struct list *e;
5962 BOOL found;
5963 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5965 if(!(Handle || pRectPatchInfo)) {
5966 /* TODO: Write a test for the return value, thus the FIXME */
5967 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5968 return WINED3DERR_INVALIDCALL;
5971 if(Handle) {
5972 i = PATCHMAP_HASHFUNC(Handle);
5973 found = FALSE;
5974 LIST_FOR_EACH(e, &This->patches[i]) {
5975 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5976 if(patch->Handle == Handle) {
5977 found = TRUE;
5978 break;
5982 if(!found) {
5983 TRACE("Patch does not exist. Creating a new one\n");
5984 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5985 patch->Handle = Handle;
5986 list_add_head(&This->patches[i], &patch->entry);
5987 } else {
5988 TRACE("Found existing patch %p\n", patch);
5990 } else {
5991 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5992 * attributes we have to tesselate, read back, and draw. This needs a patch
5993 * management structure instance. Create one.
5995 * A possible improvement is to check if a vertex shader is used, and if not directly
5996 * draw the patch.
5998 FIXME("Drawing an uncached patch. This is slow\n");
5999 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6002 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6003 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6004 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6005 HRESULT hr;
6006 TRACE("Tesselation density or patch info changed, retesselating\n");
6008 if(pRectPatchInfo) {
6009 patch->RectPatchInfo = *pRectPatchInfo;
6011 patch->numSegs[0] = pNumSegs[0];
6012 patch->numSegs[1] = pNumSegs[1];
6013 patch->numSegs[2] = pNumSegs[2];
6014 patch->numSegs[3] = pNumSegs[3];
6016 hr = tesselate_rectpatch(This, patch);
6017 if(FAILED(hr)) {
6018 WARN("Patch tesselation failed\n");
6020 /* Do not release the handle to store the params of the patch */
6021 if(!Handle) {
6022 HeapFree(GetProcessHeap(), 0, patch);
6024 return hr;
6028 This->currentPatch = patch;
6029 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6030 This->currentPatch = NULL;
6032 /* Destroy uncached patches */
6033 if(!Handle) {
6034 HeapFree(GetProcessHeap(), 0, patch->mem);
6035 HeapFree(GetProcessHeap(), 0, patch);
6037 return WINED3D_OK;
6040 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6042 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6043 FIXME("(%p) : Stub\n", This);
6044 return WINED3D_OK;
6047 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6048 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6049 int i;
6050 struct WineD3DRectPatch *patch;
6051 struct list *e;
6052 TRACE("(%p) Handle(%d)\n", This, Handle);
6054 i = PATCHMAP_HASHFUNC(Handle);
6055 LIST_FOR_EACH(e, &This->patches[i]) {
6056 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6057 if(patch->Handle == Handle) {
6058 TRACE("Deleting patch %p\n", patch);
6059 list_remove(&patch->entry);
6060 HeapFree(GetProcessHeap(), 0, patch->mem);
6061 HeapFree(GetProcessHeap(), 0, patch);
6062 return WINED3D_OK;
6066 /* TODO: Write a test for the return value */
6067 FIXME("Attempt to destroy nonexistent patch\n");
6068 return WINED3DERR_INVALIDCALL;
6071 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6072 HRESULT hr;
6073 IWineD3DSwapChain *swapchain;
6075 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6076 if (SUCCEEDED(hr)) {
6077 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6078 return swapchain;
6081 return NULL;
6084 void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
6085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6087 if (!*fbo) {
6088 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
6089 checkGLcall("glGenFramebuffersEXT()");
6091 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
6092 checkGLcall("glBindFramebuffer()");
6095 /* TODO: Handle stencil attachments */
6096 void attach_depth_stencil_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, IWineD3DSurface *depth_stencil, BOOL use_render_buffer) {
6097 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6099 if (use_render_buffer && depth_stencil_impl->current_renderbuffer) {
6100 GL_EXTCALL(glFramebufferRenderbufferEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6101 checkGLcall("glFramebufferRenderbufferEXT()");
6102 } else {
6103 IWineD3DBaseTextureImpl *texture_impl;
6104 GLenum texttarget, target;
6105 GLint old_binding = 0;
6107 texttarget = depth_stencil_impl->glDescription.target;
6108 if(texttarget == GL_TEXTURE_2D) {
6109 target = GL_TEXTURE_2D;
6110 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6111 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6112 target = GL_TEXTURE_RECTANGLE_ARB;
6113 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6114 } else {
6115 target = GL_TEXTURE_CUBE_MAP_ARB;
6116 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6119 IWineD3DSurface_PreLoad(depth_stencil);
6121 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6122 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6123 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6124 glBindTexture(target, old_binding);
6126 /* Update base texture states array */
6127 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6128 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6129 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6130 if (texture_impl->baseTexture.bindCount) {
6131 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6134 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6137 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6138 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6139 checkGLcall("glFramebufferTexture2DEXT()");
6143 void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
6144 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
6145 IWineD3DBaseTextureImpl *texture_impl;
6146 GLenum texttarget, target;
6147 GLint old_binding;
6149 texttarget = surface_impl->glDescription.target;
6150 if(texttarget == GL_TEXTURE_2D) {
6151 target = GL_TEXTURE_2D;
6152 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6153 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6154 target = GL_TEXTURE_RECTANGLE_ARB;
6155 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6156 } else {
6157 target = GL_TEXTURE_CUBE_MAP_ARB;
6158 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6161 IWineD3DSurface_PreLoad(surface);
6163 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6164 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6165 glBindTexture(target, old_binding);
6167 /* Update base texture states array */
6168 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6169 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6170 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6171 if (texture_impl->baseTexture.bindCount) {
6172 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6175 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6178 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6179 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6181 checkGLcall("attach_surface_fbo");
6184 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6186 IWineD3DSwapChain *swapchain;
6188 swapchain = get_swapchain(surface);
6189 if (swapchain) {
6190 GLenum buffer;
6192 TRACE("Surface %p is onscreen\n", surface);
6194 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6195 ENTER_GL();
6196 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6197 buffer = surface_get_gl_buffer(surface, swapchain);
6198 glDrawBuffer(buffer);
6199 checkGLcall("glDrawBuffer()");
6200 } else {
6201 TRACE("Surface %p is offscreen\n", surface);
6203 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6204 ENTER_GL();
6205 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6206 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6207 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6208 checkGLcall("glFramebufferRenderbufferEXT");
6211 if (rect) {
6212 glEnable(GL_SCISSOR_TEST);
6213 if(!swapchain) {
6214 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6215 } else {
6216 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6217 rect->x2 - rect->x1, rect->y2 - rect->y1);
6219 checkGLcall("glScissor");
6220 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6221 } else {
6222 glDisable(GL_SCISSOR_TEST);
6224 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6226 glDisable(GL_BLEND);
6227 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6229 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6230 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6232 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6233 glClear(GL_COLOR_BUFFER_BIT);
6234 checkGLcall("glClear");
6236 if (This->render_offscreen) {
6237 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->fbo);
6238 } else {
6239 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6240 checkGLcall("glBindFramebuffer()");
6243 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6244 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6245 glDrawBuffer(GL_BACK);
6246 checkGLcall("glDrawBuffer()");
6249 LEAVE_GL();
6252 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6253 unsigned int r, g, b, a;
6254 DWORD ret;
6256 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6257 destfmt == WINED3DFMT_R8G8B8)
6258 return color;
6260 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6262 a = (color & 0xff000000) >> 24;
6263 r = (color & 0x00ff0000) >> 16;
6264 g = (color & 0x0000ff00) >> 8;
6265 b = (color & 0x000000ff) >> 0;
6267 switch(destfmt)
6269 case WINED3DFMT_R5G6B5:
6270 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6271 r = (r * 32) / 256;
6272 g = (g * 64) / 256;
6273 b = (b * 32) / 256;
6274 ret = r << 11;
6275 ret |= g << 5;
6276 ret |= b;
6277 TRACE("Returning %08x\n", ret);
6278 return ret;
6280 case WINED3DFMT_X1R5G5B5:
6281 case WINED3DFMT_A1R5G5B5:
6282 a = (a * 2) / 256;
6283 r = (r * 32) / 256;
6284 g = (g * 32) / 256;
6285 b = (b * 32) / 256;
6286 ret = a << 15;
6287 ret |= r << 10;
6288 ret |= g << 5;
6289 ret |= b << 0;
6290 TRACE("Returning %08x\n", ret);
6291 return ret;
6293 case WINED3DFMT_A8:
6294 TRACE("Returning %08x\n", a);
6295 return a;
6297 case WINED3DFMT_X4R4G4B4:
6298 case WINED3DFMT_A4R4G4B4:
6299 a = (a * 16) / 256;
6300 r = (r * 16) / 256;
6301 g = (g * 16) / 256;
6302 b = (b * 16) / 256;
6303 ret = a << 12;
6304 ret |= r << 8;
6305 ret |= g << 4;
6306 ret |= b << 0;
6307 TRACE("Returning %08x\n", ret);
6308 return ret;
6310 case WINED3DFMT_R3G3B2:
6311 r = (r * 8) / 256;
6312 g = (g * 8) / 256;
6313 b = (b * 4) / 256;
6314 ret = r << 5;
6315 ret |= g << 2;
6316 ret |= b << 0;
6317 TRACE("Returning %08x\n", ret);
6318 return ret;
6320 case WINED3DFMT_X8B8G8R8:
6321 case WINED3DFMT_A8B8G8R8:
6322 ret = a << 24;
6323 ret |= b << 16;
6324 ret |= g << 8;
6325 ret |= r << 0;
6326 TRACE("Returning %08x\n", ret);
6327 return ret;
6329 case WINED3DFMT_A2R10G10B10:
6330 a = (a * 4) / 256;
6331 r = (r * 1024) / 256;
6332 g = (g * 1024) / 256;
6333 b = (b * 1024) / 256;
6334 ret = a << 30;
6335 ret |= r << 20;
6336 ret |= g << 10;
6337 ret |= b << 0;
6338 TRACE("Returning %08x\n", ret);
6339 return ret;
6341 case WINED3DFMT_A2B10G10R10:
6342 a = (a * 4) / 256;
6343 r = (r * 1024) / 256;
6344 g = (g * 1024) / 256;
6345 b = (b * 1024) / 256;
6346 ret = a << 30;
6347 ret |= b << 20;
6348 ret |= g << 10;
6349 ret |= r << 0;
6350 TRACE("Returning %08x\n", ret);
6351 return ret;
6353 default:
6354 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6355 return 0;
6359 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6361 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6362 WINEDDBLTFX BltFx;
6363 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6365 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6366 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6367 return WINED3DERR_INVALIDCALL;
6370 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6371 color_fill_fbo(iface, pSurface, pRect, color);
6372 return WINED3D_OK;
6373 } else {
6374 /* Just forward this to the DirectDraw blitting engine */
6375 memset(&BltFx, 0, sizeof(BltFx));
6376 BltFx.dwSize = sizeof(BltFx);
6377 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6378 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6382 /* rendertarget and depth stencil functions */
6383 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6386 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6387 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6388 return WINED3DERR_INVALIDCALL;
6391 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6392 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6393 /* Note inc ref on returned surface */
6394 if(*ppRenderTarget != NULL)
6395 IWineD3DSurface_AddRef(*ppRenderTarget);
6396 return WINED3D_OK;
6399 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6401 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6402 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6403 IWineD3DSwapChainImpl *Swapchain;
6404 HRESULT hr;
6406 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6408 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6409 if(hr != WINED3D_OK) {
6410 ERR("Can't get the swapchain\n");
6411 return hr;
6414 /* Make sure to release the swapchain */
6415 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6417 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6418 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6419 return WINED3DERR_INVALIDCALL;
6421 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6422 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6423 return WINED3DERR_INVALIDCALL;
6426 if(Swapchain->frontBuffer != Front) {
6427 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6429 if(Swapchain->frontBuffer)
6430 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6431 Swapchain->frontBuffer = Front;
6433 if(Swapchain->frontBuffer) {
6434 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6438 if(Back && !Swapchain->backBuffer) {
6439 /* We need memory for the back buffer array - only one back buffer this way */
6440 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6441 if(!Swapchain->backBuffer) {
6442 ERR("Out of memory\n");
6443 return E_OUTOFMEMORY;
6447 if(Swapchain->backBuffer[0] != Back) {
6448 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6450 /* What to do about the context here in the case of multithreading? Not sure.
6451 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6453 ENTER_GL();
6454 if(!Swapchain->backBuffer[0]) {
6455 /* GL was told to draw to the front buffer at creation,
6456 * undo that
6458 glDrawBuffer(GL_BACK);
6459 checkGLcall("glDrawBuffer(GL_BACK)");
6460 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6461 Swapchain->presentParms.BackBufferCount = 1;
6462 } else if (!Back) {
6463 /* That makes problems - disable for now */
6464 /* glDrawBuffer(GL_FRONT); */
6465 checkGLcall("glDrawBuffer(GL_FRONT)");
6466 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6467 Swapchain->presentParms.BackBufferCount = 0;
6469 LEAVE_GL();
6471 if(Swapchain->backBuffer[0])
6472 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6473 Swapchain->backBuffer[0] = Back;
6475 if(Swapchain->backBuffer[0]) {
6476 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6477 } else {
6478 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6479 Swapchain->backBuffer = NULL;
6484 return WINED3D_OK;
6487 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6489 *ppZStencilSurface = This->stencilBufferTarget;
6490 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6492 if(*ppZStencilSurface != NULL) {
6493 /* Note inc ref on returned surface */
6494 IWineD3DSurface_AddRef(*ppZStencilSurface);
6495 return WINED3D_OK;
6496 } else {
6497 return WINED3DERR_NOTFOUND;
6501 /* TODO: Handle stencil attachments */
6502 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6505 TRACE("Set depth stencil to %p\n", depth_stencil);
6507 if (depth_stencil) {
6508 attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, depth_stencil, TRUE);
6509 } else {
6510 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6511 checkGLcall("glFramebufferTexture2DEXT()");
6515 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6518 TRACE("Set render target %u to %p\n", idx, render_target);
6520 if (render_target) {
6521 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6522 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6523 } else {
6524 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6525 checkGLcall("glFramebufferTexture2DEXT()");
6527 This->draw_buffers[idx] = GL_NONE;
6531 static void check_fbo_status(IWineD3DDevice *iface) {
6532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6533 GLenum status;
6535 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6536 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6537 TRACE("FBO complete\n");
6538 } else {
6539 IWineD3DSurfaceImpl *attachment;
6540 int i;
6541 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6543 /* Dump the FBO attachments */
6544 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6545 attachment = (IWineD3DSurfaceImpl *)This->activeContext->fbo_color_attachments[i];
6546 if (attachment) {
6547 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6548 attachment->pow2Width, attachment->pow2Height);
6551 attachment = (IWineD3DSurfaceImpl *)This->activeContext->fbo_depth_attachment;
6552 if (attachment) {
6553 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6554 attachment->pow2Width, attachment->pow2Height);
6559 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6560 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6561 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6562 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6564 if (!ds_impl) return FALSE;
6566 if (ds_impl->current_renderbuffer) {
6567 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6568 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6571 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6572 rt_impl->pow2Height != ds_impl->pow2Height);
6575 void apply_fbo_state(IWineD3DDevice *iface) {
6576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6577 WineD3DContext *context = This->activeContext;
6578 unsigned int i;
6580 if (This->render_offscreen) {
6581 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &context->fbo);
6583 /* Apply render targets */
6584 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6585 IWineD3DSurface *render_target = This->render_targets[i];
6586 if (context->fbo_color_attachments[i] != render_target) {
6587 set_render_target_fbo(iface, i, render_target);
6588 context->fbo_color_attachments[i] = render_target;
6592 /* Apply depth targets */
6593 if (context->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6594 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6595 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6597 if (This->stencilBufferTarget) {
6598 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6600 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6601 context->fbo_depth_attachment = This->stencilBufferTarget;
6603 } else {
6604 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6607 check_fbo_status(iface);
6610 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6611 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6613 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6614 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6615 GLenum gl_filter;
6616 POINT offset = {0, 0};
6618 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6619 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6620 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6621 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6623 switch (filter) {
6624 case WINED3DTEXF_LINEAR:
6625 gl_filter = GL_LINEAR;
6626 break;
6628 default:
6629 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6630 case WINED3DTEXF_NONE:
6631 case WINED3DTEXF_POINT:
6632 gl_filter = GL_NEAREST;
6633 break;
6636 /* Attach src surface to src fbo */
6637 src_swapchain = get_swapchain(src_surface);
6638 if (src_swapchain) {
6639 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6641 TRACE("Source surface %p is onscreen\n", src_surface);
6642 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6643 /* Make sure the drawable is up to date. In the offscreen case
6644 * attach_surface_fbo() implicitly takes care of this. */
6645 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6647 if(buffer == GL_FRONT) {
6648 RECT windowsize;
6649 UINT h;
6650 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6651 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6652 h = windowsize.bottom - windowsize.top;
6653 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6654 src_rect->y1 = offset.y + h - src_rect->y1;
6655 src_rect->y2 = offset.y + h - src_rect->y2;
6656 } else {
6657 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6658 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6661 ENTER_GL();
6662 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6663 glReadBuffer(buffer);
6664 checkGLcall("glReadBuffer()");
6665 } else {
6666 TRACE("Source surface %p is offscreen\n", src_surface);
6667 ENTER_GL();
6668 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6669 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6670 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6671 checkGLcall("glReadBuffer()");
6672 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6673 checkGLcall("glFramebufferRenderbufferEXT");
6675 LEAVE_GL();
6677 /* Attach dst surface to dst fbo */
6678 dst_swapchain = get_swapchain(dst_surface);
6679 if (dst_swapchain) {
6680 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6682 TRACE("Destination surface %p is onscreen\n", dst_surface);
6683 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6684 /* Make sure the drawable is up to date. In the offscreen case
6685 * attach_surface_fbo() implicitly takes care of this. */
6686 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6688 if(buffer == GL_FRONT) {
6689 RECT windowsize;
6690 UINT h;
6691 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6692 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6693 h = windowsize.bottom - windowsize.top;
6694 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6695 dst_rect->y1 = offset.y + h - dst_rect->y1;
6696 dst_rect->y2 = offset.y + h - dst_rect->y2;
6697 } else {
6698 /* Screen coords = window coords, surface height = window height */
6699 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6700 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6703 ENTER_GL();
6704 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6705 glDrawBuffer(buffer);
6706 checkGLcall("glDrawBuffer()");
6707 } else {
6708 TRACE("Destination surface %p is offscreen\n", dst_surface);
6710 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6711 if(!src_swapchain) {
6712 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6715 ENTER_GL();
6716 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6717 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6718 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6719 checkGLcall("glDrawBuffer()");
6720 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6721 checkGLcall("glFramebufferRenderbufferEXT");
6723 glDisable(GL_SCISSOR_TEST);
6724 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6726 if (flip) {
6727 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6728 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6729 checkGLcall("glBlitFramebuffer()");
6730 } else {
6731 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6732 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6733 checkGLcall("glBlitFramebuffer()");
6736 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6738 if (This->render_offscreen) {
6739 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->fbo);
6740 } else {
6741 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6742 checkGLcall("glBindFramebuffer()");
6745 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6746 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6747 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6748 glDrawBuffer(GL_BACK);
6749 checkGLcall("glDrawBuffer()");
6751 LEAVE_GL();
6754 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6756 WINED3DVIEWPORT viewport;
6758 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6760 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6761 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6762 This, RenderTargetIndex, GL_LIMITS(buffers));
6763 return WINED3DERR_INVALIDCALL;
6766 /* MSDN says that null disables the render target
6767 but a device must always be associated with a render target
6768 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6770 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6771 FIXME("Trying to set render target 0 to NULL\n");
6772 return WINED3DERR_INVALIDCALL;
6774 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6775 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);
6776 return WINED3DERR_INVALIDCALL;
6779 /* If we are trying to set what we already have, don't bother */
6780 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6781 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6782 return WINED3D_OK;
6784 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6785 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6786 This->render_targets[RenderTargetIndex] = pRenderTarget;
6788 /* Render target 0 is special */
6789 if(RenderTargetIndex == 0) {
6790 /* Finally, reset the viewport as the MSDN states. */
6791 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6792 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6793 viewport.X = 0;
6794 viewport.Y = 0;
6795 viewport.MaxZ = 1.0f;
6796 viewport.MinZ = 0.0f;
6797 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6798 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6799 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6801 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6803 return WINED3D_OK;
6806 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6808 HRESULT hr = WINED3D_OK;
6809 IWineD3DSurface *tmp;
6811 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6813 if (pNewZStencil == This->stencilBufferTarget) {
6814 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6815 } else {
6816 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6817 * depending on the renter target implementation being used.
6818 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6819 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6820 * stencil buffer and incur an extra memory overhead
6821 ******************************************************/
6823 if (This->stencilBufferTarget) {
6824 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6825 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6826 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6829 tmp = This->stencilBufferTarget;
6830 This->stencilBufferTarget = pNewZStencil;
6831 /* should we be calling the parent or the wined3d surface? */
6832 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6833 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6834 hr = WINED3D_OK;
6836 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6837 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6838 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6839 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6840 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6844 return hr;
6847 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6848 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6850 /* TODO: the use of Impl is deprecated. */
6851 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6852 WINED3DLOCKED_RECT lockedRect;
6854 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6856 /* some basic validation checks */
6857 if(This->cursorTexture) {
6858 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6859 ENTER_GL();
6860 glDeleteTextures(1, &This->cursorTexture);
6861 LEAVE_GL();
6862 This->cursorTexture = 0;
6865 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6866 This->haveHardwareCursor = TRUE;
6867 else
6868 This->haveHardwareCursor = FALSE;
6870 if(pCursorBitmap) {
6871 WINED3DLOCKED_RECT rect;
6873 /* MSDN: Cursor must be A8R8G8B8 */
6874 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6875 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6876 return WINED3DERR_INVALIDCALL;
6879 /* MSDN: Cursor must be smaller than the display mode */
6880 if(pSur->currentDesc.Width > This->ddraw_width ||
6881 pSur->currentDesc.Height > This->ddraw_height) {
6882 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);
6883 return WINED3DERR_INVALIDCALL;
6886 if (!This->haveHardwareCursor) {
6887 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6889 /* Do not store the surface's pointer because the application may
6890 * release it after setting the cursor image. Windows doesn't
6891 * addref the set surface, so we can't do this either without
6892 * creating circular refcount dependencies. Copy out the gl texture
6893 * instead.
6895 This->cursorWidth = pSur->currentDesc.Width;
6896 This->cursorHeight = pSur->currentDesc.Height;
6897 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6899 const GlPixelFormatDesc *glDesc;
6900 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6901 char *mem, *bits = (char *)rect.pBits;
6902 GLint intfmt = glDesc->glInternal;
6903 GLint format = glDesc->glFormat;
6904 GLint type = glDesc->glType;
6905 INT height = This->cursorHeight;
6906 INT width = This->cursorWidth;
6907 INT bpp = tableEntry->bpp;
6908 INT i, sampler;
6910 /* Reformat the texture memory (pitch and width can be
6911 * different) */
6912 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6913 for(i = 0; i < height; i++)
6914 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6915 IWineD3DSurface_UnlockRect(pCursorBitmap);
6916 ENTER_GL();
6918 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6919 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6920 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6923 /* Make sure that a proper texture unit is selected */
6924 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6925 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6926 checkGLcall("glActiveTextureARB");
6928 sampler = This->rev_tex_unit_map[0];
6929 if (sampler != -1) {
6930 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6932 /* Create a new cursor texture */
6933 glGenTextures(1, &This->cursorTexture);
6934 checkGLcall("glGenTextures");
6935 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6936 checkGLcall("glBindTexture");
6937 /* Copy the bitmap memory into the cursor texture */
6938 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6939 HeapFree(GetProcessHeap(), 0, mem);
6940 checkGLcall("glTexImage2D");
6942 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6943 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6944 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6947 LEAVE_GL();
6949 else
6951 FIXME("A cursor texture was not returned.\n");
6952 This->cursorTexture = 0;
6955 else
6957 /* Draw a hardware cursor */
6958 ICONINFO cursorInfo;
6959 HCURSOR cursor;
6960 /* Create and clear maskBits because it is not needed for
6961 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6962 * chunks. */
6963 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6964 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6965 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6966 WINED3DLOCK_NO_DIRTY_UPDATE |
6967 WINED3DLOCK_READONLY
6969 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6970 pSur->currentDesc.Height);
6972 cursorInfo.fIcon = FALSE;
6973 cursorInfo.xHotspot = XHotSpot;
6974 cursorInfo.yHotspot = YHotSpot;
6975 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6976 pSur->currentDesc.Height, 1,
6977 1, &maskBits);
6978 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6979 pSur->currentDesc.Height, 1,
6980 32, lockedRect.pBits);
6981 IWineD3DSurface_UnlockRect(pCursorBitmap);
6982 /* Create our cursor and clean up. */
6983 cursor = CreateIconIndirect(&cursorInfo);
6984 SetCursor(cursor);
6985 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6986 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6987 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6988 This->hardwareCursor = cursor;
6989 HeapFree(GetProcessHeap(), 0, maskBits);
6993 This->xHotSpot = XHotSpot;
6994 This->yHotSpot = YHotSpot;
6995 return WINED3D_OK;
6998 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7000 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7002 This->xScreenSpace = XScreenSpace;
7003 This->yScreenSpace = YScreenSpace;
7005 return;
7009 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7011 BOOL oldVisible = This->bCursorVisible;
7012 POINT pt;
7014 TRACE("(%p) : visible(%d)\n", This, bShow);
7017 * When ShowCursor is first called it should make the cursor appear at the OS's last
7018 * known cursor position. Because of this, some applications just repetitively call
7019 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7021 GetCursorPos(&pt);
7022 This->xScreenSpace = pt.x;
7023 This->yScreenSpace = pt.y;
7025 if (This->haveHardwareCursor) {
7026 This->bCursorVisible = bShow;
7027 if (bShow)
7028 SetCursor(This->hardwareCursor);
7029 else
7030 SetCursor(NULL);
7032 else
7034 if (This->cursorTexture)
7035 This->bCursorVisible = bShow;
7038 return oldVisible;
7041 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7043 IWineD3DResourceImpl *resource;
7044 TRACE("(%p) : state (%u)\n", This, This->state);
7046 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7047 switch (This->state) {
7048 case WINED3D_OK:
7049 return WINED3D_OK;
7050 case WINED3DERR_DEVICELOST:
7052 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7053 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7054 return WINED3DERR_DEVICENOTRESET;
7056 return WINED3DERR_DEVICELOST;
7058 case WINED3DERR_DRIVERINTERNALERROR:
7059 return WINED3DERR_DRIVERINTERNALERROR;
7062 /* Unknown state */
7063 return WINED3DERR_DRIVERINTERNALERROR;
7067 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7069 /** FIXME: Resource tracking needs to be done,
7070 * The closes we can do to this is set the priorities of all managed textures low
7071 * and then reset them.
7072 ***********************************************************/
7073 FIXME("(%p) : stub\n", This);
7074 return WINED3D_OK;
7077 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7078 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7080 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7081 if(surface->Flags & SFLAG_DIBSECTION) {
7082 /* Release the DC */
7083 SelectObject(surface->hDC, surface->dib.holdbitmap);
7084 DeleteDC(surface->hDC);
7085 /* Release the DIB section */
7086 DeleteObject(surface->dib.DIBsection);
7087 surface->dib.bitmap_data = NULL;
7088 surface->resource.allocatedMemory = NULL;
7089 surface->Flags &= ~SFLAG_DIBSECTION;
7091 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7092 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7093 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7094 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7095 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7096 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7097 } else {
7098 surface->pow2Width = surface->pow2Height = 1;
7099 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7100 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7102 surface->glRect.left = 0;
7103 surface->glRect.top = 0;
7104 surface->glRect.right = surface->pow2Width;
7105 surface->glRect.bottom = surface->pow2Height;
7107 if(surface->glDescription.textureName) {
7108 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7109 ENTER_GL();
7110 glDeleteTextures(1, &surface->glDescription.textureName);
7111 LEAVE_GL();
7112 surface->glDescription.textureName = 0;
7113 surface->Flags &= ~SFLAG_CLIENT;
7115 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7116 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7117 surface->Flags |= SFLAG_NONPOW2;
7118 } else {
7119 surface->Flags &= ~SFLAG_NONPOW2;
7121 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7122 surface->resource.allocatedMemory = NULL;
7123 surface->resource.heapMemory = NULL;
7124 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7125 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7126 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7127 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7128 } else {
7129 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7133 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7134 TRACE("Unloading resource %p\n", resource);
7135 IWineD3DResource_UnLoad(resource);
7136 IWineD3DResource_Release(resource);
7137 return S_OK;
7140 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7141 UINT i, count;
7142 WINED3DDISPLAYMODE m;
7143 HRESULT hr;
7145 /* All Windowed modes are supported, as is leaving the current mode */
7146 if(pp->Windowed) return TRUE;
7147 if(!pp->BackBufferWidth) return TRUE;
7148 if(!pp->BackBufferHeight) return TRUE;
7150 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7151 for(i = 0; i < count; i++) {
7152 memset(&m, 0, sizeof(m));
7153 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7154 if(FAILED(hr)) {
7155 ERR("EnumAdapterModes failed\n");
7157 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7158 /* Mode found, it is supported */
7159 return TRUE;
7162 /* Mode not found -> not supported */
7163 return FALSE;
7166 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7168 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7169 UINT i;
7170 IWineD3DBaseShaderImpl *shader;
7172 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7173 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7174 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7177 ENTER_GL();
7178 if(This->depth_blt_texture) {
7179 glDeleteTextures(1, &This->depth_blt_texture);
7180 This->depth_blt_texture = 0;
7182 if (This->depth_blt_rb) {
7183 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7184 This->depth_blt_rb = 0;
7185 This->depth_blt_rb_w = 0;
7186 This->depth_blt_rb_h = 0;
7188 This->blitter->free_private(iface);
7189 This->frag_pipe->free_private(iface);
7190 This->shader_backend->shader_free_private(iface);
7192 for (i = 0; i < GL_LIMITS(textures); i++) {
7193 /* Textures are recreated below */
7194 glDeleteTextures(1, &This->dummyTextureName[i]);
7195 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7196 This->dummyTextureName[i] = 0;
7198 LEAVE_GL();
7200 while(This->numContexts) {
7201 DestroyContext(This, This->contexts[0]);
7203 This->activeContext = NULL;
7204 HeapFree(GetProcessHeap(), 0, swapchain->context);
7205 swapchain->context = NULL;
7206 swapchain->num_contexts = 0;
7209 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7211 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7212 HRESULT hr;
7213 IWineD3DSurfaceImpl *target;
7215 /* Recreate the primary swapchain's context */
7216 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7217 if(swapchain->backBuffer) {
7218 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7219 } else {
7220 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7222 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7223 &swapchain->presentParms);
7224 swapchain->num_contexts = 1;
7225 This->activeContext = swapchain->context[0];
7227 create_dummy_textures(This);
7229 hr = This->shader_backend->shader_alloc_private(iface);
7230 if(FAILED(hr)) {
7231 ERR("Failed to recreate shader private data\n");
7232 goto err_out;
7234 hr = This->frag_pipe->alloc_private(iface);
7235 if(FAILED(hr)) {
7236 TRACE("Fragment pipeline private data couldn't be allocated\n");
7237 goto err_out;
7239 hr = This->blitter->alloc_private(iface);
7240 if(FAILED(hr)) {
7241 TRACE("Blitter private data couldn't be allocated\n");
7242 goto err_out;
7245 return WINED3D_OK;
7247 err_out:
7248 This->blitter->free_private(iface);
7249 This->frag_pipe->free_private(iface);
7250 This->shader_backend->shader_free_private(iface);
7251 return hr;
7254 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7256 IWineD3DSwapChainImpl *swapchain;
7257 HRESULT hr;
7258 BOOL DisplayModeChanged = FALSE;
7259 WINED3DDISPLAYMODE mode;
7260 TRACE("(%p)\n", This);
7262 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7263 if(FAILED(hr)) {
7264 ERR("Failed to get the first implicit swapchain\n");
7265 return hr;
7268 if(!is_display_mode_supported(This, pPresentationParameters)) {
7269 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7270 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7271 pPresentationParameters->BackBufferHeight);
7272 return WINED3DERR_INVALIDCALL;
7275 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7276 * on an existing gl context, so there's no real need for recreation.
7278 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7280 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7282 TRACE("New params:\n");
7283 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7284 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7285 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7286 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7287 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7288 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7289 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7290 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7291 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7292 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7293 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7294 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7295 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7297 /* No special treatment of these parameters. Just store them */
7298 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7299 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7300 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7301 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7303 /* What to do about these? */
7304 if(pPresentationParameters->BackBufferCount != 0 &&
7305 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7306 ERR("Cannot change the back buffer count yet\n");
7308 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7309 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7310 ERR("Cannot change the back buffer format yet\n");
7312 if(pPresentationParameters->hDeviceWindow != NULL &&
7313 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7314 ERR("Cannot change the device window yet\n");
7316 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7317 ERR("What do do about a changed auto depth stencil parameter?\n");
7320 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7322 if(pPresentationParameters->Windowed) {
7323 mode.Width = swapchain->orig_width;
7324 mode.Height = swapchain->orig_height;
7325 mode.RefreshRate = 0;
7326 mode.Format = swapchain->presentParms.BackBufferFormat;
7327 } else {
7328 mode.Width = pPresentationParameters->BackBufferWidth;
7329 mode.Height = pPresentationParameters->BackBufferHeight;
7330 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7331 mode.Format = swapchain->presentParms.BackBufferFormat;
7334 /* Should Width == 800 && Height == 0 set 800x600? */
7335 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7336 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7337 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7339 WINED3DVIEWPORT vp;
7340 int i;
7342 vp.X = 0;
7343 vp.Y = 0;
7344 vp.Width = pPresentationParameters->BackBufferWidth;
7345 vp.Height = pPresentationParameters->BackBufferHeight;
7346 vp.MinZ = 0;
7347 vp.MaxZ = 1;
7349 if(!pPresentationParameters->Windowed) {
7350 DisplayModeChanged = TRUE;
7352 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7353 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7355 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7356 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7357 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7359 if(This->auto_depth_stencil_buffer) {
7360 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7364 /* Now set the new viewport */
7365 IWineD3DDevice_SetViewport(iface, &vp);
7368 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7369 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7370 DisplayModeChanged) {
7372 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7374 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7375 if(swapchain->presentParms.Windowed) {
7376 /* switch from windowed to fs */
7377 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7378 pPresentationParameters->BackBufferWidth,
7379 pPresentationParameters->BackBufferHeight);
7380 } else {
7381 /* Fullscreen -> fullscreen mode change */
7382 MoveWindow(swapchain->win_handle, 0, 0,
7383 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7384 TRUE);
7386 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7387 /* Fullscreen -> windowed switch */
7388 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7390 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7391 } else if(!pPresentationParameters->Windowed) {
7392 DWORD style = This->style, exStyle = This->exStyle;
7393 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7394 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7395 * Reset to clear up their mess. Guild Wars also loses the device during that.
7397 This->style = 0;
7398 This->exStyle = 0;
7399 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7400 pPresentationParameters->BackBufferWidth,
7401 pPresentationParameters->BackBufferHeight);
7402 This->style = style;
7403 This->exStyle = exStyle;
7406 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7407 if(FAILED(hr)) {
7408 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7411 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7412 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7414 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7415 * first use
7417 return hr;
7420 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7422 /** FIXME: always true at the moment **/
7423 if(!bEnableDialogs) {
7424 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7426 return WINED3D_OK;
7430 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7432 TRACE("(%p) : pParameters %p\n", This, pParameters);
7434 *pParameters = This->createParms;
7435 return WINED3D_OK;
7438 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7439 IWineD3DSwapChain *swapchain;
7441 TRACE("Relaying to swapchain\n");
7443 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7444 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7445 IWineD3DSwapChain_Release(swapchain);
7447 return;
7450 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7451 IWineD3DSwapChain *swapchain;
7453 TRACE("Relaying to swapchain\n");
7455 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7456 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7457 IWineD3DSwapChain_Release(swapchain);
7459 return;
7463 /** ********************************************************
7464 * Notification functions
7465 ** ********************************************************/
7466 /** This function must be called in the release of a resource when ref == 0,
7467 * the contents of resource must still be correct,
7468 * any handles to other resource held by the caller must be closed
7469 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7470 *****************************************************/
7471 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7474 TRACE("(%p) : Adding Resource %p\n", This, resource);
7475 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7478 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7481 TRACE("(%p) : Removing resource %p\n", This, resource);
7483 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7487 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7489 int counter;
7491 TRACE("(%p) : resource %p\n", This, resource);
7492 switch(IWineD3DResource_GetType(resource)){
7493 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7494 case WINED3DRTYPE_SURFACE: {
7495 unsigned int i;
7497 /* Cleanup any FBO attachments if d3d is enabled */
7498 if(This->d3d_initialized) {
7499 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7500 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7502 TRACE("Last active render target destroyed\n");
7503 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7504 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7505 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7506 * and the lastActiveRenderTarget member shouldn't matter
7508 if(swapchain) {
7509 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7510 TRACE("Activating primary back buffer\n");
7511 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7512 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7513 /* Single buffering environment */
7514 TRACE("Activating primary front buffer\n");
7515 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7516 } else {
7517 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7518 /* Implicit render target destroyed, that means the device is being destroyed
7519 * whatever we set here, it shouldn't matter
7521 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7523 } else {
7524 /* May happen during ddraw uninitialization */
7525 TRACE("Render target set, but swapchain does not exist!\n");
7526 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7530 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7531 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7532 This->render_targets[i] = NULL;
7535 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7536 This->stencilBufferTarget = NULL;
7539 for (i = 0; i < This->numContexts; ++i) {
7540 int j;
7541 for (j = 0; j < GL_LIMITS(buffers); ++j) {
7542 if (This->contexts[i]->fbo_color_attachments[j] == (IWineD3DSurface *)resource) {
7543 This->contexts[i]->fbo_color_attachments[j] = NULL;
7546 if (This->contexts[i]->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7547 This->contexts[i]->fbo_depth_attachment = NULL;
7552 break;
7554 case WINED3DRTYPE_TEXTURE:
7555 case WINED3DRTYPE_CUBETEXTURE:
7556 case WINED3DRTYPE_VOLUMETEXTURE:
7557 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7558 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7559 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7560 This->stateBlock->textures[counter] = NULL;
7562 if (This->updateStateBlock != This->stateBlock ){
7563 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7564 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7565 This->updateStateBlock->textures[counter] = NULL;
7569 break;
7570 case WINED3DRTYPE_VOLUME:
7571 /* TODO: nothing really? */
7572 break;
7573 case WINED3DRTYPE_VERTEXBUFFER:
7574 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7576 int streamNumber;
7577 TRACE("Cleaning up stream pointers\n");
7579 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7580 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7581 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7583 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7584 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7585 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7586 This->updateStateBlock->streamSource[streamNumber] = 0;
7587 /* Set changed flag? */
7590 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) */
7591 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7592 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7593 This->stateBlock->streamSource[streamNumber] = 0;
7596 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7597 else { /* This shouldn't happen */
7598 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7600 #endif
7604 break;
7605 case WINED3DRTYPE_INDEXBUFFER:
7606 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7607 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7608 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7609 This->updateStateBlock->pIndexData = NULL;
7612 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7613 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7614 This->stateBlock->pIndexData = NULL;
7618 break;
7619 default:
7620 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7621 break;
7625 /* Remove the resource from the resourceStore */
7626 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7628 TRACE("Resource released\n");
7632 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7634 IWineD3DResourceImpl *resource, *cursor;
7635 HRESULT ret;
7636 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7638 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7639 TRACE("enumerating resource %p\n", resource);
7640 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7641 ret = pCallback((IWineD3DResource *) resource, pData);
7642 if(ret == S_FALSE) {
7643 TRACE("Canceling enumeration\n");
7644 break;
7647 return WINED3D_OK;
7650 /**********************************************************
7651 * IWineD3DDevice VTbl follows
7652 **********************************************************/
7654 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7656 /*** IUnknown methods ***/
7657 IWineD3DDeviceImpl_QueryInterface,
7658 IWineD3DDeviceImpl_AddRef,
7659 IWineD3DDeviceImpl_Release,
7660 /*** IWineD3DDevice methods ***/
7661 IWineD3DDeviceImpl_GetParent,
7662 /*** Creation methods**/
7663 IWineD3DDeviceImpl_CreateVertexBuffer,
7664 IWineD3DDeviceImpl_CreateIndexBuffer,
7665 IWineD3DDeviceImpl_CreateStateBlock,
7666 IWineD3DDeviceImpl_CreateSurface,
7667 IWineD3DDeviceImpl_CreateTexture,
7668 IWineD3DDeviceImpl_CreateVolumeTexture,
7669 IWineD3DDeviceImpl_CreateVolume,
7670 IWineD3DDeviceImpl_CreateCubeTexture,
7671 IWineD3DDeviceImpl_CreateQuery,
7672 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7673 IWineD3DDeviceImpl_CreateVertexDeclaration,
7674 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7675 IWineD3DDeviceImpl_CreateVertexShader,
7676 IWineD3DDeviceImpl_CreatePixelShader,
7677 IWineD3DDeviceImpl_CreatePalette,
7678 /*** Odd functions **/
7679 IWineD3DDeviceImpl_Init3D,
7680 IWineD3DDeviceImpl_InitGDI,
7681 IWineD3DDeviceImpl_Uninit3D,
7682 IWineD3DDeviceImpl_UninitGDI,
7683 IWineD3DDeviceImpl_SetMultithreaded,
7684 IWineD3DDeviceImpl_EvictManagedResources,
7685 IWineD3DDeviceImpl_GetAvailableTextureMem,
7686 IWineD3DDeviceImpl_GetBackBuffer,
7687 IWineD3DDeviceImpl_GetCreationParameters,
7688 IWineD3DDeviceImpl_GetDeviceCaps,
7689 IWineD3DDeviceImpl_GetDirect3D,
7690 IWineD3DDeviceImpl_GetDisplayMode,
7691 IWineD3DDeviceImpl_SetDisplayMode,
7692 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7693 IWineD3DDeviceImpl_GetRasterStatus,
7694 IWineD3DDeviceImpl_GetSwapChain,
7695 IWineD3DDeviceImpl_Reset,
7696 IWineD3DDeviceImpl_SetDialogBoxMode,
7697 IWineD3DDeviceImpl_SetCursorProperties,
7698 IWineD3DDeviceImpl_SetCursorPosition,
7699 IWineD3DDeviceImpl_ShowCursor,
7700 IWineD3DDeviceImpl_TestCooperativeLevel,
7701 /*** Getters and setters **/
7702 IWineD3DDeviceImpl_SetClipPlane,
7703 IWineD3DDeviceImpl_GetClipPlane,
7704 IWineD3DDeviceImpl_SetClipStatus,
7705 IWineD3DDeviceImpl_GetClipStatus,
7706 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7707 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7708 IWineD3DDeviceImpl_SetDepthStencilSurface,
7709 IWineD3DDeviceImpl_GetDepthStencilSurface,
7710 IWineD3DDeviceImpl_SetFVF,
7711 IWineD3DDeviceImpl_GetFVF,
7712 IWineD3DDeviceImpl_SetGammaRamp,
7713 IWineD3DDeviceImpl_GetGammaRamp,
7714 IWineD3DDeviceImpl_SetIndices,
7715 IWineD3DDeviceImpl_GetIndices,
7716 IWineD3DDeviceImpl_SetBaseVertexIndex,
7717 IWineD3DDeviceImpl_GetBaseVertexIndex,
7718 IWineD3DDeviceImpl_SetLight,
7719 IWineD3DDeviceImpl_GetLight,
7720 IWineD3DDeviceImpl_SetLightEnable,
7721 IWineD3DDeviceImpl_GetLightEnable,
7722 IWineD3DDeviceImpl_SetMaterial,
7723 IWineD3DDeviceImpl_GetMaterial,
7724 IWineD3DDeviceImpl_SetNPatchMode,
7725 IWineD3DDeviceImpl_GetNPatchMode,
7726 IWineD3DDeviceImpl_SetPaletteEntries,
7727 IWineD3DDeviceImpl_GetPaletteEntries,
7728 IWineD3DDeviceImpl_SetPixelShader,
7729 IWineD3DDeviceImpl_GetPixelShader,
7730 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7731 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7732 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7733 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7734 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7735 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7736 IWineD3DDeviceImpl_SetRenderState,
7737 IWineD3DDeviceImpl_GetRenderState,
7738 IWineD3DDeviceImpl_SetRenderTarget,
7739 IWineD3DDeviceImpl_GetRenderTarget,
7740 IWineD3DDeviceImpl_SetFrontBackBuffers,
7741 IWineD3DDeviceImpl_SetSamplerState,
7742 IWineD3DDeviceImpl_GetSamplerState,
7743 IWineD3DDeviceImpl_SetScissorRect,
7744 IWineD3DDeviceImpl_GetScissorRect,
7745 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7746 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7747 IWineD3DDeviceImpl_SetStreamSource,
7748 IWineD3DDeviceImpl_GetStreamSource,
7749 IWineD3DDeviceImpl_SetStreamSourceFreq,
7750 IWineD3DDeviceImpl_GetStreamSourceFreq,
7751 IWineD3DDeviceImpl_SetTexture,
7752 IWineD3DDeviceImpl_GetTexture,
7753 IWineD3DDeviceImpl_SetTextureStageState,
7754 IWineD3DDeviceImpl_GetTextureStageState,
7755 IWineD3DDeviceImpl_SetTransform,
7756 IWineD3DDeviceImpl_GetTransform,
7757 IWineD3DDeviceImpl_SetVertexDeclaration,
7758 IWineD3DDeviceImpl_GetVertexDeclaration,
7759 IWineD3DDeviceImpl_SetVertexShader,
7760 IWineD3DDeviceImpl_GetVertexShader,
7761 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7762 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7763 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7764 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7765 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7766 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7767 IWineD3DDeviceImpl_SetViewport,
7768 IWineD3DDeviceImpl_GetViewport,
7769 IWineD3DDeviceImpl_MultiplyTransform,
7770 IWineD3DDeviceImpl_ValidateDevice,
7771 IWineD3DDeviceImpl_ProcessVertices,
7772 /*** State block ***/
7773 IWineD3DDeviceImpl_BeginStateBlock,
7774 IWineD3DDeviceImpl_EndStateBlock,
7775 /*** Scene management ***/
7776 IWineD3DDeviceImpl_BeginScene,
7777 IWineD3DDeviceImpl_EndScene,
7778 IWineD3DDeviceImpl_Present,
7779 IWineD3DDeviceImpl_Clear,
7780 /*** Drawing ***/
7781 IWineD3DDeviceImpl_DrawPrimitive,
7782 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7783 IWineD3DDeviceImpl_DrawPrimitiveUP,
7784 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7785 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7786 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7787 IWineD3DDeviceImpl_DrawRectPatch,
7788 IWineD3DDeviceImpl_DrawTriPatch,
7789 IWineD3DDeviceImpl_DeletePatch,
7790 IWineD3DDeviceImpl_ColorFill,
7791 IWineD3DDeviceImpl_UpdateTexture,
7792 IWineD3DDeviceImpl_UpdateSurface,
7793 IWineD3DDeviceImpl_GetFrontBufferData,
7794 /*** object tracking ***/
7795 IWineD3DDeviceImpl_ResourceReleased,
7796 IWineD3DDeviceImpl_EnumResources
7799 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7801 /*** IUnknown methods ***/
7802 IWineD3DDeviceImpl_QueryInterface,
7803 IWineD3DDeviceImpl_AddRef,
7804 IWineD3DDeviceImpl_Release,
7805 /*** IWineD3DDevice methods ***/
7806 IWineD3DDeviceImpl_GetParent,
7807 /*** Creation methods**/
7808 IWineD3DDeviceImpl_CreateVertexBuffer,
7809 IWineD3DDeviceImpl_CreateIndexBuffer,
7810 IWineD3DDeviceImpl_CreateStateBlock,
7811 IWineD3DDeviceImpl_CreateSurface,
7812 IWineD3DDeviceImpl_CreateTexture,
7813 IWineD3DDeviceImpl_CreateVolumeTexture,
7814 IWineD3DDeviceImpl_CreateVolume,
7815 IWineD3DDeviceImpl_CreateCubeTexture,
7816 IWineD3DDeviceImpl_CreateQuery,
7817 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7818 IWineD3DDeviceImpl_CreateVertexDeclaration,
7819 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7820 IWineD3DDeviceImpl_CreateVertexShader,
7821 IWineD3DDeviceImpl_CreatePixelShader,
7822 IWineD3DDeviceImpl_CreatePalette,
7823 /*** Odd functions **/
7824 IWineD3DDeviceImpl_Init3D,
7825 IWineD3DDeviceImpl_InitGDI,
7826 IWineD3DDeviceImpl_Uninit3D,
7827 IWineD3DDeviceImpl_UninitGDI,
7828 IWineD3DDeviceImpl_SetMultithreaded,
7829 IWineD3DDeviceImpl_EvictManagedResources,
7830 IWineD3DDeviceImpl_GetAvailableTextureMem,
7831 IWineD3DDeviceImpl_GetBackBuffer,
7832 IWineD3DDeviceImpl_GetCreationParameters,
7833 IWineD3DDeviceImpl_GetDeviceCaps,
7834 IWineD3DDeviceImpl_GetDirect3D,
7835 IWineD3DDeviceImpl_GetDisplayMode,
7836 IWineD3DDeviceImpl_SetDisplayMode,
7837 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7838 IWineD3DDeviceImpl_GetRasterStatus,
7839 IWineD3DDeviceImpl_GetSwapChain,
7840 IWineD3DDeviceImpl_Reset,
7841 IWineD3DDeviceImpl_SetDialogBoxMode,
7842 IWineD3DDeviceImpl_SetCursorProperties,
7843 IWineD3DDeviceImpl_SetCursorPosition,
7844 IWineD3DDeviceImpl_ShowCursor,
7845 IWineD3DDeviceImpl_TestCooperativeLevel,
7846 /*** Getters and setters **/
7847 IWineD3DDeviceImpl_SetClipPlane,
7848 IWineD3DDeviceImpl_GetClipPlane,
7849 IWineD3DDeviceImpl_SetClipStatus,
7850 IWineD3DDeviceImpl_GetClipStatus,
7851 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7852 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7853 IWineD3DDeviceImpl_SetDepthStencilSurface,
7854 IWineD3DDeviceImpl_GetDepthStencilSurface,
7855 IWineD3DDeviceImpl_SetFVF,
7856 IWineD3DDeviceImpl_GetFVF,
7857 IWineD3DDeviceImpl_SetGammaRamp,
7858 IWineD3DDeviceImpl_GetGammaRamp,
7859 IWineD3DDeviceImpl_SetIndices,
7860 IWineD3DDeviceImpl_GetIndices,
7861 IWineD3DDeviceImpl_SetBaseVertexIndex,
7862 IWineD3DDeviceImpl_GetBaseVertexIndex,
7863 IWineD3DDeviceImpl_SetLight,
7864 IWineD3DDeviceImpl_GetLight,
7865 IWineD3DDeviceImpl_SetLightEnable,
7866 IWineD3DDeviceImpl_GetLightEnable,
7867 IWineD3DDeviceImpl_SetMaterial,
7868 IWineD3DDeviceImpl_GetMaterial,
7869 IWineD3DDeviceImpl_SetNPatchMode,
7870 IWineD3DDeviceImpl_GetNPatchMode,
7871 IWineD3DDeviceImpl_SetPaletteEntries,
7872 IWineD3DDeviceImpl_GetPaletteEntries,
7873 IWineD3DDeviceImpl_SetPixelShader,
7874 IWineD3DDeviceImpl_GetPixelShader,
7875 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7876 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7877 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7878 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7879 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7880 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7881 IWineD3DDeviceImpl_SetRenderState,
7882 IWineD3DDeviceImpl_GetRenderState,
7883 IWineD3DDeviceImpl_SetRenderTarget,
7884 IWineD3DDeviceImpl_GetRenderTarget,
7885 IWineD3DDeviceImpl_SetFrontBackBuffers,
7886 IWineD3DDeviceImpl_SetSamplerState,
7887 IWineD3DDeviceImpl_GetSamplerState,
7888 IWineD3DDeviceImpl_SetScissorRect,
7889 IWineD3DDeviceImpl_GetScissorRect,
7890 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7891 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7892 IWineD3DDeviceImpl_SetStreamSource,
7893 IWineD3DDeviceImpl_GetStreamSource,
7894 IWineD3DDeviceImpl_SetStreamSourceFreq,
7895 IWineD3DDeviceImpl_GetStreamSourceFreq,
7896 IWineD3DDeviceImpl_SetTexture,
7897 IWineD3DDeviceImpl_GetTexture,
7898 IWineD3DDeviceImpl_SetTextureStageState,
7899 IWineD3DDeviceImpl_GetTextureStageState,
7900 IWineD3DDeviceImpl_SetTransform,
7901 IWineD3DDeviceImpl_GetTransform,
7902 IWineD3DDeviceImpl_SetVertexDeclaration,
7903 IWineD3DDeviceImpl_GetVertexDeclaration,
7904 IWineD3DDeviceImpl_SetVertexShader,
7905 IWineD3DDeviceImpl_GetVertexShader,
7906 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7907 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7908 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7909 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7910 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7911 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7912 IWineD3DDeviceImpl_SetViewport,
7913 IWineD3DDeviceImpl_GetViewport,
7914 IWineD3DDeviceImpl_MultiplyTransform,
7915 IWineD3DDeviceImpl_ValidateDevice,
7916 IWineD3DDeviceImpl_ProcessVertices,
7917 /*** State block ***/
7918 IWineD3DDeviceImpl_BeginStateBlock,
7919 IWineD3DDeviceImpl_EndStateBlock,
7920 /*** Scene management ***/
7921 IWineD3DDeviceImpl_BeginScene,
7922 IWineD3DDeviceImpl_EndScene,
7923 IWineD3DDeviceImpl_Present,
7924 IWineD3DDeviceImpl_Clear,
7925 /*** Drawing ***/
7926 IWineD3DDeviceImpl_DrawPrimitive,
7927 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7928 IWineD3DDeviceImpl_DrawPrimitiveUP,
7929 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7930 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7931 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7932 IWineD3DDeviceImpl_DrawRectPatch,
7933 IWineD3DDeviceImpl_DrawTriPatch,
7934 IWineD3DDeviceImpl_DeletePatch,
7935 IWineD3DDeviceImpl_ColorFill,
7936 IWineD3DDeviceImpl_UpdateTexture,
7937 IWineD3DDeviceImpl_UpdateSurface,
7938 IWineD3DDeviceImpl_GetFrontBufferData,
7939 /*** object tracking ***/
7940 IWineD3DDeviceImpl_ResourceReleased,
7941 IWineD3DDeviceImpl_EnumResources
7944 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7945 WINED3DRS_ALPHABLENDENABLE ,
7946 WINED3DRS_ALPHAFUNC ,
7947 WINED3DRS_ALPHAREF ,
7948 WINED3DRS_ALPHATESTENABLE ,
7949 WINED3DRS_BLENDOP ,
7950 WINED3DRS_COLORWRITEENABLE ,
7951 WINED3DRS_DESTBLEND ,
7952 WINED3DRS_DITHERENABLE ,
7953 WINED3DRS_FILLMODE ,
7954 WINED3DRS_FOGDENSITY ,
7955 WINED3DRS_FOGEND ,
7956 WINED3DRS_FOGSTART ,
7957 WINED3DRS_LASTPIXEL ,
7958 WINED3DRS_SHADEMODE ,
7959 WINED3DRS_SRCBLEND ,
7960 WINED3DRS_STENCILENABLE ,
7961 WINED3DRS_STENCILFAIL ,
7962 WINED3DRS_STENCILFUNC ,
7963 WINED3DRS_STENCILMASK ,
7964 WINED3DRS_STENCILPASS ,
7965 WINED3DRS_STENCILREF ,
7966 WINED3DRS_STENCILWRITEMASK ,
7967 WINED3DRS_STENCILZFAIL ,
7968 WINED3DRS_TEXTUREFACTOR ,
7969 WINED3DRS_WRAP0 ,
7970 WINED3DRS_WRAP1 ,
7971 WINED3DRS_WRAP2 ,
7972 WINED3DRS_WRAP3 ,
7973 WINED3DRS_WRAP4 ,
7974 WINED3DRS_WRAP5 ,
7975 WINED3DRS_WRAP6 ,
7976 WINED3DRS_WRAP7 ,
7977 WINED3DRS_ZENABLE ,
7978 WINED3DRS_ZFUNC ,
7979 WINED3DRS_ZWRITEENABLE
7982 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7983 WINED3DTSS_ADDRESSW ,
7984 WINED3DTSS_ALPHAARG0 ,
7985 WINED3DTSS_ALPHAARG1 ,
7986 WINED3DTSS_ALPHAARG2 ,
7987 WINED3DTSS_ALPHAOP ,
7988 WINED3DTSS_BUMPENVLOFFSET ,
7989 WINED3DTSS_BUMPENVLSCALE ,
7990 WINED3DTSS_BUMPENVMAT00 ,
7991 WINED3DTSS_BUMPENVMAT01 ,
7992 WINED3DTSS_BUMPENVMAT10 ,
7993 WINED3DTSS_BUMPENVMAT11 ,
7994 WINED3DTSS_COLORARG0 ,
7995 WINED3DTSS_COLORARG1 ,
7996 WINED3DTSS_COLORARG2 ,
7997 WINED3DTSS_COLOROP ,
7998 WINED3DTSS_RESULTARG ,
7999 WINED3DTSS_TEXCOORDINDEX ,
8000 WINED3DTSS_TEXTURETRANSFORMFLAGS
8003 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8004 WINED3DSAMP_ADDRESSU ,
8005 WINED3DSAMP_ADDRESSV ,
8006 WINED3DSAMP_ADDRESSW ,
8007 WINED3DSAMP_BORDERCOLOR ,
8008 WINED3DSAMP_MAGFILTER ,
8009 WINED3DSAMP_MINFILTER ,
8010 WINED3DSAMP_MIPFILTER ,
8011 WINED3DSAMP_MIPMAPLODBIAS ,
8012 WINED3DSAMP_MAXMIPLEVEL ,
8013 WINED3DSAMP_MAXANISOTROPY ,
8014 WINED3DSAMP_SRGBTEXTURE ,
8015 WINED3DSAMP_ELEMENTINDEX
8018 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8019 WINED3DRS_AMBIENT ,
8020 WINED3DRS_AMBIENTMATERIALSOURCE ,
8021 WINED3DRS_CLIPPING ,
8022 WINED3DRS_CLIPPLANEENABLE ,
8023 WINED3DRS_COLORVERTEX ,
8024 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8025 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8026 WINED3DRS_FOGDENSITY ,
8027 WINED3DRS_FOGEND ,
8028 WINED3DRS_FOGSTART ,
8029 WINED3DRS_FOGTABLEMODE ,
8030 WINED3DRS_FOGVERTEXMODE ,
8031 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8032 WINED3DRS_LIGHTING ,
8033 WINED3DRS_LOCALVIEWER ,
8034 WINED3DRS_MULTISAMPLEANTIALIAS ,
8035 WINED3DRS_MULTISAMPLEMASK ,
8036 WINED3DRS_NORMALIZENORMALS ,
8037 WINED3DRS_PATCHEDGESTYLE ,
8038 WINED3DRS_POINTSCALE_A ,
8039 WINED3DRS_POINTSCALE_B ,
8040 WINED3DRS_POINTSCALE_C ,
8041 WINED3DRS_POINTSCALEENABLE ,
8042 WINED3DRS_POINTSIZE ,
8043 WINED3DRS_POINTSIZE_MAX ,
8044 WINED3DRS_POINTSIZE_MIN ,
8045 WINED3DRS_POINTSPRITEENABLE ,
8046 WINED3DRS_RANGEFOGENABLE ,
8047 WINED3DRS_SPECULARMATERIALSOURCE ,
8048 WINED3DRS_TWEENFACTOR ,
8049 WINED3DRS_VERTEXBLEND ,
8050 WINED3DRS_CULLMODE ,
8051 WINED3DRS_FOGCOLOR
8054 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8055 WINED3DTSS_TEXCOORDINDEX ,
8056 WINED3DTSS_TEXTURETRANSFORMFLAGS
8059 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8060 WINED3DSAMP_DMAPOFFSET
8063 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8064 DWORD rep = This->StateTable[state].representative;
8065 DWORD idx;
8066 BYTE shift;
8067 UINT i;
8068 WineD3DContext *context;
8070 if(!rep) return;
8071 for(i = 0; i < This->numContexts; i++) {
8072 context = This->contexts[i];
8073 if(isStateDirty(context, rep)) continue;
8075 context->dirtyArray[context->numDirtyEntries++] = rep;
8076 idx = rep >> 5;
8077 shift = rep & 0x1f;
8078 context->isStateDirty[idx] |= (1 << shift);
8082 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8083 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8084 /* The drawable size of a pbuffer render target is the current pbuffer size
8086 *width = dev->pbufferWidth;
8087 *height = dev->pbufferHeight;
8090 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8091 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8093 *width = This->pow2Width;
8094 *height = This->pow2Height;
8097 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8098 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8099 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8100 * current context's drawable, which is the size of the back buffer of the swapchain
8101 * the active context belongs to. The back buffer of the swapchain is stored as the
8102 * surface the context belongs to.
8104 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8105 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;