wined3d: Use CTXUSAGE_RESOURCELOAD for ActivateContext() in color_fill_fbo().
[wine/gsoc_dplay.git] / dlls / wined3d / device.c
blobcc1b44864a7e8800dca6635656a74891808ca5ac
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-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
66 object->ref = 1; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
99 *pp##type = NULL; \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 WineD3DAdapterChangeGLRam(This, _size); \
104 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
108 *pp##type = NULL; \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
139 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
140 if (IsEqualGUID(riid, &IID_IUnknown)
141 || IsEqualGUID(riid, &IID_IWineD3DBase)
142 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
143 IUnknown_AddRef(iface);
144 *ppobj = This;
145 return S_OK;
147 *ppobj = NULL;
148 return E_NOINTERFACE;
151 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 ULONG refCount = InterlockedIncrement(&This->ref);
155 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
156 return refCount;
159 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 ULONG refCount = InterlockedDecrement(&This->ref);
163 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
165 if (!refCount) {
166 if (This->fbo) {
167 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
169 if (This->src_fbo) {
170 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
172 if (This->dst_fbo) {
173 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
176 /* TODO: Clean up all the surfaces and textures! */
177 /* NOTE: You must release the parent if the object was created via a callback
178 ** ***************************/
180 if (!list_empty(&This->resources)) {
181 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
182 dumpResources(&This->resources);
185 if(This->contexts) ERR("Context array not freed!\n");
186 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
187 This->haveHardwareCursor = FALSE;
189 IWineD3D_Release(This->wineD3D);
190 This->wineD3D = NULL;
191 HeapFree(GetProcessHeap(), 0, This);
192 TRACE("Freed device %p\n", This);
193 This = NULL;
195 return refCount;
198 /**********************************************************
199 * IWineD3DDevice implementation follows
200 **********************************************************/
201 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
203 *pParent = This->parent;
204 IUnknown_AddRef(This->parent);
205 return WINED3D_OK;
208 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
209 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
210 IUnknown *parent) {
211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
212 IWineD3DVertexBufferImpl *object;
213 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
214 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
215 BOOL conv;
217 if(Size == 0) {
218 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
219 *ppVertexBuffer = NULL;
220 return WINED3DERR_INVALIDCALL;
221 } else if(Pool == WINED3DPOOL_SCRATCH) {
222 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
223 * anyway, SCRATCH vertex buffers aren't usable anywhere
225 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
226 *ppVertexBuffer = NULL;
227 return WINED3DERR_INVALIDCALL;
230 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
232 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);
233 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
235 object->fvf = FVF;
237 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
238 * drawStridedFast (half-life 2).
240 * Basically converting the vertices in the buffer is quite expensive, and observations
241 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
242 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
244 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
245 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
246 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
247 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
248 * dx7 apps.
249 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
250 * more. In this call we can convert dx7 buffers too.
252 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
253 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
254 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
255 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
256 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
257 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
258 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
259 } else if(dxVersion <= 7 && conv) {
260 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
261 } else {
262 object->Flags |= VBFLAG_CREATEVBO;
264 return WINED3D_OK;
267 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
268 GLenum error, glUsage;
269 TRACE("Creating VBO for Index Buffer %p\n", object);
271 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
272 * restored on the next draw
274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
276 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
277 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
278 ENTER_GL();
280 while(glGetError());
282 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
283 error = glGetError();
284 if(error != GL_NO_ERROR || object->vbo == 0) {
285 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
286 goto out;
289 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
290 error = glGetError();
291 if(error != GL_NO_ERROR) {
292 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
293 goto out;
296 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
297 * copy no readback will be needed
299 glUsage = GL_STATIC_DRAW_ARB;
300 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
301 error = glGetError();
302 if(error != GL_NO_ERROR) {
303 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
304 goto out;
306 LEAVE_GL();
307 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
308 return;
310 out:
311 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
312 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
313 LEAVE_GL();
314 object->vbo = 0;
317 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
318 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
319 HANDLE *sharedHandle, IUnknown *parent) {
320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
321 IWineD3DIndexBufferImpl *object;
322 TRACE("(%p) Creating index buffer\n", This);
324 /* Allocate the storage for the device */
325 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
327 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
328 CreateIndexBufferVBO(This, object);
331 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
332 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
333 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
335 return WINED3D_OK;
338 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
341 IWineD3DStateBlockImpl *object;
342 int i, j;
343 HRESULT temp_result;
345 D3DCREATEOBJECTINSTANCE(object, StateBlock)
346 object->blockType = Type;
348 for(i = 0; i < LIGHTMAP_SIZE; i++) {
349 list_init(&object->lightMap[i]);
352 /* Special case - Used during initialization to produce a placeholder stateblock
353 so other functions called can update a state block */
354 if (Type == WINED3DSBT_INIT) {
355 /* Don't bother increasing the reference count otherwise a device will never
356 be freed due to circular dependencies */
357 return WINED3D_OK;
360 temp_result = allocate_shader_constants(object);
361 if (WINED3D_OK != temp_result)
362 return temp_result;
364 /* Otherwise, might as well set the whole state block to the appropriate values */
365 if (This->stateBlock != NULL)
366 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
367 else
368 memset(object->streamFreq, 1, sizeof(object->streamFreq));
370 /* Reset the ref and type after kludging it */
371 object->wineD3DDevice = This;
372 object->ref = 1;
373 object->blockType = Type;
375 TRACE("Updating changed flags appropriate for type %d\n", Type);
377 if (Type == WINED3DSBT_ALL) {
379 TRACE("ALL => Pretend everything has changed\n");
380 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
382 /* Lights are not part of the changed / set structure */
383 for(j = 0; j < LIGHTMAP_SIZE; j++) {
384 struct list *e;
385 LIST_FOR_EACH(e, &object->lightMap[j]) {
386 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
387 light->changed = TRUE;
388 light->enabledChanged = TRUE;
391 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
392 object->contained_render_states[j - 1] = j;
394 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
395 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
396 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
397 object->contained_transform_states[j - 1] = j;
399 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
400 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
401 object->contained_vs_consts_f[j] = j;
403 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
404 for(j = 0; j < MAX_CONST_I; j++) {
405 object->contained_vs_consts_i[j] = j;
407 object->num_contained_vs_consts_i = MAX_CONST_I;
408 for(j = 0; j < MAX_CONST_B; j++) {
409 object->contained_vs_consts_b[j] = j;
411 object->num_contained_vs_consts_b = MAX_CONST_B;
412 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
413 object->contained_ps_consts_f[j] = j;
415 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
416 for(j = 0; j < MAX_CONST_I; j++) {
417 object->contained_ps_consts_i[j] = j;
419 object->num_contained_ps_consts_i = MAX_CONST_I;
420 for(j = 0; j < MAX_CONST_B; j++) {
421 object->contained_ps_consts_b[j] = j;
423 object->num_contained_ps_consts_b = MAX_CONST_B;
424 for(i = 0; i < MAX_TEXTURES; i++) {
425 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
426 object->contained_tss_states[object->num_contained_tss_states].stage = i;
427 object->contained_tss_states[object->num_contained_tss_states].state = j;
428 object->num_contained_tss_states++;
431 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
432 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
433 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
434 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
435 object->num_contained_sampler_states++;
439 for(i = 0; i < MAX_STREAMS; i++) {
440 if(object->streamSource[i]) {
441 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
444 if(object->pIndexData) {
445 IWineD3DIndexBuffer_AddRef(object->pIndexData);
447 if(object->vertexShader) {
448 IWineD3DVertexShader_AddRef(object->vertexShader);
450 if(object->pixelShader) {
451 IWineD3DPixelShader_AddRef(object->pixelShader);
454 } else if (Type == WINED3DSBT_PIXELSTATE) {
456 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
457 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
459 object->changed.pixelShader = TRUE;
461 /* Pixel Shader Constants */
462 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
463 object->contained_ps_consts_f[i] = i;
464 object->changed.pixelShaderConstantsF[i] = TRUE;
466 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
467 for (i = 0; i < MAX_CONST_B; ++i) {
468 object->contained_ps_consts_b[i] = i;
469 object->changed.pixelShaderConstantsB[i] = TRUE;
471 object->num_contained_ps_consts_b = MAX_CONST_B;
472 for (i = 0; i < MAX_CONST_I; ++i) {
473 object->contained_ps_consts_i[i] = i;
474 object->changed.pixelShaderConstantsI[i] = TRUE;
476 object->num_contained_ps_consts_i = MAX_CONST_I;
478 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
479 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
480 object->contained_render_states[i] = SavedPixelStates_R[i];
482 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
483 for (j = 0; j < MAX_TEXTURES; j++) {
484 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
485 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
486 object->contained_tss_states[object->num_contained_tss_states].stage = j;
487 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
488 object->num_contained_tss_states++;
491 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
492 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
493 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
494 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
495 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
496 object->num_contained_sampler_states++;
499 if(object->pixelShader) {
500 IWineD3DPixelShader_AddRef(object->pixelShader);
503 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
504 * on them. This makes releasing the buffer easier
506 for(i = 0; i < MAX_STREAMS; i++) {
507 object->streamSource[i] = NULL;
509 object->pIndexData = NULL;
510 object->vertexShader = NULL;
512 } else if (Type == WINED3DSBT_VERTEXSTATE) {
514 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
515 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
517 object->changed.vertexShader = TRUE;
519 /* Vertex Shader Constants */
520 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
521 object->changed.vertexShaderConstantsF[i] = TRUE;
522 object->contained_vs_consts_f[i] = i;
524 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
525 for (i = 0; i < MAX_CONST_B; ++i) {
526 object->changed.vertexShaderConstantsB[i] = TRUE;
527 object->contained_vs_consts_b[i] = i;
529 object->num_contained_vs_consts_b = MAX_CONST_B;
530 for (i = 0; i < MAX_CONST_I; ++i) {
531 object->changed.vertexShaderConstantsI[i] = TRUE;
532 object->contained_vs_consts_i[i] = i;
534 object->num_contained_vs_consts_i = MAX_CONST_I;
535 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
536 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
537 object->contained_render_states[i] = SavedVertexStates_R[i];
539 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
540 for (j = 0; j < MAX_TEXTURES; j++) {
541 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
542 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
543 object->contained_tss_states[object->num_contained_tss_states].stage = j;
544 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
545 object->num_contained_tss_states++;
548 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
549 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
550 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
551 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
552 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
553 object->num_contained_sampler_states++;
557 for(j = 0; j < LIGHTMAP_SIZE; j++) {
558 struct list *e;
559 LIST_FOR_EACH(e, &object->lightMap[j]) {
560 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
561 light->changed = TRUE;
562 light->enabledChanged = TRUE;
566 for(i = 0; i < MAX_STREAMS; i++) {
567 if(object->streamSource[i]) {
568 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
571 if(object->vertexShader) {
572 IWineD3DVertexShader_AddRef(object->vertexShader);
574 object->pIndexData = NULL;
575 object->pixelShader = NULL;
576 } else {
577 FIXME("Unrecognized state block type %d\n", Type);
580 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
581 return WINED3D_OK;
584 /* ************************************
585 MSDN:
586 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
588 Discard
589 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
591 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.
593 ******************************** */
595 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) {
596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
597 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
598 unsigned int Size = 1;
599 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
600 TRACE("(%p) Create surface\n",This);
602 /** FIXME: Check ranges on the inputs are valid
603 * MSDN
604 * MultisampleQuality
605 * [in] Quality level. The valid range is between zero and one less than the level
606 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
607 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
608 * values of paired render targets, depth stencil surfaces, and the MultiSample type
609 * must all match.
610 *******************************/
614 * TODO: Discard MSDN
615 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
617 * If this flag is set, the contents of the depth stencil buffer will be
618 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
619 * with a different depth surface.
621 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
622 ***************************/
624 if(MultisampleQuality > 0) {
625 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
626 MultisampleQuality=0;
629 /** FIXME: Check that the format is supported
630 * by the device.
631 *******************************/
633 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
634 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
635 * space!
636 *********************************/
637 if (WINED3DFMT_UNKNOWN == Format) {
638 Size = 0;
639 } else if (Format == WINED3DFMT_DXT1) {
640 /* DXT1 is half byte per pixel */
641 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
643 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
644 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
645 Format == WINED3DFMT_ATI2N) {
646 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
647 } else {
648 /* The pitch is a multiple of 4 bytes */
649 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
650 Size *= Height;
653 /** Create and initialise the surface resource **/
654 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
655 /* "Standalone" surface */
656 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
658 object->currentDesc.Width = Width;
659 object->currentDesc.Height = Height;
660 object->currentDesc.MultiSampleType = MultiSample;
661 object->currentDesc.MultiSampleQuality = MultisampleQuality;
662 object->glDescription.level = Level;
664 /* Flags */
665 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
666 object->Flags |= Discard ? SFLAG_DISCARD : 0;
667 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
668 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
671 if (WINED3DFMT_UNKNOWN != Format) {
672 object->bytesPerPixel = tableEntry->bpp;
673 } else {
674 object->bytesPerPixel = 0;
677 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
679 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
681 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
682 * this function is too deep to need to care about things like this.
683 * Levels need to be checked too, and possibly Type since they all affect what can be done.
684 * ****************************************/
685 switch(Pool) {
686 case WINED3DPOOL_SCRATCH:
687 if(!Lockable)
688 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
689 "which are mutually exclusive, setting lockable to TRUE\n");
690 Lockable = TRUE;
691 break;
692 case WINED3DPOOL_SYSTEMMEM:
693 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
694 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
695 case WINED3DPOOL_MANAGED:
696 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
697 "Usage of DYNAMIC which are mutually exclusive, not doing "
698 "anything just telling you.\n");
699 break;
700 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
701 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
702 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
703 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
704 break;
705 default:
706 FIXME("(%p) Unknown pool %d\n", This, Pool);
707 break;
710 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
711 FIXME("Trying to create a render target that isn't in the default pool\n");
714 /* mark the texture as dirty so that it gets loaded first time around*/
715 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
716 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
717 This, Width, Height, Format, debug_d3dformat(Format),
718 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
720 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
721 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
722 This->ddraw_primary = (IWineD3DSurface *) object;
724 /* Look at the implementation and set the correct Vtable */
725 switch(Impl) {
726 case SURFACE_OPENGL:
727 /* Check if a 3D adapter is available when creating gl surfaces */
728 if(!This->adapter) {
729 ERR("OpenGL surfaces are not available without opengl\n");
730 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
731 HeapFree(GetProcessHeap(), 0, object);
732 return WINED3DERR_NOTAVAILABLE;
734 break;
736 case SURFACE_GDI:
737 object->lpVtbl = &IWineGDISurface_Vtbl;
738 break;
740 default:
741 /* To be sure to catch this */
742 ERR("Unknown requested surface implementation %d!\n", Impl);
743 IWineD3DSurface_Release((IWineD3DSurface *) object);
744 return WINED3DERR_INVALIDCALL;
747 list_init(&object->renderbuffers);
749 /* Call the private setup routine */
750 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
754 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
755 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
756 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
757 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
760 IWineD3DTextureImpl *object;
761 unsigned int i;
762 UINT tmpW;
763 UINT tmpH;
764 HRESULT hr;
765 unsigned int pow2Width;
766 unsigned int pow2Height;
767 const GlPixelFormatDesc *glDesc;
768 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
770 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
771 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
772 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
774 /* TODO: It should only be possible to create textures for formats
775 that are reported as supported */
776 if (WINED3DFMT_UNKNOWN >= Format) {
777 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
778 return WINED3DERR_INVALIDCALL;
781 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
782 D3DINITIALIZEBASETEXTURE(object->baseTexture);
783 object->width = Width;
784 object->height = Height;
786 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
787 object->baseTexture.minMipLookup = &minMipLookup;
788 object->baseTexture.magLookup = &magLookup;
789 } else {
790 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
791 object->baseTexture.magLookup = &magLookup_noFilter;
794 /** Non-power2 support **/
795 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
796 pow2Width = Width;
797 pow2Height = Height;
798 } else {
799 /* Find the nearest pow2 match */
800 pow2Width = pow2Height = 1;
801 while (pow2Width < Width) pow2Width <<= 1;
802 while (pow2Height < Height) pow2Height <<= 1;
804 if(pow2Width != Width || pow2Height != Height) {
805 if(Levels > 1) {
806 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
807 HeapFree(GetProcessHeap(), 0, object);
808 *ppTexture = NULL;
809 return WINED3DERR_INVALIDCALL;
810 } else {
811 Levels = 1;
816 /** FIXME: add support for real non-power-two if it's provided by the video card **/
817 /* Precalculated scaling for 'faked' non power of two texture coords.
818 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
819 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
820 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
822 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
823 object->baseTexture.pow2Matrix[0] = 1.0;
824 object->baseTexture.pow2Matrix[5] = 1.0;
825 object->baseTexture.pow2Matrix[10] = 1.0;
826 object->baseTexture.pow2Matrix[15] = 1.0;
827 object->target = GL_TEXTURE_2D;
828 object->cond_np2 = TRUE;
829 pow2Width = Width;
830 pow2Height = Height;
831 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
832 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
833 (Width != pow2Width || Height != pow2Height) &&
834 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
836 object->baseTexture.pow2Matrix[0] = (float)Width;
837 object->baseTexture.pow2Matrix[5] = (float)Height;
838 object->baseTexture.pow2Matrix[10] = 1.0;
839 object->baseTexture.pow2Matrix[15] = 1.0;
840 object->target = GL_TEXTURE_RECTANGLE_ARB;
841 object->cond_np2 = TRUE;
842 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
843 } else {
844 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
845 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
846 object->baseTexture.pow2Matrix[10] = 1.0;
847 object->baseTexture.pow2Matrix[15] = 1.0;
848 object->target = GL_TEXTURE_2D;
849 object->cond_np2 = FALSE;
851 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
853 /* Calculate levels for mip mapping */
854 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
855 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
856 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
857 return WINED3DERR_INVALIDCALL;
859 if(Levels > 1) {
860 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
861 return WINED3DERR_INVALIDCALL;
863 object->baseTexture.levels = 1;
864 } else if (Levels == 0) {
865 TRACE("calculating levels %d\n", object->baseTexture.levels);
866 object->baseTexture.levels++;
867 tmpW = Width;
868 tmpH = Height;
869 while (tmpW > 1 || tmpH > 1) {
870 tmpW = max(1, tmpW >> 1);
871 tmpH = max(1, tmpH >> 1);
872 object->baseTexture.levels++;
874 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
877 /* Generate all the surfaces */
878 tmpW = Width;
879 tmpH = Height;
880 for (i = 0; i < object->baseTexture.levels; i++)
882 /* use the callback to create the texture surface */
883 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
884 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
885 FIXME("Failed to create surface %p\n", object);
886 /* clean up */
887 object->surfaces[i] = NULL;
888 IWineD3DTexture_Release((IWineD3DTexture *)object);
890 *ppTexture = NULL;
891 return hr;
894 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
895 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
896 /* calculate the next mipmap level */
897 tmpW = max(1, tmpW >> 1);
898 tmpH = max(1, tmpH >> 1);
900 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
902 TRACE("(%p) : Created texture %p\n", This, object);
903 return WINED3D_OK;
906 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
907 UINT Width, UINT Height, UINT Depth,
908 UINT Levels, DWORD Usage,
909 WINED3DFORMAT Format, WINED3DPOOL Pool,
910 IWineD3DVolumeTexture **ppVolumeTexture,
911 HANDLE *pSharedHandle, IUnknown *parent,
912 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
915 IWineD3DVolumeTextureImpl *object;
916 unsigned int i;
917 UINT tmpW;
918 UINT tmpH;
919 UINT tmpD;
920 const GlPixelFormatDesc *glDesc;
922 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
924 /* TODO: It should only be possible to create textures for formats
925 that are reported as supported */
926 if (WINED3DFMT_UNKNOWN >= Format) {
927 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
928 return WINED3DERR_INVALIDCALL;
930 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
931 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
932 return WINED3DERR_INVALIDCALL;
935 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
936 D3DINITIALIZEBASETEXTURE(object->baseTexture);
938 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
939 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
941 object->width = Width;
942 object->height = Height;
943 object->depth = Depth;
945 /* Is NP2 support for volumes needed? */
946 object->baseTexture.pow2Matrix[ 0] = 1.0;
947 object->baseTexture.pow2Matrix[ 5] = 1.0;
948 object->baseTexture.pow2Matrix[10] = 1.0;
949 object->baseTexture.pow2Matrix[15] = 1.0;
951 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
952 object->baseTexture.minMipLookup = &minMipLookup;
953 object->baseTexture.magLookup = &magLookup;
954 } else {
955 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
956 object->baseTexture.magLookup = &magLookup_noFilter;
959 /* Calculate levels for mip mapping */
960 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
961 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
962 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
963 return WINED3DERR_INVALIDCALL;
965 if(Levels > 1) {
966 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
967 return WINED3DERR_INVALIDCALL;
969 Levels = 1;
970 } else if (Levels == 0) {
971 object->baseTexture.levels++;
972 tmpW = Width;
973 tmpH = Height;
974 tmpD = Depth;
975 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
976 tmpW = max(1, tmpW >> 1);
977 tmpH = max(1, tmpH >> 1);
978 tmpD = max(1, tmpD >> 1);
979 object->baseTexture.levels++;
981 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
984 /* Generate all the surfaces */
985 tmpW = Width;
986 tmpH = Height;
987 tmpD = Depth;
989 for (i = 0; i < object->baseTexture.levels; i++)
991 HRESULT hr;
992 /* Create the volume */
993 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
994 &object->volumes[i], pSharedHandle);
996 if(FAILED(hr)) {
997 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
998 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
999 *ppVolumeTexture = NULL;
1000 return hr;
1003 /* Set its container to this object */
1004 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1006 /* calculate the next mipmap level */
1007 tmpW = max(1, tmpW >> 1);
1008 tmpH = max(1, tmpH >> 1);
1009 tmpD = max(1, tmpD >> 1);
1011 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1013 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1014 TRACE("(%p) : Created volume texture %p\n", This, object);
1015 return WINED3D_OK;
1018 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1019 UINT Width, UINT Height, UINT Depth,
1020 DWORD Usage,
1021 WINED3DFORMAT Format, WINED3DPOOL Pool,
1022 IWineD3DVolume** ppVolume,
1023 HANDLE* pSharedHandle, IUnknown *parent) {
1025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1026 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1027 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1029 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1030 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1031 return WINED3DERR_INVALIDCALL;
1034 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1036 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1037 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1039 object->currentDesc.Width = Width;
1040 object->currentDesc.Height = Height;
1041 object->currentDesc.Depth = Depth;
1042 object->bytesPerPixel = formatDesc->bpp;
1044 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1045 object->lockable = TRUE;
1046 object->locked = FALSE;
1047 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1048 object->dirty = TRUE;
1050 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1053 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1054 UINT Levels, DWORD Usage,
1055 WINED3DFORMAT Format, WINED3DPOOL Pool,
1056 IWineD3DCubeTexture **ppCubeTexture,
1057 HANDLE *pSharedHandle, IUnknown *parent,
1058 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1061 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1062 unsigned int i, j;
1063 UINT tmpW;
1064 HRESULT hr;
1065 unsigned int pow2EdgeLength = EdgeLength;
1066 const GlPixelFormatDesc *glDesc;
1067 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1069 /* TODO: It should only be possible to create textures for formats
1070 that are reported as supported */
1071 if (WINED3DFMT_UNKNOWN >= Format) {
1072 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1073 return WINED3DERR_INVALIDCALL;
1076 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1077 WARN("(%p) : Tried to create not supported cube texture\n", This);
1078 return WINED3DERR_INVALIDCALL;
1081 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1082 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1084 TRACE("(%p) Create Cube Texture\n", This);
1086 /** Non-power2 support **/
1088 /* Find the nearest pow2 match */
1089 pow2EdgeLength = 1;
1090 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1092 object->edgeLength = EdgeLength;
1093 /* TODO: support for native non-power 2 */
1094 /* Precalculated scaling for 'faked' non power of two texture coords */
1095 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1096 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1097 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1098 object->baseTexture.pow2Matrix[15] = 1.0;
1100 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1101 object->baseTexture.minMipLookup = &minMipLookup;
1102 object->baseTexture.magLookup = &magLookup;
1103 } else {
1104 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
1105 object->baseTexture.magLookup = &magLookup_noFilter;
1108 /* Calculate levels for mip mapping */
1109 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1110 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1111 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1112 HeapFree(GetProcessHeap(), 0, object);
1113 *ppCubeTexture = NULL;
1115 return WINED3DERR_INVALIDCALL;
1117 if(Levels > 1) {
1118 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1119 HeapFree(GetProcessHeap(), 0, object);
1120 *ppCubeTexture = NULL;
1122 return WINED3DERR_INVALIDCALL;
1124 Levels = 1;
1125 } else if (Levels == 0) {
1126 object->baseTexture.levels++;
1127 tmpW = EdgeLength;
1128 while (tmpW > 1) {
1129 tmpW = max(1, tmpW >> 1);
1130 object->baseTexture.levels++;
1132 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1135 /* Generate all the surfaces */
1136 tmpW = EdgeLength;
1137 for (i = 0; i < object->baseTexture.levels; i++) {
1139 /* Create the 6 faces */
1140 for (j = 0; j < 6; j++) {
1142 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1143 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1145 if(hr!= WINED3D_OK) {
1146 /* clean up */
1147 int k;
1148 int l;
1149 for (l = 0; l < j; l++) {
1150 IWineD3DSurface_Release(object->surfaces[l][i]);
1152 for (k = 0; k < i; k++) {
1153 for (l = 0; l < 6; l++) {
1154 IWineD3DSurface_Release(object->surfaces[l][k]);
1158 FIXME("(%p) Failed to create surface\n",object);
1159 HeapFree(GetProcessHeap(),0,object);
1160 *ppCubeTexture = NULL;
1161 return hr;
1163 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1164 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1166 tmpW = max(1, tmpW >> 1);
1168 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1170 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1171 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1172 return WINED3D_OK;
1175 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1177 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1178 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1179 const IWineD3DQueryVtbl *vtable;
1181 /* Just a check to see if we support this type of query */
1182 switch(Type) {
1183 case WINED3DQUERYTYPE_OCCLUSION:
1184 TRACE("(%p) occlusion query\n", This);
1185 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1186 hr = WINED3D_OK;
1187 else
1188 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1190 vtable = &IWineD3DOcclusionQuery_Vtbl;
1191 break;
1193 case WINED3DQUERYTYPE_EVENT:
1194 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1195 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1196 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1198 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1200 vtable = &IWineD3DEventQuery_Vtbl;
1201 hr = WINED3D_OK;
1202 break;
1204 case WINED3DQUERYTYPE_VCACHE:
1205 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1206 case WINED3DQUERYTYPE_VERTEXSTATS:
1207 case WINED3DQUERYTYPE_TIMESTAMP:
1208 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1209 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1210 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1211 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1212 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1213 case WINED3DQUERYTYPE_PIXELTIMINGS:
1214 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1215 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1216 default:
1217 /* Use the base Query vtable until we have a special one for each query */
1218 vtable = &IWineD3DQuery_Vtbl;
1219 FIXME("(%p) Unhandled query type %d\n", This, Type);
1221 if(NULL == ppQuery || hr != WINED3D_OK) {
1222 return hr;
1225 D3DCREATEOBJECTINSTANCE(object, Query)
1226 object->lpVtbl = vtable;
1227 object->type = Type;
1228 object->state = QUERY_CREATED;
1229 /* allocated the 'extended' data based on the type of query requested */
1230 switch(Type){
1231 case WINED3DQUERYTYPE_OCCLUSION:
1232 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1233 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1235 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1236 TRACE("(%p) Allocating data for an occlusion query\n", This);
1237 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1238 break;
1240 case WINED3DQUERYTYPE_EVENT:
1241 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1242 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1244 if(GL_SUPPORT(APPLE_FENCE)) {
1245 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1246 checkGLcall("glGenFencesAPPLE");
1247 } else if(GL_SUPPORT(NV_FENCE)) {
1248 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1249 checkGLcall("glGenFencesNV");
1251 break;
1253 case WINED3DQUERYTYPE_VCACHE:
1254 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1255 case WINED3DQUERYTYPE_VERTEXSTATS:
1256 case WINED3DQUERYTYPE_TIMESTAMP:
1257 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1258 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1259 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1260 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1261 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1262 case WINED3DQUERYTYPE_PIXELTIMINGS:
1263 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1264 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1265 default:
1266 object->extendedData = 0;
1267 FIXME("(%p) Unhandled query type %d\n",This , Type);
1269 TRACE("(%p) : Created Query %p\n", This, object);
1270 return WINED3D_OK;
1273 /*****************************************************************************
1274 * IWineD3DDeviceImpl_SetupFullscreenWindow
1276 * Helper function that modifies a HWND's Style and ExStyle for proper
1277 * fullscreen use.
1279 * Params:
1280 * iface: Pointer to the IWineD3DDevice interface
1281 * window: Window to setup
1283 *****************************************************************************/
1284 static LONG fullscreen_style(LONG orig_style) {
1285 LONG style = orig_style;
1286 style &= ~WS_CAPTION;
1287 style &= ~WS_THICKFRAME;
1289 /* Make sure the window is managed, otherwise we won't get keyboard input */
1290 style |= WS_POPUP | WS_SYSMENU;
1292 return style;
1295 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1296 LONG exStyle = orig_exStyle;
1298 /* Filter out window decorations */
1299 exStyle &= ~WS_EX_WINDOWEDGE;
1300 exStyle &= ~WS_EX_CLIENTEDGE;
1302 return exStyle;
1305 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1308 LONG style, exStyle;
1309 /* Don't do anything if an original style is stored.
1310 * That shouldn't happen
1312 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1313 if (This->style || This->exStyle) {
1314 ERR("(%p): Want to change the window parameters of HWND %p, but "
1315 "another style is stored for restoration afterwards\n", This, window);
1318 /* Get the parameters and save them */
1319 style = GetWindowLongW(window, GWL_STYLE);
1320 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1321 This->style = style;
1322 This->exStyle = exStyle;
1324 style = fullscreen_style(style);
1325 exStyle = fullscreen_exStyle(exStyle);
1327 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1328 This->style, This->exStyle, style, exStyle);
1330 SetWindowLongW(window, GWL_STYLE, style);
1331 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1333 /* Inform the window about the update. */
1334 SetWindowPos(window, HWND_TOP, 0, 0,
1335 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1336 ShowWindow(window, SW_NORMAL);
1339 /*****************************************************************************
1340 * IWineD3DDeviceImpl_RestoreWindow
1342 * Helper function that restores a windows' properties when taking it out
1343 * of fullscreen mode
1345 * Params:
1346 * iface: Pointer to the IWineD3DDevice interface
1347 * window: Window to setup
1349 *****************************************************************************/
1350 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1352 LONG style, exStyle;
1354 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1355 * switch, do nothing
1357 if (!This->style && !This->exStyle) return;
1359 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1360 This, window, This->style, This->exStyle);
1362 style = GetWindowLongW(window, GWL_STYLE);
1363 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1365 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1366 * Some applications change it before calling Reset() when switching between windowed and
1367 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1369 if(style == fullscreen_style(This->style) &&
1370 exStyle == fullscreen_style(This->exStyle)) {
1371 SetWindowLongW(window, GWL_STYLE, This->style);
1372 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1375 /* Delete the old values */
1376 This->style = 0;
1377 This->exStyle = 0;
1379 /* Inform the window about the update */
1380 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1381 0, 0, 0, 0, /* Pos, Size, ignored */
1382 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1385 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1386 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1387 IUnknown* parent,
1388 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1389 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1392 HDC hDc;
1393 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1394 HRESULT hr = WINED3D_OK;
1395 IUnknown *bufferParent;
1396 BOOL displaymode_set = FALSE;
1397 WINED3DDISPLAYMODE Mode;
1398 const StaticPixelFormatDesc *formatDesc;
1400 TRACE("(%p) : Created Additional Swap Chain\n", This);
1402 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1403 * does a device hold a reference to a swap chain giving them a lifetime of the device
1404 * or does the swap chain notify the device of its destruction.
1405 *******************************/
1407 /* Check the params */
1408 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1409 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1410 return WINED3DERR_INVALIDCALL;
1411 } else if (pPresentationParameters->BackBufferCount > 1) {
1412 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");
1415 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1417 /*********************
1418 * Lookup the window Handle and the relating X window handle
1419 ********************/
1421 /* Setup hwnd we are using, plus which display this equates to */
1422 object->win_handle = pPresentationParameters->hDeviceWindow;
1423 if (!object->win_handle) {
1424 object->win_handle = This->createParms.hFocusWindow;
1426 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1428 hDc = GetDC(object->win_handle);
1429 TRACE("Using hDc %p\n", hDc);
1431 if (NULL == hDc) {
1432 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1433 return WINED3DERR_NOTAVAILABLE;
1436 /* Get info on the current display setup */
1437 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1438 object->orig_width = Mode.Width;
1439 object->orig_height = Mode.Height;
1440 object->orig_fmt = Mode.Format;
1441 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1443 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1444 * then the corresponding dimension of the client area of the hDeviceWindow
1445 * (or the focus window, if hDeviceWindow is NULL) is taken.
1446 **********************/
1448 if (pPresentationParameters->Windowed &&
1449 ((pPresentationParameters->BackBufferWidth == 0) ||
1450 (pPresentationParameters->BackBufferHeight == 0) ||
1451 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1453 RECT Rect;
1454 GetClientRect(object->win_handle, &Rect);
1456 if (pPresentationParameters->BackBufferWidth == 0) {
1457 pPresentationParameters->BackBufferWidth = Rect.right;
1458 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1460 if (pPresentationParameters->BackBufferHeight == 0) {
1461 pPresentationParameters->BackBufferHeight = Rect.bottom;
1462 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1464 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1465 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1466 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1470 /* Put the correct figures in the presentation parameters */
1471 TRACE("Copying across presentation parameters\n");
1472 object->presentParms = *pPresentationParameters;
1474 TRACE("calling rendertarget CB\n");
1475 hr = D3DCB_CreateRenderTarget(This->parent,
1476 parent,
1477 object->presentParms.BackBufferWidth,
1478 object->presentParms.BackBufferHeight,
1479 object->presentParms.BackBufferFormat,
1480 object->presentParms.MultiSampleType,
1481 object->presentParms.MultiSampleQuality,
1482 TRUE /* Lockable */,
1483 &object->frontBuffer,
1484 NULL /* pShared (always null)*/);
1485 if (object->frontBuffer != NULL) {
1486 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1487 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1488 } else {
1489 ERR("Failed to create the front buffer\n");
1490 goto error;
1493 /*********************
1494 * Windowed / Fullscreen
1495 *******************/
1498 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1499 * so we should really check to see if there is a fullscreen swapchain already
1500 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1501 **************************************/
1503 if (!pPresentationParameters->Windowed) {
1504 WINED3DDISPLAYMODE mode;
1507 /* Change the display settings */
1508 mode.Width = pPresentationParameters->BackBufferWidth;
1509 mode.Height = pPresentationParameters->BackBufferHeight;
1510 mode.Format = pPresentationParameters->BackBufferFormat;
1511 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1513 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1514 displaymode_set = TRUE;
1515 IWineD3DDevice_SetFullscreen(iface, TRUE);
1519 * Create an opengl context for the display visual
1520 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1521 * use different properties after that point in time. FIXME: How to handle when requested format
1522 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1523 * it chooses is identical to the one already being used!
1524 **********************************/
1525 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1527 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1528 if(!object->context)
1529 return E_OUTOFMEMORY;
1530 object->num_contexts = 1;
1532 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1533 if (!object->context[0]) {
1534 ERR("Failed to create a new context\n");
1535 hr = WINED3DERR_NOTAVAILABLE;
1536 goto error;
1537 } else {
1538 TRACE("Context created (HWND=%p, glContext=%p)\n",
1539 object->win_handle, object->context[0]->glCtx);
1542 /*********************
1543 * Create the back, front and stencil buffers
1544 *******************/
1545 if(object->presentParms.BackBufferCount > 0) {
1546 int i;
1548 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1549 if(!object->backBuffer) {
1550 ERR("Out of memory\n");
1551 hr = E_OUTOFMEMORY;
1552 goto error;
1555 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1556 TRACE("calling rendertarget CB\n");
1557 hr = D3DCB_CreateRenderTarget(This->parent,
1558 parent,
1559 object->presentParms.BackBufferWidth,
1560 object->presentParms.BackBufferHeight,
1561 object->presentParms.BackBufferFormat,
1562 object->presentParms.MultiSampleType,
1563 object->presentParms.MultiSampleQuality,
1564 TRUE /* Lockable */,
1565 &object->backBuffer[i],
1566 NULL /* pShared (always null)*/);
1567 if(hr == WINED3D_OK && object->backBuffer[i]) {
1568 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1569 } else {
1570 ERR("Cannot create new back buffer\n");
1571 goto error;
1573 ENTER_GL();
1574 glDrawBuffer(GL_BACK);
1575 checkGLcall("glDrawBuffer(GL_BACK)");
1576 LEAVE_GL();
1578 } else {
1579 object->backBuffer = NULL;
1581 /* Single buffering - draw to front buffer */
1582 ENTER_GL();
1583 glDrawBuffer(GL_FRONT);
1584 checkGLcall("glDrawBuffer(GL_FRONT)");
1585 LEAVE_GL();
1588 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1589 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1590 TRACE("Creating depth stencil buffer\n");
1591 if (This->auto_depth_stencil_buffer == NULL ) {
1592 hr = D3DCB_CreateDepthStencil(This->parent,
1593 parent,
1594 object->presentParms.BackBufferWidth,
1595 object->presentParms.BackBufferHeight,
1596 object->presentParms.AutoDepthStencilFormat,
1597 object->presentParms.MultiSampleType,
1598 object->presentParms.MultiSampleQuality,
1599 FALSE /* FIXME: Discard */,
1600 &This->auto_depth_stencil_buffer,
1601 NULL /* pShared (always null)*/ );
1602 if (This->auto_depth_stencil_buffer != NULL)
1603 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1606 /** TODO: A check on width, height and multisample types
1607 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1608 ****************************/
1609 object->wantsDepthStencilBuffer = TRUE;
1610 } else {
1611 object->wantsDepthStencilBuffer = FALSE;
1614 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1616 TRACE("Created swapchain %p\n", object);
1617 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1618 return WINED3D_OK;
1620 error:
1621 if (displaymode_set) {
1622 DEVMODEW devmode;
1623 RECT clip_rc;
1625 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1626 ClipCursor(NULL);
1628 /* Change the display settings */
1629 memset(&devmode, 0, sizeof(devmode));
1630 devmode.dmSize = sizeof(devmode);
1631 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1632 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1633 devmode.dmPelsWidth = object->orig_width;
1634 devmode.dmPelsHeight = object->orig_height;
1635 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1638 if (object->backBuffer) {
1639 int i;
1640 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1641 if(object->backBuffer[i]) {
1642 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1643 IUnknown_Release(bufferParent); /* once for the get parent */
1644 if (IUnknown_Release(bufferParent) > 0) {
1645 FIXME("(%p) Something's still holding the back buffer\n",This);
1649 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1650 object->backBuffer = NULL;
1652 if(object->context[0])
1653 DestroyContext(This, object->context[0]);
1654 if(object->frontBuffer) {
1655 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1656 IUnknown_Release(bufferParent); /* once for the get parent */
1657 if (IUnknown_Release(bufferParent) > 0) {
1658 FIXME("(%p) Something's still holding the front buffer\n",This);
1661 HeapFree(GetProcessHeap(), 0, object);
1662 return hr;
1665 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1666 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1668 TRACE("(%p)\n", This);
1670 return This->NumberOfSwapChains;
1673 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1675 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1677 if(iSwapChain < This->NumberOfSwapChains) {
1678 *pSwapChain = This->swapchains[iSwapChain];
1679 IWineD3DSwapChain_AddRef(*pSwapChain);
1680 TRACE("(%p) returning %p\n", This, *pSwapChain);
1681 return WINED3D_OK;
1682 } else {
1683 TRACE("Swapchain out of range\n");
1684 *pSwapChain = NULL;
1685 return WINED3DERR_INVALIDCALL;
1689 /*****
1690 * Vertex Declaration
1691 *****/
1692 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1693 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1695 IWineD3DVertexDeclarationImpl *object = NULL;
1696 HRESULT hr = WINED3D_OK;
1698 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1699 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1701 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1703 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1704 if(FAILED(hr)) {
1705 *ppVertexDeclaration = NULL;
1706 HeapFree(GetProcessHeap(), 0, object);
1709 return hr;
1712 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1713 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1715 unsigned int idx, idx2;
1716 unsigned int offset;
1717 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1718 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1719 BOOL has_blend_idx = has_blend &&
1720 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1721 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1722 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1723 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1724 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1725 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1726 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1728 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1729 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1731 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1732 WINED3DVERTEXELEMENT *elements = NULL;
1734 unsigned int size;
1735 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1736 if (has_blend_idx) num_blends--;
1738 /* Compute declaration size */
1739 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1740 has_psize + has_diffuse + has_specular + num_textures + 1;
1742 /* convert the declaration */
1743 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1744 if (!elements)
1745 return 0;
1747 elements[size-1] = end_element;
1748 idx = 0;
1749 if (has_pos) {
1750 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1751 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1752 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1754 else {
1755 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1756 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1758 elements[idx].UsageIndex = 0;
1759 idx++;
1761 if (has_blend && (num_blends > 0)) {
1762 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1763 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1764 else
1765 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1766 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1767 elements[idx].UsageIndex = 0;
1768 idx++;
1770 if (has_blend_idx) {
1771 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1772 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1773 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1774 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1775 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1776 else
1777 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1778 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1779 elements[idx].UsageIndex = 0;
1780 idx++;
1782 if (has_normal) {
1783 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1784 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1785 elements[idx].UsageIndex = 0;
1786 idx++;
1788 if (has_psize) {
1789 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1790 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1791 elements[idx].UsageIndex = 0;
1792 idx++;
1794 if (has_diffuse) {
1795 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1796 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1797 elements[idx].UsageIndex = 0;
1798 idx++;
1800 if (has_specular) {
1801 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1802 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1803 elements[idx].UsageIndex = 1;
1804 idx++;
1806 for (idx2 = 0; idx2 < num_textures; idx2++) {
1807 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1808 switch (numcoords) {
1809 case WINED3DFVF_TEXTUREFORMAT1:
1810 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1811 break;
1812 case WINED3DFVF_TEXTUREFORMAT2:
1813 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1814 break;
1815 case WINED3DFVF_TEXTUREFORMAT3:
1816 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1817 break;
1818 case WINED3DFVF_TEXTUREFORMAT4:
1819 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1820 break;
1822 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1823 elements[idx].UsageIndex = idx2;
1824 idx++;
1827 /* Now compute offsets, and initialize the rest of the fields */
1828 for (idx = 0, offset = 0; idx < size-1; idx++) {
1829 elements[idx].Stream = 0;
1830 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1831 elements[idx].Offset = offset;
1832 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1835 *ppVertexElements = elements;
1836 return size;
1839 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1840 WINED3DVERTEXELEMENT* elements = NULL;
1841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1842 unsigned int size;
1843 DWORD hr;
1845 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1846 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1848 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1849 HeapFree(GetProcessHeap(), 0, elements);
1850 if (hr != S_OK) return hr;
1852 return WINED3D_OK;
1855 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1857 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1858 HRESULT hr = WINED3D_OK;
1859 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1860 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1862 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1864 if (vertex_declaration) {
1865 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1868 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1870 if (WINED3D_OK != hr) {
1871 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1872 IWineD3DVertexShader_Release(*ppVertexShader);
1873 return WINED3DERR_INVALIDCALL;
1875 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1877 return WINED3D_OK;
1880 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1882 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1883 HRESULT hr = WINED3D_OK;
1885 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1886 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1887 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1888 if (WINED3D_OK == hr) {
1889 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1890 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1891 } else {
1892 WARN("(%p) : Failed to create pixel shader\n", This);
1895 return hr;
1898 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1900 IWineD3DPaletteImpl *object;
1901 HRESULT hr;
1902 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1904 /* Create the new object */
1905 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1906 if(!object) {
1907 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1908 return E_OUTOFMEMORY;
1911 object->lpVtbl = &IWineD3DPalette_Vtbl;
1912 object->ref = 1;
1913 object->Flags = Flags;
1914 object->parent = Parent;
1915 object->wineD3DDevice = This;
1916 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1918 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1920 if(!object->hpal) {
1921 HeapFree( GetProcessHeap(), 0, object);
1922 return E_OUTOFMEMORY;
1925 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1926 if(FAILED(hr)) {
1927 IWineD3DPalette_Release((IWineD3DPalette *) object);
1928 return hr;
1931 *Palette = (IWineD3DPalette *) object;
1933 return WINED3D_OK;
1936 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1937 HBITMAP hbm;
1938 BITMAP bm;
1939 HRESULT hr;
1940 HDC dcb = NULL, dcs = NULL;
1941 WINEDDCOLORKEY colorkey;
1943 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1944 if(hbm)
1946 GetObjectA(hbm, sizeof(BITMAP), &bm);
1947 dcb = CreateCompatibleDC(NULL);
1948 if(!dcb) goto out;
1949 SelectObject(dcb, hbm);
1951 else
1953 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1954 * couldn't be loaded
1956 memset(&bm, 0, sizeof(bm));
1957 bm.bmWidth = 32;
1958 bm.bmHeight = 32;
1961 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1962 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1963 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1964 if(FAILED(hr)) {
1965 ERR("Wine logo requested, but failed to create surface\n");
1966 goto out;
1969 if(dcb) {
1970 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1971 if(FAILED(hr)) goto out;
1972 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1973 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1975 colorkey.dwColorSpaceLowValue = 0;
1976 colorkey.dwColorSpaceHighValue = 0;
1977 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1978 } else {
1979 /* Fill the surface with a white color to show that wined3d is there */
1980 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1983 out:
1984 if(dcb) {
1985 DeleteDC(dcb);
1987 if(hbm) {
1988 DeleteObject(hbm);
1990 return;
1993 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1994 unsigned int i;
1995 /* Under DirectX you can have texture stage operations even if no texture is
1996 bound, whereas opengl will only do texture operations when a valid texture is
1997 bound. We emulate this by creating dummy textures and binding them to each
1998 texture stage, but disable all stages by default. Hence if a stage is enabled
1999 then the default texture will kick in until replaced by a SetTexture call */
2000 ENTER_GL();
2002 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2003 /* The dummy texture does not have client storage backing */
2004 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2005 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2007 for (i = 0; i < GL_LIMITS(textures); i++) {
2008 GLubyte white = 255;
2010 /* Make appropriate texture active */
2011 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2012 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2013 checkGLcall("glActiveTextureARB");
2014 } else if (i > 0) {
2015 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2018 /* Generate an opengl texture name */
2019 glGenTextures(1, &This->dummyTextureName[i]);
2020 checkGLcall("glGenTextures");
2021 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2023 /* Generate a dummy 2d texture (not using 1d because they cause many
2024 * DRI drivers fall back to sw) */
2025 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2026 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2027 checkGLcall("glBindTexture");
2029 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2030 checkGLcall("glTexImage2D");
2032 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2033 /* Reenable because if supported it is enabled by default */
2034 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2035 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2038 LEAVE_GL();
2041 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2043 IWineD3DSwapChainImpl *swapchain = NULL;
2044 HRESULT hr;
2045 DWORD state;
2046 unsigned int i;
2048 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2049 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2050 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2052 /* TODO: Test if OpenGL is compiled in and loaded */
2054 TRACE("(%p) : Creating stateblock\n", This);
2055 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2056 hr = IWineD3DDevice_CreateStateBlock(iface,
2057 WINED3DSBT_INIT,
2058 (IWineD3DStateBlock **)&This->stateBlock,
2059 NULL);
2060 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2061 WARN("Failed to create stateblock\n");
2062 goto err_out;
2064 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2065 This->updateStateBlock = This->stateBlock;
2066 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2068 hr = allocate_shader_constants(This->updateStateBlock);
2069 if (WINED3D_OK != hr) {
2070 goto err_out;
2073 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2074 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2075 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2077 This->NumberOfPalettes = 1;
2078 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2079 if(!This->palettes || !This->render_targets || !This->fbo_color_attachments || !This->draw_buffers) {
2080 ERR("Out of memory!\n");
2081 goto err_out;
2083 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2084 if(!This->palettes[0]) {
2085 ERR("Out of memory!\n");
2086 goto err_out;
2088 for (i = 0; i < 256; ++i) {
2089 This->palettes[0][i].peRed = 0xFF;
2090 This->palettes[0][i].peGreen = 0xFF;
2091 This->palettes[0][i].peBlue = 0xFF;
2092 This->palettes[0][i].peFlags = 0xFF;
2094 This->currentPalette = 0;
2096 /* Initialize the texture unit mapping to a 1:1 mapping */
2097 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2098 if (state < GL_LIMITS(fragment_samplers)) {
2099 This->texUnitMap[state] = state;
2100 This->rev_tex_unit_map[state] = state;
2101 } else {
2102 This->texUnitMap[state] = -1;
2103 This->rev_tex_unit_map[state] = -1;
2107 /* Setup the implicit swapchain */
2108 TRACE("Creating implicit swapchain\n");
2109 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2110 if (FAILED(hr) || !swapchain) {
2111 WARN("Failed to create implicit swapchain\n");
2112 goto err_out;
2115 This->NumberOfSwapChains = 1;
2116 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2117 if(!This->swapchains) {
2118 ERR("Out of memory!\n");
2119 goto err_out;
2121 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2123 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2124 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2125 This->render_targets[0] = swapchain->backBuffer[0];
2126 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2128 else {
2129 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2130 This->render_targets[0] = swapchain->frontBuffer;
2131 This->lastActiveRenderTarget = swapchain->frontBuffer;
2133 IWineD3DSurface_AddRef(This->render_targets[0]);
2134 This->activeContext = swapchain->context[0];
2135 This->lastThread = GetCurrentThreadId();
2137 /* Depth Stencil support */
2138 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2139 if (NULL != This->stencilBufferTarget) {
2140 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2143 hr = This->shader_backend->shader_alloc_private(iface);
2144 if(FAILED(hr)) {
2145 TRACE("Shader private data couldn't be allocated\n");
2146 goto err_out;
2148 hr = This->frag_pipe->alloc_private(iface);
2149 if(FAILED(hr)) {
2150 TRACE("Fragment pipeline private data couldn't be allocated\n");
2151 goto err_out;
2154 /* Set up some starting GL setup */
2156 /* Setup all the devices defaults */
2157 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2158 create_dummy_textures(This);
2160 ENTER_GL();
2162 #if 0
2163 IWineD3DImpl_CheckGraphicsMemory();
2164 #endif
2166 { /* Set a default viewport */
2167 WINED3DVIEWPORT vp;
2168 vp.X = 0;
2169 vp.Y = 0;
2170 vp.Width = pPresentationParameters->BackBufferWidth;
2171 vp.Height = pPresentationParameters->BackBufferHeight;
2172 vp.MinZ = 0.0f;
2173 vp.MaxZ = 1.0f;
2174 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2177 /* Initialize the current view state */
2178 This->view_ident = 1;
2179 This->contexts[0]->last_was_rhw = 0;
2180 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2181 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2183 switch(wined3d_settings.offscreen_rendering_mode) {
2184 case ORM_FBO:
2185 case ORM_PBUFFER:
2186 This->offscreenBuffer = GL_BACK;
2187 break;
2189 case ORM_BACKBUFFER:
2191 if(This->activeContext->aux_buffers > 0) {
2192 TRACE("Using auxilliary buffer for offscreen rendering\n");
2193 This->offscreenBuffer = GL_AUX0;
2194 } else {
2195 TRACE("Using back buffer for offscreen rendering\n");
2196 This->offscreenBuffer = GL_BACK;
2201 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2202 LEAVE_GL();
2204 /* Clear the screen */
2205 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2206 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2207 0x00, 1.0, 0);
2209 This->d3d_initialized = TRUE;
2211 if(wined3d_settings.logo) {
2212 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2214 This->highest_dirty_ps_const = 0;
2215 This->highest_dirty_vs_const = 0;
2216 return WINED3D_OK;
2218 err_out:
2219 HeapFree(GetProcessHeap(), 0, This->render_targets);
2220 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2221 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2222 HeapFree(GetProcessHeap(), 0, This->swapchains);
2223 This->NumberOfSwapChains = 0;
2224 if(This->palettes) {
2225 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2226 HeapFree(GetProcessHeap(), 0, This->palettes);
2228 This->NumberOfPalettes = 0;
2229 if(swapchain) {
2230 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2232 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2233 if(This->stateBlock) {
2234 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2235 This->stateBlock = NULL;
2237 This->frag_pipe->free_private(iface);
2238 This->shader_backend->shader_free_private(iface);
2239 return hr;
2242 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2244 int sampler;
2245 UINT i;
2246 TRACE("(%p)\n", This);
2248 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2250 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2251 * it was created. Thus make sure a context is active for the glDelete* calls
2253 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2255 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2257 TRACE("Deleting high order patches\n");
2258 for(i = 0; i < PATCHMAP_SIZE; i++) {
2259 struct list *e1, *e2;
2260 struct WineD3DRectPatch *patch;
2261 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2262 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2263 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2267 /* Delete the palette conversion shader if it is around */
2268 if(This->paletteConversionShader) {
2269 ENTER_GL();
2270 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2271 LEAVE_GL();
2272 This->paletteConversionShader = 0;
2275 /* Delete the pbuffer context if there is any */
2276 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2278 /* Delete the mouse cursor texture */
2279 if(This->cursorTexture) {
2280 ENTER_GL();
2281 glDeleteTextures(1, &This->cursorTexture);
2282 LEAVE_GL();
2283 This->cursorTexture = 0;
2286 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2287 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2289 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2290 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2293 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2294 * private data, it might contain opengl pointers
2296 if(This->depth_blt_texture) {
2297 glDeleteTextures(1, &This->depth_blt_texture);
2298 This->depth_blt_texture = 0;
2300 if (This->depth_blt_rb) {
2301 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2302 This->depth_blt_rb = 0;
2303 This->depth_blt_rb_w = 0;
2304 This->depth_blt_rb_h = 0;
2307 /* Release the update stateblock */
2308 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2309 if(This->updateStateBlock != This->stateBlock)
2310 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2312 This->updateStateBlock = NULL;
2314 { /* because were not doing proper internal refcounts releasing the primary state block
2315 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2316 to set this->stateBlock = NULL; first */
2317 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2318 This->stateBlock = NULL;
2320 /* Release the stateblock */
2321 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2322 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2326 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2327 This->frag_pipe->free_private(iface);
2328 This->shader_backend->shader_free_private(iface);
2330 /* Release the buffers (with sanity checks)*/
2331 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2332 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2333 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2334 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2336 This->stencilBufferTarget = NULL;
2338 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2339 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2340 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2342 TRACE("Setting rendertarget to NULL\n");
2343 This->render_targets[0] = NULL;
2345 if (This->auto_depth_stencil_buffer) {
2346 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2347 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2349 This->auto_depth_stencil_buffer = NULL;
2352 for(i=0; i < This->NumberOfSwapChains; i++) {
2353 TRACE("Releasing the implicit swapchain %d\n", i);
2354 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2355 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2359 HeapFree(GetProcessHeap(), 0, This->swapchains);
2360 This->swapchains = NULL;
2361 This->NumberOfSwapChains = 0;
2363 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2364 HeapFree(GetProcessHeap(), 0, This->palettes);
2365 This->palettes = NULL;
2366 This->NumberOfPalettes = 0;
2368 HeapFree(GetProcessHeap(), 0, This->render_targets);
2369 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2370 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2371 This->render_targets = NULL;
2372 This->fbo_color_attachments = NULL;
2373 This->draw_buffers = NULL;
2375 This->d3d_initialized = FALSE;
2376 return WINED3D_OK;
2379 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2381 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2383 /* Setup the window for fullscreen mode */
2384 if(fullscreen && !This->ddraw_fullscreen) {
2385 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2386 } else if(!fullscreen && This->ddraw_fullscreen) {
2387 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2390 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2391 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2392 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2393 * separately.
2395 This->ddraw_fullscreen = fullscreen;
2398 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2399 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2400 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2402 * There is no way to deactivate thread safety once it is enabled.
2404 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2407 /*For now just store the flag(needed in case of ddraw) */
2408 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2410 return;
2413 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2414 DEVMODEW devmode;
2415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2416 LONG ret;
2417 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2418 RECT clip_rc;
2420 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2422 /* Resize the screen even without a window:
2423 * The app could have unset it with SetCooperativeLevel, but not called
2424 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2425 * but we don't have any hwnd
2428 memset(&devmode, 0, sizeof(devmode));
2429 devmode.dmSize = sizeof(devmode);
2430 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2431 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2432 devmode.dmPelsWidth = pMode->Width;
2433 devmode.dmPelsHeight = pMode->Height;
2435 devmode.dmDisplayFrequency = pMode->RefreshRate;
2436 if (pMode->RefreshRate != 0) {
2437 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2440 /* Only change the mode if necessary */
2441 if( (This->ddraw_width == pMode->Width) &&
2442 (This->ddraw_height == pMode->Height) &&
2443 (This->ddraw_format == pMode->Format) &&
2444 (pMode->RefreshRate == 0) ) {
2445 return WINED3D_OK;
2448 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2449 if (ret != DISP_CHANGE_SUCCESSFUL) {
2450 if(devmode.dmDisplayFrequency != 0) {
2451 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2452 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2453 devmode.dmDisplayFrequency = 0;
2454 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2456 if(ret != DISP_CHANGE_SUCCESSFUL) {
2457 return WINED3DERR_NOTAVAILABLE;
2461 /* Store the new values */
2462 This->ddraw_width = pMode->Width;
2463 This->ddraw_height = pMode->Height;
2464 This->ddraw_format = pMode->Format;
2466 /* Only do this with a window of course, and only if we're fullscreened */
2467 if(This->ddraw_window && This->ddraw_fullscreen)
2468 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2470 /* And finally clip mouse to our screen */
2471 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2472 ClipCursor(&clip_rc);
2474 return WINED3D_OK;
2477 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2479 *ppD3D= This->wineD3D;
2480 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2481 IWineD3D_AddRef(*ppD3D);
2482 return WINED3D_OK;
2485 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2488 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2489 (This->adapter->TextureRam/(1024*1024)),
2490 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2491 /* return simulated texture memory left */
2492 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2497 /*****
2498 * Get / Set FVF
2499 *****/
2500 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2503 /* Update the current state block */
2504 This->updateStateBlock->changed.fvf = TRUE;
2506 if(This->updateStateBlock->fvf == fvf) {
2507 TRACE("Application is setting the old fvf over, nothing to do\n");
2508 return WINED3D_OK;
2511 This->updateStateBlock->fvf = fvf;
2512 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2513 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2514 return WINED3D_OK;
2518 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2520 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2521 *pfvf = This->stateBlock->fvf;
2522 return WINED3D_OK;
2525 /*****
2526 * Get / Set Stream Source
2527 *****/
2528 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2530 IWineD3DVertexBuffer *oldSrc;
2532 if (StreamNumber >= MAX_STREAMS) {
2533 WARN("Stream out of range %d\n", StreamNumber);
2534 return WINED3DERR_INVALIDCALL;
2535 } else if(OffsetInBytes & 0x3) {
2536 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2537 return WINED3DERR_INVALIDCALL;
2540 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2541 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2543 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2545 if(oldSrc == pStreamData &&
2546 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2547 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2548 TRACE("Application is setting the old values over, nothing to do\n");
2549 return WINED3D_OK;
2552 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2553 if (pStreamData) {
2554 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2555 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2558 /* Handle recording of state blocks */
2559 if (This->isRecordingState) {
2560 TRACE("Recording... not performing anything\n");
2561 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2562 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2563 return WINED3D_OK;
2566 /* Need to do a getParent and pass the references up */
2567 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2568 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2569 so for now, just count internally */
2570 if (pStreamData != NULL) {
2571 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2572 InterlockedIncrement(&vbImpl->bindCount);
2573 IWineD3DVertexBuffer_AddRef(pStreamData);
2575 if (oldSrc != NULL) {
2576 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2577 IWineD3DVertexBuffer_Release(oldSrc);
2580 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2582 return WINED3D_OK;
2585 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2588 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2589 This->stateBlock->streamSource[StreamNumber],
2590 This->stateBlock->streamOffset[StreamNumber],
2591 This->stateBlock->streamStride[StreamNumber]);
2593 if (StreamNumber >= MAX_STREAMS) {
2594 WARN("Stream out of range %d\n", StreamNumber);
2595 return WINED3DERR_INVALIDCALL;
2597 *pStream = This->stateBlock->streamSource[StreamNumber];
2598 *pStride = This->stateBlock->streamStride[StreamNumber];
2599 if (pOffset) {
2600 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2603 if (*pStream != NULL) {
2604 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2606 return WINED3D_OK;
2609 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2611 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2612 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2614 /* Verify input at least in d3d9 this is invalid*/
2615 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2616 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2617 return WINED3DERR_INVALIDCALL;
2619 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2620 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2621 return WINED3DERR_INVALIDCALL;
2623 if( Divider == 0 ){
2624 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2625 return WINED3DERR_INVALIDCALL;
2628 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2629 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2631 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2632 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2634 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2635 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2636 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2639 return WINED3D_OK;
2642 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2645 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2646 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2648 TRACE("(%p) : returning %d\n", This, *Divider);
2650 return WINED3D_OK;
2653 /*****
2654 * Get / Set & Multiply Transform
2655 *****/
2656 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2659 /* Most of this routine, comments included copied from ddraw tree initially: */
2660 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2662 /* Handle recording of state blocks */
2663 if (This->isRecordingState) {
2664 TRACE("Recording... not performing anything\n");
2665 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2666 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2667 return WINED3D_OK;
2671 * If the new matrix is the same as the current one,
2672 * we cut off any further processing. this seems to be a reasonable
2673 * optimization because as was noticed, some apps (warcraft3 for example)
2674 * tend towards setting the same matrix repeatedly for some reason.
2676 * From here on we assume that the new matrix is different, wherever it matters.
2678 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2679 TRACE("The app is setting the same matrix over again\n");
2680 return WINED3D_OK;
2681 } else {
2682 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2686 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2687 where ViewMat = Camera space, WorldMat = world space.
2689 In OpenGL, camera and world space is combined into GL_MODELVIEW
2690 matrix. The Projection matrix stay projection matrix.
2693 /* Capture the times we can just ignore the change for now */
2694 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2695 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2696 /* Handled by the state manager */
2699 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2700 return WINED3D_OK;
2703 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2705 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2706 *pMatrix = This->stateBlock->transforms[State];
2707 return WINED3D_OK;
2710 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2711 WINED3DMATRIX *mat = NULL;
2712 WINED3DMATRIX temp;
2714 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2715 * below means it will be recorded in a state block change, but it
2716 * works regardless where it is recorded.
2717 * If this is found to be wrong, change to StateBlock.
2719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2720 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2722 if (State < HIGHEST_TRANSFORMSTATE)
2724 mat = &This->updateStateBlock->transforms[State];
2725 } else {
2726 FIXME("Unhandled transform state!!\n");
2729 multiply_matrix(&temp, mat, pMatrix);
2731 /* Apply change via set transform - will reapply to eg. lights this way */
2732 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2735 /*****
2736 * Get / Set Light
2737 *****/
2738 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2739 you can reference any indexes you want as long as that number max are enabled at any
2740 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2741 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2742 but when recording, just build a chain pretty much of commands to be replayed. */
2744 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2745 float rho;
2746 PLIGHTINFOEL *object = NULL;
2747 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2748 struct list *e;
2750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2751 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2753 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2754 * the gl driver.
2756 if(!pLight) {
2757 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2758 return WINED3DERR_INVALIDCALL;
2761 switch(pLight->Type) {
2762 case WINED3DLIGHT_POINT:
2763 case WINED3DLIGHT_SPOT:
2764 case WINED3DLIGHT_PARALLELPOINT:
2765 case WINED3DLIGHT_GLSPOT:
2766 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2767 * most wanted
2769 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2770 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2771 return WINED3DERR_INVALIDCALL;
2773 break;
2775 case WINED3DLIGHT_DIRECTIONAL:
2776 /* Ignores attenuation */
2777 break;
2779 default:
2780 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2781 return WINED3DERR_INVALIDCALL;
2784 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2785 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2786 if(object->OriginalIndex == Index) break;
2787 object = NULL;
2790 if(!object) {
2791 TRACE("Adding new light\n");
2792 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2793 if(!object) {
2794 ERR("Out of memory error when allocating a light\n");
2795 return E_OUTOFMEMORY;
2797 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2798 object->glIndex = -1;
2799 object->OriginalIndex = Index;
2800 object->changed = TRUE;
2803 /* Initialize the object */
2804 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,
2805 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2806 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2807 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2808 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2809 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2810 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2812 /* Save away the information */
2813 object->OriginalParms = *pLight;
2815 switch (pLight->Type) {
2816 case WINED3DLIGHT_POINT:
2817 /* Position */
2818 object->lightPosn[0] = pLight->Position.x;
2819 object->lightPosn[1] = pLight->Position.y;
2820 object->lightPosn[2] = pLight->Position.z;
2821 object->lightPosn[3] = 1.0f;
2822 object->cutoff = 180.0f;
2823 /* FIXME: Range */
2824 break;
2826 case WINED3DLIGHT_DIRECTIONAL:
2827 /* Direction */
2828 object->lightPosn[0] = -pLight->Direction.x;
2829 object->lightPosn[1] = -pLight->Direction.y;
2830 object->lightPosn[2] = -pLight->Direction.z;
2831 object->lightPosn[3] = 0.0;
2832 object->exponent = 0.0f;
2833 object->cutoff = 180.0f;
2834 break;
2836 case WINED3DLIGHT_SPOT:
2837 /* Position */
2838 object->lightPosn[0] = pLight->Position.x;
2839 object->lightPosn[1] = pLight->Position.y;
2840 object->lightPosn[2] = pLight->Position.z;
2841 object->lightPosn[3] = 1.0;
2843 /* Direction */
2844 object->lightDirn[0] = pLight->Direction.x;
2845 object->lightDirn[1] = pLight->Direction.y;
2846 object->lightDirn[2] = pLight->Direction.z;
2847 object->lightDirn[3] = 1.0;
2850 * opengl-ish and d3d-ish spot lights use too different models for the
2851 * light "intensity" as a function of the angle towards the main light direction,
2852 * so we only can approximate very roughly.
2853 * however spot lights are rather rarely used in games (if ever used at all).
2854 * furthermore if still used, probably nobody pays attention to such details.
2856 if (pLight->Falloff == 0) {
2857 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2858 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2859 * will always be 1.0 for both of them, and we don't have to care for the
2860 * rest of the rather complex calculation
2862 object->exponent = 0;
2863 } else {
2864 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2865 if (rho < 0.0001) rho = 0.0001f;
2866 object->exponent = -0.3/log(cos(rho/2));
2868 if (object->exponent > 128.0) {
2869 object->exponent = 128.0;
2871 object->cutoff = pLight->Phi*90/M_PI;
2873 /* FIXME: Range */
2874 break;
2876 default:
2877 FIXME("Unrecognized light type %d\n", pLight->Type);
2880 /* Update the live definitions if the light is currently assigned a glIndex */
2881 if (object->glIndex != -1 && !This->isRecordingState) {
2882 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2884 return WINED3D_OK;
2887 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2888 PLIGHTINFOEL *lightInfo = NULL;
2889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2890 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2891 struct list *e;
2892 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2894 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2895 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2896 if(lightInfo->OriginalIndex == Index) break;
2897 lightInfo = NULL;
2900 if (lightInfo == NULL) {
2901 TRACE("Light information requested but light not defined\n");
2902 return WINED3DERR_INVALIDCALL;
2905 *pLight = lightInfo->OriginalParms;
2906 return WINED3D_OK;
2909 /*****
2910 * Get / Set Light Enable
2911 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2912 *****/
2913 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2914 PLIGHTINFOEL *lightInfo = NULL;
2915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2916 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2917 struct list *e;
2918 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2920 /* Tests show true = 128...not clear why */
2921 Enable = Enable? 128: 0;
2923 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2924 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2925 if(lightInfo->OriginalIndex == Index) break;
2926 lightInfo = NULL;
2928 TRACE("Found light: %p\n", lightInfo);
2930 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2931 if (lightInfo == NULL) {
2933 TRACE("Light enabled requested but light not defined, so defining one!\n");
2934 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2936 /* Search for it again! Should be fairly quick as near head of list */
2937 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2938 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2939 if(lightInfo->OriginalIndex == Index) break;
2940 lightInfo = NULL;
2942 if (lightInfo == NULL) {
2943 FIXME("Adding default lights has failed dismally\n");
2944 return WINED3DERR_INVALIDCALL;
2948 lightInfo->enabledChanged = TRUE;
2949 if(!Enable) {
2950 if(lightInfo->glIndex != -1) {
2951 if(!This->isRecordingState) {
2952 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2955 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2956 lightInfo->glIndex = -1;
2957 } else {
2958 TRACE("Light already disabled, nothing to do\n");
2960 lightInfo->enabled = FALSE;
2961 } else {
2962 lightInfo->enabled = TRUE;
2963 if (lightInfo->glIndex != -1) {
2964 /* nop */
2965 TRACE("Nothing to do as light was enabled\n");
2966 } else {
2967 int i;
2968 /* Find a free gl light */
2969 for(i = 0; i < This->maxConcurrentLights; i++) {
2970 if(This->stateBlock->activeLights[i] == NULL) {
2971 This->stateBlock->activeLights[i] = lightInfo;
2972 lightInfo->glIndex = i;
2973 break;
2976 if(lightInfo->glIndex == -1) {
2977 /* Our tests show that Windows returns D3D_OK in this situation, even with
2978 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2979 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2980 * as well for those lights.
2982 * TODO: Test how this affects rendering
2984 FIXME("Too many concurrently active lights\n");
2985 return WINED3D_OK;
2988 /* i == lightInfo->glIndex */
2989 if(!This->isRecordingState) {
2990 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2995 return WINED3D_OK;
2998 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3000 PLIGHTINFOEL *lightInfo = NULL;
3001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3002 struct list *e;
3003 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3004 TRACE("(%p) : for idx(%d)\n", This, Index);
3006 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3007 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3008 if(lightInfo->OriginalIndex == Index) break;
3009 lightInfo = NULL;
3012 if (lightInfo == NULL) {
3013 TRACE("Light enabled state requested but light not defined\n");
3014 return WINED3DERR_INVALIDCALL;
3016 /* true is 128 according to SetLightEnable */
3017 *pEnable = lightInfo->enabled ? 128 : 0;
3018 return WINED3D_OK;
3021 /*****
3022 * Get / Set Clip Planes
3023 *****/
3024 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3026 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3028 /* Validate Index */
3029 if (Index >= GL_LIMITS(clipplanes)) {
3030 TRACE("Application has requested clipplane this device doesn't support\n");
3031 return WINED3DERR_INVALIDCALL;
3034 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3036 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3037 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3038 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3039 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3040 TRACE("Application is setting old values over, nothing to do\n");
3041 return WINED3D_OK;
3044 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3045 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3046 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3047 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3049 /* Handle recording of state blocks */
3050 if (This->isRecordingState) {
3051 TRACE("Recording... not performing anything\n");
3052 return WINED3D_OK;
3055 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3057 return WINED3D_OK;
3060 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3062 TRACE("(%p) : for idx %d\n", This, Index);
3064 /* Validate Index */
3065 if (Index >= GL_LIMITS(clipplanes)) {
3066 TRACE("Application has requested clipplane this device doesn't support\n");
3067 return WINED3DERR_INVALIDCALL;
3070 pPlane[0] = This->stateBlock->clipplane[Index][0];
3071 pPlane[1] = This->stateBlock->clipplane[Index][1];
3072 pPlane[2] = This->stateBlock->clipplane[Index][2];
3073 pPlane[3] = This->stateBlock->clipplane[Index][3];
3074 return WINED3D_OK;
3077 /*****
3078 * Get / Set Clip Plane Status
3079 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3080 *****/
3081 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3083 FIXME("(%p) : stub\n", This);
3084 if (NULL == pClipStatus) {
3085 return WINED3DERR_INVALIDCALL;
3087 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3088 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3089 return WINED3D_OK;
3092 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3094 FIXME("(%p) : stub\n", This);
3095 if (NULL == pClipStatus) {
3096 return WINED3DERR_INVALIDCALL;
3098 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3099 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3100 return WINED3D_OK;
3103 /*****
3104 * Get / Set Material
3105 *****/
3106 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3109 if (!pMaterial) return WINED3DERR_INVALIDCALL;
3111 This->updateStateBlock->changed.material = TRUE;
3112 This->updateStateBlock->material = *pMaterial;
3114 /* Handle recording of state blocks */
3115 if (This->isRecordingState) {
3116 TRACE("Recording... not performing anything\n");
3117 return WINED3D_OK;
3120 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3121 return WINED3D_OK;
3124 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3126 *pMaterial = This->updateStateBlock->material;
3127 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3128 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3129 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3130 pMaterial->Ambient.b, pMaterial->Ambient.a);
3131 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3132 pMaterial->Specular.b, pMaterial->Specular.a);
3133 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3134 pMaterial->Emissive.b, pMaterial->Emissive.a);
3135 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3137 return WINED3D_OK;
3140 /*****
3141 * Get / Set Indices
3142 *****/
3143 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3145 IWineD3DIndexBuffer *oldIdxs;
3147 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3148 oldIdxs = This->updateStateBlock->pIndexData;
3150 This->updateStateBlock->changed.indices = TRUE;
3151 This->updateStateBlock->pIndexData = pIndexData;
3153 /* Handle recording of state blocks */
3154 if (This->isRecordingState) {
3155 TRACE("Recording... not performing anything\n");
3156 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3157 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3158 return WINED3D_OK;
3161 if(oldIdxs != pIndexData) {
3162 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3163 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3164 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3166 return WINED3D_OK;
3169 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3172 *ppIndexData = This->stateBlock->pIndexData;
3174 /* up ref count on ppindexdata */
3175 if (*ppIndexData) {
3176 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3177 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3178 }else{
3179 TRACE("(%p) No index data set\n", This);
3181 TRACE("Returning %p\n", *ppIndexData);
3183 return WINED3D_OK;
3186 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3187 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3189 TRACE("(%p)->(%d)\n", This, BaseIndex);
3191 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3192 TRACE("Application is setting the old value over, nothing to do\n");
3193 return WINED3D_OK;
3196 This->updateStateBlock->baseVertexIndex = BaseIndex;
3198 if (This->isRecordingState) {
3199 TRACE("Recording... not performing anything\n");
3200 return WINED3D_OK;
3202 /* The base vertex index affects the stream sources */
3203 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3204 return WINED3D_OK;
3207 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3209 TRACE("(%p) : base_index %p\n", This, base_index);
3211 *base_index = This->stateBlock->baseVertexIndex;
3213 TRACE("Returning %u\n", *base_index);
3215 return WINED3D_OK;
3218 /*****
3219 * Get / Set Viewports
3220 *****/
3221 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3224 TRACE("(%p)\n", This);
3225 This->updateStateBlock->changed.viewport = TRUE;
3226 This->updateStateBlock->viewport = *pViewport;
3228 /* Handle recording of state blocks */
3229 if (This->isRecordingState) {
3230 TRACE("Recording... not performing anything\n");
3231 return WINED3D_OK;
3234 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3235 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3237 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3238 return WINED3D_OK;
3242 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3244 TRACE("(%p)\n", This);
3245 *pViewport = This->stateBlock->viewport;
3246 return WINED3D_OK;
3249 /*****
3250 * Get / Set Render States
3251 * TODO: Verify against dx9 definitions
3252 *****/
3253 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3256 DWORD oldValue = This->stateBlock->renderState[State];
3258 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3260 This->updateStateBlock->changed.renderState[State] = TRUE;
3261 This->updateStateBlock->renderState[State] = Value;
3263 /* Handle recording of state blocks */
3264 if (This->isRecordingState) {
3265 TRACE("Recording... not performing anything\n");
3266 return WINED3D_OK;
3269 /* Compared here and not before the assignment to allow proper stateblock recording */
3270 if(Value == oldValue) {
3271 TRACE("Application is setting the old value over, nothing to do\n");
3272 } else {
3273 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3276 return WINED3D_OK;
3279 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3281 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3282 *pValue = This->stateBlock->renderState[State];
3283 return WINED3D_OK;
3286 /*****
3287 * Get / Set Sampler States
3288 * TODO: Verify against dx9 definitions
3289 *****/
3291 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3293 DWORD oldValue;
3295 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3296 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3298 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3299 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3302 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3303 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3304 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3307 * SetSampler is designed to allow for more than the standard up to 8 textures
3308 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3309 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3311 * http://developer.nvidia.com/object/General_FAQ.html#t6
3313 * There are two new settings for GForce
3314 * the sampler one:
3315 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3316 * and the texture one:
3317 * GL_MAX_TEXTURE_COORDS_ARB.
3318 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3319 ******************/
3321 oldValue = This->stateBlock->samplerState[Sampler][Type];
3322 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3323 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3325 /* Handle recording of state blocks */
3326 if (This->isRecordingState) {
3327 TRACE("Recording... not performing anything\n");
3328 return WINED3D_OK;
3331 if(oldValue == Value) {
3332 TRACE("Application is setting the old value over, nothing to do\n");
3333 return WINED3D_OK;
3336 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3338 return WINED3D_OK;
3341 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3344 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3345 This, Sampler, debug_d3dsamplerstate(Type), Type);
3347 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3348 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3351 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3352 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3353 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3355 *Value = This->stateBlock->samplerState[Sampler][Type];
3356 TRACE("(%p) : Returning %#x\n", This, *Value);
3358 return WINED3D_OK;
3361 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3364 This->updateStateBlock->changed.scissorRect = TRUE;
3365 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3366 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3367 return WINED3D_OK;
3369 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3371 if(This->isRecordingState) {
3372 TRACE("Recording... not performing anything\n");
3373 return WINED3D_OK;
3376 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3378 return WINED3D_OK;
3381 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3384 *pRect = This->updateStateBlock->scissorRect;
3385 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3386 return WINED3D_OK;
3389 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3391 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3393 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3395 This->updateStateBlock->vertexDecl = pDecl;
3396 This->updateStateBlock->changed.vertexDecl = TRUE;
3398 if (This->isRecordingState) {
3399 TRACE("Recording... not performing anything\n");
3400 return WINED3D_OK;
3401 } else if(pDecl == oldDecl) {
3402 /* Checked after the assignment to allow proper stateblock recording */
3403 TRACE("Application is setting the old declaration over, nothing to do\n");
3404 return WINED3D_OK;
3407 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3408 return WINED3D_OK;
3411 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3414 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3416 *ppDecl = This->stateBlock->vertexDecl;
3417 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3418 return WINED3D_OK;
3421 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3423 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3425 This->updateStateBlock->vertexShader = pShader;
3426 This->updateStateBlock->changed.vertexShader = TRUE;
3428 if (This->isRecordingState) {
3429 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3430 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3431 TRACE("Recording... not performing anything\n");
3432 return WINED3D_OK;
3433 } else if(oldShader == pShader) {
3434 /* Checked here to allow proper stateblock recording */
3435 TRACE("App is setting the old shader over, nothing to do\n");
3436 return WINED3D_OK;
3439 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3440 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3441 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3443 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3445 return WINED3D_OK;
3448 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3449 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3451 if (NULL == ppShader) {
3452 return WINED3DERR_INVALIDCALL;
3454 *ppShader = This->stateBlock->vertexShader;
3455 if( NULL != *ppShader)
3456 IWineD3DVertexShader_AddRef(*ppShader);
3458 TRACE("(%p) : returning %p\n", This, *ppShader);
3459 return WINED3D_OK;
3462 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3463 IWineD3DDevice *iface,
3464 UINT start,
3465 CONST BOOL *srcData,
3466 UINT count) {
3468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3469 int i, cnt = min(count, MAX_CONST_B - start);
3471 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3472 iface, srcData, start, count);
3474 if (srcData == NULL || cnt < 0)
3475 return WINED3DERR_INVALIDCALL;
3477 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3478 for (i = 0; i < cnt; i++)
3479 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3481 for (i = start; i < cnt + start; ++i) {
3482 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3485 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3487 return WINED3D_OK;
3490 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3491 IWineD3DDevice *iface,
3492 UINT start,
3493 BOOL *dstData,
3494 UINT count) {
3496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3497 int cnt = min(count, MAX_CONST_B - start);
3499 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3500 iface, dstData, start, count);
3502 if (dstData == NULL || cnt < 0)
3503 return WINED3DERR_INVALIDCALL;
3505 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3506 return WINED3D_OK;
3509 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3510 IWineD3DDevice *iface,
3511 UINT start,
3512 CONST int *srcData,
3513 UINT count) {
3515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3516 int i, cnt = min(count, MAX_CONST_I - start);
3518 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3519 iface, srcData, start, count);
3521 if (srcData == NULL || cnt < 0)
3522 return WINED3DERR_INVALIDCALL;
3524 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3525 for (i = 0; i < cnt; i++)
3526 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3527 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3529 for (i = start; i < cnt + start; ++i) {
3530 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3533 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3535 return WINED3D_OK;
3538 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3539 IWineD3DDevice *iface,
3540 UINT start,
3541 int *dstData,
3542 UINT count) {
3544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3545 int cnt = min(count, MAX_CONST_I - start);
3547 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3548 iface, dstData, start, count);
3550 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3551 return WINED3DERR_INVALIDCALL;
3553 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3554 return WINED3D_OK;
3557 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3558 IWineD3DDevice *iface,
3559 UINT start,
3560 CONST float *srcData,
3561 UINT count) {
3563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3564 int i;
3566 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3567 iface, srcData, start, count);
3569 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3570 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3571 return WINED3DERR_INVALIDCALL;
3573 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3574 if(TRACE_ON(d3d)) {
3575 for (i = 0; i < count; i++)
3576 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3577 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3580 for (i = start; i < count + start; ++i) {
3581 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3582 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3583 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3584 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3585 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3587 ptr->idx[ptr->count++] = i;
3588 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3592 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3594 return WINED3D_OK;
3597 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3598 IWineD3DDevice *iface,
3599 UINT start,
3600 CONST float *srcData,
3601 UINT count) {
3603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3604 int i;
3606 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3607 iface, srcData, start, count);
3609 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3610 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3611 return WINED3DERR_INVALIDCALL;
3613 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3614 if(TRACE_ON(d3d)) {
3615 for (i = 0; i < count; i++)
3616 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3617 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3620 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3621 * context. On a context switch the old context will be fully dirtified
3623 memset(This->activeContext->vshader_const_dirty + start, 1,
3624 sizeof(*This->activeContext->vshader_const_dirty) * count);
3625 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3627 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3629 return WINED3D_OK;
3632 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3633 IWineD3DDevice *iface,
3634 UINT start,
3635 float *dstData,
3636 UINT count) {
3638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3639 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3641 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3642 iface, dstData, start, count);
3644 if (dstData == NULL || cnt < 0)
3645 return WINED3DERR_INVALIDCALL;
3647 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3648 return WINED3D_OK;
3651 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3652 DWORD i;
3653 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3654 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3658 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3659 int i = This->rev_tex_unit_map[unit];
3660 int j = This->texUnitMap[stage];
3662 This->texUnitMap[stage] = unit;
3663 if (i != -1 && i != stage) {
3664 This->texUnitMap[i] = -1;
3667 This->rev_tex_unit_map[unit] = stage;
3668 if (j != -1 && j != unit) {
3669 This->rev_tex_unit_map[j] = -1;
3673 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3674 int i;
3676 for (i = 0; i < MAX_TEXTURES; ++i) {
3677 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3678 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3679 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3680 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3681 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3682 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3683 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3684 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3686 if (color_op == WINED3DTOP_DISABLE) {
3687 /* Not used, and disable higher stages */
3688 while (i < MAX_TEXTURES) {
3689 This->fixed_function_usage_map[i] = FALSE;
3690 ++i;
3692 break;
3695 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3696 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3697 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3698 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3699 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3700 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3701 This->fixed_function_usage_map[i] = TRUE;
3702 } else {
3703 This->fixed_function_usage_map[i] = FALSE;
3706 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3707 This->fixed_function_usage_map[i+1] = TRUE;
3712 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3713 int i, tex;
3715 device_update_fixed_function_usage_map(This);
3717 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3718 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3719 if (!This->fixed_function_usage_map[i]) continue;
3721 if (This->texUnitMap[i] != i) {
3722 device_map_stage(This, i, i);
3723 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3724 markTextureStagesDirty(This, i);
3727 return;
3730 /* Now work out the mapping */
3731 tex = 0;
3732 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3733 if (!This->fixed_function_usage_map[i]) continue;
3735 if (This->texUnitMap[i] != tex) {
3736 device_map_stage(This, i, tex);
3737 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3738 markTextureStagesDirty(This, i);
3741 ++tex;
3745 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3746 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3747 int i;
3749 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3750 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3751 device_map_stage(This, i, i);
3752 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3753 if (i < MAX_TEXTURES) {
3754 markTextureStagesDirty(This, i);
3760 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3761 int current_mapping = This->rev_tex_unit_map[unit];
3763 if (current_mapping == -1) {
3764 /* Not currently used */
3765 return TRUE;
3768 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3769 /* Used by a fragment sampler */
3771 if (!pshader_sampler_tokens) {
3772 /* No pixel shader, check fixed function */
3773 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3776 /* Pixel shader, check the shader's sampler map */
3777 return !pshader_sampler_tokens[current_mapping];
3780 /* Used by a vertex sampler */
3781 return !vshader_sampler_tokens[current_mapping];
3784 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3785 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3786 DWORD *pshader_sampler_tokens = NULL;
3787 int start = GL_LIMITS(combined_samplers) - 1;
3788 int i;
3790 if (ps) {
3791 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3793 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3794 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3795 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3798 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3799 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3800 if (vshader_sampler_tokens[i]) {
3801 if (This->texUnitMap[vsampler_idx] != -1) {
3802 /* Already mapped somewhere */
3803 continue;
3806 while (start >= 0) {
3807 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3808 device_map_stage(This, vsampler_idx, start);
3809 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3811 --start;
3812 break;
3815 --start;
3821 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3822 BOOL vs = use_vs(This);
3823 BOOL ps = use_ps(This);
3825 * Rules are:
3826 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3827 * that would be really messy and require shader recompilation
3828 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3829 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3831 if (ps) {
3832 device_map_psamplers(This);
3833 } else {
3834 device_map_fixed_function_samplers(This);
3837 if (vs) {
3838 device_map_vsamplers(This, ps);
3842 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3844 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3845 This->updateStateBlock->pixelShader = pShader;
3846 This->updateStateBlock->changed.pixelShader = TRUE;
3848 /* Handle recording of state blocks */
3849 if (This->isRecordingState) {
3850 TRACE("Recording... not performing anything\n");
3853 if (This->isRecordingState) {
3854 TRACE("Recording... not performing anything\n");
3855 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3856 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3857 return WINED3D_OK;
3860 if(pShader == oldShader) {
3861 TRACE("App is setting the old pixel shader over, nothing to do\n");
3862 return WINED3D_OK;
3865 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3866 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3868 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3869 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3871 return WINED3D_OK;
3874 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3877 if (NULL == ppShader) {
3878 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3879 return WINED3DERR_INVALIDCALL;
3882 *ppShader = This->stateBlock->pixelShader;
3883 if (NULL != *ppShader) {
3884 IWineD3DPixelShader_AddRef(*ppShader);
3886 TRACE("(%p) : returning %p\n", This, *ppShader);
3887 return WINED3D_OK;
3890 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3891 IWineD3DDevice *iface,
3892 UINT start,
3893 CONST BOOL *srcData,
3894 UINT count) {
3896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3897 int i, cnt = min(count, MAX_CONST_B - start);
3899 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3900 iface, srcData, start, count);
3902 if (srcData == NULL || cnt < 0)
3903 return WINED3DERR_INVALIDCALL;
3905 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3906 for (i = 0; i < cnt; i++)
3907 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3909 for (i = start; i < cnt + start; ++i) {
3910 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3913 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3915 return WINED3D_OK;
3918 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3919 IWineD3DDevice *iface,
3920 UINT start,
3921 BOOL *dstData,
3922 UINT count) {
3924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3925 int cnt = min(count, MAX_CONST_B - start);
3927 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3928 iface, dstData, start, count);
3930 if (dstData == NULL || cnt < 0)
3931 return WINED3DERR_INVALIDCALL;
3933 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3934 return WINED3D_OK;
3937 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3938 IWineD3DDevice *iface,
3939 UINT start,
3940 CONST int *srcData,
3941 UINT count) {
3943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3944 int i, cnt = min(count, MAX_CONST_I - start);
3946 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3947 iface, srcData, start, count);
3949 if (srcData == NULL || cnt < 0)
3950 return WINED3DERR_INVALIDCALL;
3952 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3953 for (i = 0; i < cnt; i++)
3954 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3955 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3957 for (i = start; i < cnt + start; ++i) {
3958 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3961 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3963 return WINED3D_OK;
3966 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3967 IWineD3DDevice *iface,
3968 UINT start,
3969 int *dstData,
3970 UINT count) {
3972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3973 int cnt = min(count, MAX_CONST_I - start);
3975 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3976 iface, dstData, start, count);
3978 if (dstData == NULL || cnt < 0)
3979 return WINED3DERR_INVALIDCALL;
3981 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3982 return WINED3D_OK;
3985 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3986 IWineD3DDevice *iface,
3987 UINT start,
3988 CONST float *srcData,
3989 UINT count) {
3991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3992 int i;
3994 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3995 iface, srcData, start, count);
3997 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3998 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3999 return WINED3DERR_INVALIDCALL;
4001 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4002 if(TRACE_ON(d3d)) {
4003 for (i = 0; i < count; i++)
4004 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4005 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4008 for (i = start; i < count + start; ++i) {
4009 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
4010 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
4011 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
4012 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
4013 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
4015 ptr->idx[ptr->count++] = i;
4016 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4020 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4022 return WINED3D_OK;
4025 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4026 IWineD3DDevice *iface,
4027 UINT start,
4028 CONST float *srcData,
4029 UINT count) {
4031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4032 int i;
4034 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4035 iface, srcData, start, count);
4037 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4038 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4039 return WINED3DERR_INVALIDCALL;
4041 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4042 if(TRACE_ON(d3d)) {
4043 for (i = 0; i < count; i++)
4044 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4045 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4048 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4049 * context. On a context switch the old context will be fully dirtified
4051 memset(This->activeContext->pshader_const_dirty + start, 1,
4052 sizeof(*This->activeContext->pshader_const_dirty) * count);
4053 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4055 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4057 return WINED3D_OK;
4060 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4061 IWineD3DDevice *iface,
4062 UINT start,
4063 float *dstData,
4064 UINT count) {
4066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4067 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4069 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4070 iface, dstData, start, count);
4072 if (dstData == NULL || cnt < 0)
4073 return WINED3DERR_INVALIDCALL;
4075 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4076 return WINED3D_OK;
4079 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4080 static HRESULT
4081 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4082 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4083 unsigned int i;
4084 DWORD DestFVF = dest->fvf;
4085 WINED3DVIEWPORT vp;
4086 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4087 BOOL doClip;
4088 int numTextures;
4090 if (lpStrideData->u.s.normal.lpData) {
4091 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4094 if (lpStrideData->u.s.position.lpData == NULL) {
4095 ERR("Source has no position mask\n");
4096 return WINED3DERR_INVALIDCALL;
4099 /* We might access VBOs from this code, so hold the lock */
4100 ENTER_GL();
4102 if (dest->resource.allocatedMemory == NULL) {
4103 /* This may happen if we do direct locking into a vbo. Unlikely,
4104 * but theoretically possible(ddraw processvertices test)
4106 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4107 if(!dest->resource.allocatedMemory) {
4108 LEAVE_GL();
4109 ERR("Out of memory\n");
4110 return E_OUTOFMEMORY;
4112 if(dest->vbo) {
4113 void *src;
4114 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4115 checkGLcall("glBindBufferARB");
4116 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4117 if(src) {
4118 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4120 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4121 checkGLcall("glUnmapBufferARB");
4125 /* Get a pointer into the destination vbo(create one if none exists) and
4126 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4128 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4129 dest->Flags |= VBFLAG_CREATEVBO;
4130 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4133 if(dest->vbo) {
4134 unsigned char extrabytes = 0;
4135 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4136 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4137 * this may write 4 extra bytes beyond the area that should be written
4139 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4140 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4141 if(!dest_conv_addr) {
4142 ERR("Out of memory\n");
4143 /* Continue without storing converted vertices */
4145 dest_conv = dest_conv_addr;
4148 /* Should I clip?
4149 * a) WINED3DRS_CLIPPING is enabled
4150 * b) WINED3DVOP_CLIP is passed
4152 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4153 static BOOL warned = FALSE;
4155 * The clipping code is not quite correct. Some things need
4156 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4157 * so disable clipping for now.
4158 * (The graphics in Half-Life are broken, and my processvertices
4159 * test crashes with IDirect3DDevice3)
4160 doClip = TRUE;
4162 doClip = FALSE;
4163 if(!warned) {
4164 warned = TRUE;
4165 FIXME("Clipping is broken and disabled for now\n");
4167 } else doClip = FALSE;
4168 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4170 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4171 WINED3DTS_VIEW,
4172 &view_mat);
4173 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4174 WINED3DTS_PROJECTION,
4175 &proj_mat);
4176 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4177 WINED3DTS_WORLDMATRIX(0),
4178 &world_mat);
4180 TRACE("View mat:\n");
4181 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);
4182 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);
4183 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);
4184 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);
4186 TRACE("Proj mat:\n");
4187 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);
4188 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);
4189 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);
4190 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);
4192 TRACE("World mat:\n");
4193 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);
4194 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);
4195 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);
4196 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);
4198 /* Get the viewport */
4199 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4200 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4201 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4203 multiply_matrix(&mat,&view_mat,&world_mat);
4204 multiply_matrix(&mat,&proj_mat,&mat);
4206 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4208 for (i = 0; i < dwCount; i+= 1) {
4209 unsigned int tex_index;
4211 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4212 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4213 /* The position first */
4214 float *p =
4215 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4216 float x, y, z, rhw;
4217 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4219 /* Multiplication with world, view and projection matrix */
4220 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);
4221 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);
4222 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);
4223 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);
4225 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4227 /* WARNING: The following things are taken from d3d7 and were not yet checked
4228 * against d3d8 or d3d9!
4231 /* Clipping conditions: From msdn
4233 * A vertex is clipped if it does not match the following requirements
4234 * -rhw < x <= rhw
4235 * -rhw < y <= rhw
4236 * 0 < z <= rhw
4237 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4239 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4240 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4244 if( !doClip ||
4245 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4246 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4247 ( rhw > eps ) ) ) {
4249 /* "Normal" viewport transformation (not clipped)
4250 * 1) The values are divided by rhw
4251 * 2) The y axis is negative, so multiply it with -1
4252 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4253 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4254 * 4) Multiply x with Width/2 and add Width/2
4255 * 5) The same for the height
4256 * 6) Add the viewpoint X and Y to the 2D coordinates and
4257 * The minimum Z value to z
4258 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4260 * Well, basically it's simply a linear transformation into viewport
4261 * coordinates
4264 x /= rhw;
4265 y /= rhw;
4266 z /= rhw;
4268 y *= -1;
4270 x *= vp.Width / 2;
4271 y *= vp.Height / 2;
4272 z *= vp.MaxZ - vp.MinZ;
4274 x += vp.Width / 2 + vp.X;
4275 y += vp.Height / 2 + vp.Y;
4276 z += vp.MinZ;
4278 rhw = 1 / rhw;
4279 } else {
4280 /* That vertex got clipped
4281 * Contrary to OpenGL it is not dropped completely, it just
4282 * undergoes a different calculation.
4284 TRACE("Vertex got clipped\n");
4285 x += rhw;
4286 y += rhw;
4288 x /= 2;
4289 y /= 2;
4291 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4292 * outside of the main vertex buffer memory. That needs some more
4293 * investigation...
4297 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4300 ( (float *) dest_ptr)[0] = x;
4301 ( (float *) dest_ptr)[1] = y;
4302 ( (float *) dest_ptr)[2] = z;
4303 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4305 dest_ptr += 3 * sizeof(float);
4307 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4308 dest_ptr += sizeof(float);
4311 if(dest_conv) {
4312 float w = 1 / rhw;
4313 ( (float *) dest_conv)[0] = x * w;
4314 ( (float *) dest_conv)[1] = y * w;
4315 ( (float *) dest_conv)[2] = z * w;
4316 ( (float *) dest_conv)[3] = w;
4318 dest_conv += 3 * sizeof(float);
4320 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4321 dest_conv += sizeof(float);
4325 if (DestFVF & WINED3DFVF_PSIZE) {
4326 dest_ptr += sizeof(DWORD);
4327 if(dest_conv) dest_conv += sizeof(DWORD);
4329 if (DestFVF & WINED3DFVF_NORMAL) {
4330 float *normal =
4331 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4332 /* AFAIK this should go into the lighting information */
4333 FIXME("Didn't expect the destination to have a normal\n");
4334 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4335 if(dest_conv) {
4336 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4340 if (DestFVF & WINED3DFVF_DIFFUSE) {
4341 DWORD *color_d =
4342 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4343 if(!color_d) {
4344 static BOOL warned = FALSE;
4346 if(!warned) {
4347 ERR("No diffuse color in source, but destination has one\n");
4348 warned = TRUE;
4351 *( (DWORD *) dest_ptr) = 0xffffffff;
4352 dest_ptr += sizeof(DWORD);
4354 if(dest_conv) {
4355 *( (DWORD *) dest_conv) = 0xffffffff;
4356 dest_conv += sizeof(DWORD);
4359 else {
4360 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4361 if(dest_conv) {
4362 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4363 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4364 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4365 dest_conv += sizeof(DWORD);
4370 if (DestFVF & WINED3DFVF_SPECULAR) {
4371 /* What's the color value in the feedback buffer? */
4372 DWORD *color_s =
4373 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4374 if(!color_s) {
4375 static BOOL warned = FALSE;
4377 if(!warned) {
4378 ERR("No specular color in source, but destination has one\n");
4379 warned = TRUE;
4382 *( (DWORD *) dest_ptr) = 0xFF000000;
4383 dest_ptr += sizeof(DWORD);
4385 if(dest_conv) {
4386 *( (DWORD *) dest_conv) = 0xFF000000;
4387 dest_conv += sizeof(DWORD);
4390 else {
4391 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4392 if(dest_conv) {
4393 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4394 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4395 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4396 dest_conv += sizeof(DWORD);
4401 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4402 float *tex_coord =
4403 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4404 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4405 if(!tex_coord) {
4406 ERR("No source texture, but destination requests one\n");
4407 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4408 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4410 else {
4411 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4412 if(dest_conv) {
4413 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4419 if(dest_conv) {
4420 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4421 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4422 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4423 dwCount * get_flexible_vertex_size(DestFVF),
4424 dest_conv_addr));
4425 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4426 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4429 LEAVE_GL();
4431 return WINED3D_OK;
4433 #undef copy_and_next
4435 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4437 WineDirect3DVertexStridedData strided;
4438 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4439 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4441 if(pVertexDecl) {
4442 ERR("Output vertex declaration not implemented yet\n");
4445 /* Need any context to write to the vbo. */
4446 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4448 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4449 * control the streamIsUP flag, thus restore it afterwards.
4451 This->stateBlock->streamIsUP = FALSE;
4452 memset(&strided, 0, sizeof(strided));
4453 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4454 This->stateBlock->streamIsUP = streamWasUP;
4456 if(vbo || SrcStartIndex) {
4457 unsigned int i;
4458 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4459 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4461 * Also get the start index in, but only loop over all elements if there's something to add at all.
4463 #define FIXSRC(type) \
4464 if(strided.u.s.type.VBO) { \
4465 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4466 strided.u.s.type.VBO = 0; \
4467 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4468 ENTER_GL(); \
4469 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4470 vb->vbo = 0; \
4471 LEAVE_GL(); \
4473 if(strided.u.s.type.lpData) { \
4474 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4476 FIXSRC(position);
4477 FIXSRC(blendWeights);
4478 FIXSRC(blendMatrixIndices);
4479 FIXSRC(normal);
4480 FIXSRC(pSize);
4481 FIXSRC(diffuse);
4482 FIXSRC(specular);
4483 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4484 FIXSRC(texCoords[i]);
4486 FIXSRC(position2);
4487 FIXSRC(normal2);
4488 FIXSRC(tangent);
4489 FIXSRC(binormal);
4490 FIXSRC(tessFactor);
4491 FIXSRC(fog);
4492 FIXSRC(depth);
4493 FIXSRC(sample);
4494 #undef FIXSRC
4497 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4500 /*****
4501 * Get / Set Texture Stage States
4502 * TODO: Verify against dx9 definitions
4503 *****/
4504 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4506 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4508 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4510 if (Stage >= MAX_TEXTURES) {
4511 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4512 return WINED3D_OK;
4515 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4516 This->updateStateBlock->textureState[Stage][Type] = Value;
4518 if (This->isRecordingState) {
4519 TRACE("Recording... not performing anything\n");
4520 return WINED3D_OK;
4523 /* Checked after the assignments to allow proper stateblock recording */
4524 if(oldValue == Value) {
4525 TRACE("App is setting the old value over, nothing to do\n");
4526 return WINED3D_OK;
4529 if(Stage > This->stateBlock->lowest_disabled_stage &&
4530 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4531 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4532 * Changes in other states are important on disabled stages too
4534 return WINED3D_OK;
4537 if(Type == WINED3DTSS_COLOROP) {
4538 int i;
4540 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4541 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4542 * they have to be disabled
4544 * The current stage is dirtified below.
4546 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4547 TRACE("Additionally dirtifying stage %d\n", i);
4548 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4550 This->stateBlock->lowest_disabled_stage = Stage;
4551 TRACE("New lowest disabled: %d\n", Stage);
4552 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4553 /* Previously disabled stage enabled. Stages above it may need enabling
4554 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4555 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4557 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4560 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4561 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4562 break;
4564 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4565 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4567 This->stateBlock->lowest_disabled_stage = i;
4568 TRACE("New lowest disabled: %d\n", i);
4570 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4571 /* TODO: Built a stage -> texture unit mapping for register combiners */
4575 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4577 return WINED3D_OK;
4580 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4582 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4583 *pValue = This->updateStateBlock->textureState[Stage][Type];
4584 return WINED3D_OK;
4587 /*****
4588 * Get / Set Texture
4589 *****/
4590 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4592 IWineD3DBaseTexture *oldTexture;
4594 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4596 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4597 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4600 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4601 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4602 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4605 oldTexture = This->updateStateBlock->textures[Stage];
4607 if(pTexture != NULL) {
4608 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4610 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4611 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4612 return WINED3DERR_INVALIDCALL;
4614 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4617 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4618 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4620 This->updateStateBlock->changed.textures[Stage] = TRUE;
4621 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4622 This->updateStateBlock->textures[Stage] = pTexture;
4624 /* Handle recording of state blocks */
4625 if (This->isRecordingState) {
4626 TRACE("Recording... not performing anything\n");
4627 return WINED3D_OK;
4630 if(oldTexture == pTexture) {
4631 TRACE("App is setting the same texture again, nothing to do\n");
4632 return WINED3D_OK;
4635 /** NOTE: MSDN says that setTexture increases the reference count,
4636 * and that the application must set the texture back to null (or have a leaky application),
4637 * This means we should pass the refcount up to the parent
4638 *******************************/
4639 if (NULL != This->updateStateBlock->textures[Stage]) {
4640 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4641 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4643 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4644 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4645 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4646 * so the COLOROP and ALPHAOP have to be dirtified.
4648 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4649 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4651 if(bindCount == 1) {
4652 new->baseTexture.sampler = Stage;
4654 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4658 if (NULL != oldTexture) {
4659 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4660 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4662 IWineD3DBaseTexture_Release(oldTexture);
4663 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4664 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4665 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4668 if(bindCount && old->baseTexture.sampler == Stage) {
4669 int i;
4670 /* Have to do a search for the other sampler(s) where the texture is bound to
4671 * Shouldn't happen as long as apps bind a texture only to one stage
4673 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4674 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4675 if(This->updateStateBlock->textures[i] == oldTexture) {
4676 old->baseTexture.sampler = i;
4677 break;
4683 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4685 return WINED3D_OK;
4688 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4691 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4693 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4694 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4697 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4698 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4699 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4702 *ppTexture=This->stateBlock->textures[Stage];
4703 if (*ppTexture)
4704 IWineD3DBaseTexture_AddRef(*ppTexture);
4706 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4708 return WINED3D_OK;
4711 /*****
4712 * Get Back Buffer
4713 *****/
4714 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4715 IWineD3DSurface **ppBackBuffer) {
4716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4717 IWineD3DSwapChain *swapChain;
4718 HRESULT hr;
4720 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4722 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4723 if (hr == WINED3D_OK) {
4724 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4725 IWineD3DSwapChain_Release(swapChain);
4726 } else {
4727 *ppBackBuffer = NULL;
4729 return hr;
4732 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4734 WARN("(%p) : stub, calling idirect3d for now\n", This);
4735 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4738 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4740 IWineD3DSwapChain *swapChain;
4741 HRESULT hr;
4743 if(iSwapChain > 0) {
4744 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4745 if (hr == WINED3D_OK) {
4746 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4747 IWineD3DSwapChain_Release(swapChain);
4748 } else {
4749 FIXME("(%p) Error getting display mode\n", This);
4751 } else {
4752 /* Don't read the real display mode,
4753 but return the stored mode instead. X11 can't change the color
4754 depth, and some apps are pretty angry if they SetDisplayMode from
4755 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4757 Also don't relay to the swapchain because with ddraw it's possible
4758 that there isn't a swapchain at all */
4759 pMode->Width = This->ddraw_width;
4760 pMode->Height = This->ddraw_height;
4761 pMode->Format = This->ddraw_format;
4762 pMode->RefreshRate = 0;
4763 hr = WINED3D_OK;
4766 return hr;
4769 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4771 TRACE("(%p)->(%p)\n", This, hWnd);
4773 if(This->ddraw_fullscreen) {
4774 if(This->ddraw_window && This->ddraw_window != hWnd) {
4775 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4777 if(hWnd && This->ddraw_window != hWnd) {
4778 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4782 This->ddraw_window = hWnd;
4783 return WINED3D_OK;
4786 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4788 TRACE("(%p)->(%p)\n", This, hWnd);
4790 *hWnd = This->ddraw_window;
4791 return WINED3D_OK;
4794 /*****
4795 * Stateblock related functions
4796 *****/
4798 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4800 IWineD3DStateBlockImpl *object;
4801 HRESULT temp_result;
4802 int i;
4804 TRACE("(%p)\n", This);
4806 if (This->isRecordingState) {
4807 return WINED3DERR_INVALIDCALL;
4810 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4811 if (NULL == object ) {
4812 FIXME("(%p)Error allocating memory for stateblock\n", This);
4813 return E_OUTOFMEMORY;
4815 TRACE("(%p) created object %p\n", This, object);
4816 object->wineD3DDevice= This;
4817 /** FIXME: object->parent = parent; **/
4818 object->parent = NULL;
4819 object->blockType = WINED3DSBT_RECORDED;
4820 object->ref = 1;
4821 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4823 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4824 list_init(&object->lightMap[i]);
4827 temp_result = allocate_shader_constants(object);
4828 if (WINED3D_OK != temp_result)
4829 return temp_result;
4831 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4832 This->updateStateBlock = object;
4833 This->isRecordingState = TRUE;
4835 TRACE("(%p) recording stateblock %p\n",This , object);
4836 return WINED3D_OK;
4839 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4841 unsigned int i, j;
4842 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4844 if (!This->isRecordingState) {
4845 FIXME("(%p) not recording! returning error\n", This);
4846 *ppStateBlock = NULL;
4847 return WINED3DERR_INVALIDCALL;
4850 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4851 if(object->changed.renderState[i]) {
4852 object->contained_render_states[object->num_contained_render_states] = i;
4853 object->num_contained_render_states++;
4856 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4857 if(object->changed.transform[i]) {
4858 object->contained_transform_states[object->num_contained_transform_states] = i;
4859 object->num_contained_transform_states++;
4862 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4863 if(object->changed.vertexShaderConstantsF[i]) {
4864 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4865 object->num_contained_vs_consts_f++;
4868 for(i = 0; i < MAX_CONST_I; i++) {
4869 if(object->changed.vertexShaderConstantsI[i]) {
4870 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4871 object->num_contained_vs_consts_i++;
4874 for(i = 0; i < MAX_CONST_B; i++) {
4875 if(object->changed.vertexShaderConstantsB[i]) {
4876 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4877 object->num_contained_vs_consts_b++;
4880 for(i = 0; i < MAX_CONST_I; i++) {
4881 if(object->changed.pixelShaderConstantsI[i]) {
4882 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4883 object->num_contained_ps_consts_i++;
4886 for(i = 0; i < MAX_CONST_B; i++) {
4887 if(object->changed.pixelShaderConstantsB[i]) {
4888 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4889 object->num_contained_ps_consts_b++;
4892 for(i = 0; i < MAX_TEXTURES; i++) {
4893 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4894 if(object->changed.textureState[i][j]) {
4895 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4896 object->contained_tss_states[object->num_contained_tss_states].state = j;
4897 object->num_contained_tss_states++;
4901 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4902 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4903 if(object->changed.samplerState[i][j]) {
4904 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4905 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4906 object->num_contained_sampler_states++;
4911 *ppStateBlock = (IWineD3DStateBlock*) object;
4912 This->isRecordingState = FALSE;
4913 This->updateStateBlock = This->stateBlock;
4914 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4915 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4916 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4917 return WINED3D_OK;
4920 /*****
4921 * Scene related functions
4922 *****/
4923 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4924 /* At the moment we have no need for any functionality at the beginning
4925 of a scene */
4926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4927 TRACE("(%p)\n", This);
4929 if(This->inScene) {
4930 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4931 return WINED3DERR_INVALIDCALL;
4933 This->inScene = TRUE;
4934 return WINED3D_OK;
4937 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4939 TRACE("(%p)\n", This);
4941 if(!This->inScene) {
4942 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4943 return WINED3DERR_INVALIDCALL;
4946 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4947 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4948 ENTER_GL();
4949 glFlush();
4950 checkGLcall("glFlush");
4951 LEAVE_GL();
4953 This->inScene = FALSE;
4954 return WINED3D_OK;
4957 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4958 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4959 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4961 IWineD3DSwapChain *swapChain = NULL;
4962 int i;
4963 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4965 TRACE("(%p) Presenting the frame\n", This);
4967 for(i = 0 ; i < swapchains ; i ++) {
4969 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4970 TRACE("presentinng chain %d, %p\n", i, swapChain);
4971 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4972 IWineD3DSwapChain_Release(swapChain);
4975 return WINED3D_OK;
4978 /* Not called from the VTable (internal subroutine) */
4979 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4980 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4981 float Z, DWORD Stencil) {
4982 GLbitfield glMask = 0;
4983 unsigned int i;
4984 WINED3DRECT curRect;
4985 RECT vp_rect;
4986 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4987 UINT drawable_width, drawable_height;
4988 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4990 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4991 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4992 * for the cleared parts, and the untouched parts.
4994 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4995 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4996 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4997 * checking all this if the dest surface is in the drawable anyway.
4999 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5000 while(1) {
5001 if(vp->X != 0 || vp->Y != 0 ||
5002 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5003 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5004 break;
5006 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5007 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5008 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5009 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5010 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5011 break;
5013 if(Count > 0 && pRects && (
5014 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5015 pRects[0].x2 < target->currentDesc.Width ||
5016 pRects[0].y2 < target->currentDesc.Height)) {
5017 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5018 break;
5020 break;
5024 target->get_drawable_size(target, &drawable_width, &drawable_height);
5026 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5027 ENTER_GL();
5029 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5030 apply_fbo_state((IWineD3DDevice *) This);
5033 /* Only set the values up once, as they are not changing */
5034 if (Flags & WINED3DCLEAR_STENCIL) {
5035 glClearStencil(Stencil);
5036 checkGLcall("glClearStencil");
5037 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5038 glStencilMask(0xFFFFFFFF);
5041 if (Flags & WINED3DCLEAR_ZBUFFER) {
5042 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5043 glDepthMask(GL_TRUE);
5044 glClearDepth(Z);
5045 checkGLcall("glClearDepth");
5046 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5047 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5049 if (vp->X != 0 || vp->Y != 0 ||
5050 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5051 surface_load_ds_location(This->stencilBufferTarget, location);
5053 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5054 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5055 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5056 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5057 surface_load_ds_location(This->stencilBufferTarget, location);
5059 else if (Count > 0 && pRects && (
5060 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5061 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5062 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5063 surface_load_ds_location(This->stencilBufferTarget, location);
5067 if (Flags & WINED3DCLEAR_TARGET) {
5068 TRACE("Clearing screen with glClear to color %x\n", Color);
5069 glClearColor(D3DCOLOR_R(Color),
5070 D3DCOLOR_G(Color),
5071 D3DCOLOR_B(Color),
5072 D3DCOLOR_A(Color));
5073 checkGLcall("glClearColor");
5075 /* Clear ALL colors! */
5076 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5077 glMask = glMask | GL_COLOR_BUFFER_BIT;
5080 vp_rect.left = vp->X;
5081 vp_rect.top = vp->Y;
5082 vp_rect.right = vp->X + vp->Width;
5083 vp_rect.bottom = vp->Y + vp->Height;
5084 if (!(Count > 0 && pRects)) {
5085 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5086 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5088 if(This->render_offscreen) {
5089 glScissor(vp_rect.left, vp_rect.top,
5090 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5091 } else {
5092 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5093 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5095 checkGLcall("glScissor");
5096 glClear(glMask);
5097 checkGLcall("glClear");
5098 } else {
5099 /* Now process each rect in turn */
5100 for (i = 0; i < Count; i++) {
5101 /* Note gl uses lower left, width/height */
5102 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5103 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5104 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5106 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5107 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5108 curRect.x1, (target->currentDesc.Height - curRect.y2),
5109 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5111 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5112 * The rectangle is not cleared, no error is returned, but further rectanlges are
5113 * still cleared if they are valid
5115 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5116 TRACE("Rectangle with negative dimensions, ignoring\n");
5117 continue;
5120 if(This->render_offscreen) {
5121 glScissor(curRect.x1, curRect.y1,
5122 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5123 } else {
5124 glScissor(curRect.x1, drawable_height - curRect.y2,
5125 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5127 checkGLcall("glScissor");
5129 glClear(glMask);
5130 checkGLcall("glClear");
5134 /* Restore the old values (why..?) */
5135 if (Flags & WINED3DCLEAR_STENCIL) {
5136 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5138 if (Flags & WINED3DCLEAR_TARGET) {
5139 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5140 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5141 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5142 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5143 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5145 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5146 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5148 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5149 /* TODO: Move the fbo logic into ModifyLocation() */
5150 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5151 target->Flags |= SFLAG_INTEXTURE;
5154 if (Flags & WINED3DCLEAR_ZBUFFER) {
5155 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5156 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5157 surface_modify_ds_location(This->stencilBufferTarget, location);
5160 LEAVE_GL();
5162 return WINED3D_OK;
5165 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5166 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5168 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5170 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5171 Count, pRects, Flags, Color, Z, Stencil);
5173 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5174 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5175 /* TODO: What about depth stencil buffers without stencil bits? */
5176 return WINED3DERR_INVALIDCALL;
5179 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5182 /*****
5183 * Drawing functions
5184 *****/
5185 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5186 UINT PrimitiveCount) {
5188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5190 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5191 debug_d3dprimitivetype(PrimitiveType),
5192 StartVertex, PrimitiveCount);
5194 if(!This->stateBlock->vertexDecl) {
5195 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5196 return WINED3DERR_INVALIDCALL;
5199 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5200 if(This->stateBlock->streamIsUP) {
5201 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5202 This->stateBlock->streamIsUP = FALSE;
5205 if(This->stateBlock->loadBaseVertexIndex != 0) {
5206 This->stateBlock->loadBaseVertexIndex = 0;
5207 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5209 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5210 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5211 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5212 return WINED3D_OK;
5215 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5216 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5217 WINED3DPRIMITIVETYPE PrimitiveType,
5218 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5221 UINT idxStride = 2;
5222 IWineD3DIndexBuffer *pIB;
5223 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5224 GLuint vbo;
5226 pIB = This->stateBlock->pIndexData;
5227 if (!pIB) {
5228 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5229 * without an index buffer set. (The first time at least...)
5230 * D3D8 simply dies, but I doubt it can do much harm to return
5231 * D3DERR_INVALIDCALL there as well. */
5232 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5233 return WINED3DERR_INVALIDCALL;
5236 if(!This->stateBlock->vertexDecl) {
5237 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5238 return WINED3DERR_INVALIDCALL;
5241 if(This->stateBlock->streamIsUP) {
5242 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5243 This->stateBlock->streamIsUP = FALSE;
5245 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5247 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5248 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5249 minIndex, NumVertices, startIndex, primCount);
5251 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5252 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5253 idxStride = 2;
5254 } else {
5255 idxStride = 4;
5258 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5259 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5260 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5263 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5264 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5266 return WINED3D_OK;
5269 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5270 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5271 UINT VertexStreamZeroStride) {
5272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5273 IWineD3DVertexBuffer *vb;
5275 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5276 debug_d3dprimitivetype(PrimitiveType),
5277 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5279 if(!This->stateBlock->vertexDecl) {
5280 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5281 return WINED3DERR_INVALIDCALL;
5284 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5285 vb = This->stateBlock->streamSource[0];
5286 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5287 if(vb) IWineD3DVertexBuffer_Release(vb);
5288 This->stateBlock->streamOffset[0] = 0;
5289 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5290 This->stateBlock->streamIsUP = TRUE;
5291 This->stateBlock->loadBaseVertexIndex = 0;
5293 /* TODO: Only mark dirty if drawing from a different UP address */
5294 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5296 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5297 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5299 /* MSDN specifies stream zero settings must be set to NULL */
5300 This->stateBlock->streamStride[0] = 0;
5301 This->stateBlock->streamSource[0] = NULL;
5303 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5304 * the new stream sources or use UP drawing again
5306 return WINED3D_OK;
5309 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5310 UINT MinVertexIndex, UINT NumVertices,
5311 UINT PrimitiveCount, CONST void* pIndexData,
5312 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5313 UINT VertexStreamZeroStride) {
5314 int idxStride;
5315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5316 IWineD3DVertexBuffer *vb;
5317 IWineD3DIndexBuffer *ib;
5319 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5320 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5321 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5322 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5324 if(!This->stateBlock->vertexDecl) {
5325 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5326 return WINED3DERR_INVALIDCALL;
5329 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5330 idxStride = 2;
5331 } else {
5332 idxStride = 4;
5335 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5336 vb = This->stateBlock->streamSource[0];
5337 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5338 if(vb) IWineD3DVertexBuffer_Release(vb);
5339 This->stateBlock->streamIsUP = TRUE;
5340 This->stateBlock->streamOffset[0] = 0;
5341 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5343 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5344 This->stateBlock->baseVertexIndex = 0;
5345 This->stateBlock->loadBaseVertexIndex = 0;
5346 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5347 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5350 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5352 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5353 This->stateBlock->streamSource[0] = NULL;
5354 This->stateBlock->streamStride[0] = 0;
5355 ib = This->stateBlock->pIndexData;
5356 if(ib) {
5357 IWineD3DIndexBuffer_Release(ib);
5358 This->stateBlock->pIndexData = NULL;
5360 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5361 * SetStreamSource to specify a vertex buffer
5364 return WINED3D_OK;
5367 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5368 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5370 /* Mark the state dirty until we have nicer tracking
5371 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5372 * that value.
5374 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5376 This->stateBlock->baseVertexIndex = 0;
5377 This->up_strided = DrawPrimStrideData;
5378 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5379 This->up_strided = NULL;
5380 return WINED3D_OK;
5383 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5385 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5387 /* Mark the state dirty until we have nicer tracking
5388 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5389 * that value.
5391 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5392 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5393 This->stateBlock->streamIsUP = TRUE;
5394 This->stateBlock->baseVertexIndex = 0;
5395 This->up_strided = DrawPrimStrideData;
5396 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5397 This->up_strided = NULL;
5398 return WINED3D_OK;
5401 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5402 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5403 * not callable by the app directly no parameter validation checks are needed here.
5405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5406 WINED3DLOCKED_BOX src;
5407 WINED3DLOCKED_BOX dst;
5408 HRESULT hr;
5409 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5411 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5412 * dirtification to improve loading performance.
5414 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5415 if(FAILED(hr)) return hr;
5416 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5417 if(FAILED(hr)) {
5418 IWineD3DVolume_UnlockBox(pSourceVolume);
5419 return hr;
5422 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5424 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5425 if(FAILED(hr)) {
5426 IWineD3DVolume_UnlockBox(pSourceVolume);
5427 } else {
5428 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5430 return hr;
5433 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5434 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5436 HRESULT hr = WINED3D_OK;
5437 WINED3DRESOURCETYPE sourceType;
5438 WINED3DRESOURCETYPE destinationType;
5439 int i ,levels;
5441 /* TODO: think about moving the code into IWineD3DBaseTexture */
5443 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5445 /* verify that the source and destination textures aren't NULL */
5446 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5447 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5448 This, pSourceTexture, pDestinationTexture);
5449 hr = WINED3DERR_INVALIDCALL;
5452 if (pSourceTexture == pDestinationTexture) {
5453 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5454 This, pSourceTexture, pDestinationTexture);
5455 hr = WINED3DERR_INVALIDCALL;
5457 /* Verify that the source and destination textures are the same type */
5458 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5459 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5461 if (sourceType != destinationType) {
5462 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5463 This);
5464 hr = WINED3DERR_INVALIDCALL;
5467 /* check that both textures have the identical numbers of levels */
5468 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5469 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5470 hr = WINED3DERR_INVALIDCALL;
5473 if (WINED3D_OK == hr) {
5475 /* Make sure that the destination texture is loaded */
5476 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5478 /* Update every surface level of the texture */
5479 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5481 switch (sourceType) {
5482 case WINED3DRTYPE_TEXTURE:
5484 IWineD3DSurface *srcSurface;
5485 IWineD3DSurface *destSurface;
5487 for (i = 0 ; i < levels ; ++i) {
5488 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5489 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5490 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5491 IWineD3DSurface_Release(srcSurface);
5492 IWineD3DSurface_Release(destSurface);
5493 if (WINED3D_OK != hr) {
5494 WARN("(%p) : Call to update surface failed\n", This);
5495 return hr;
5499 break;
5500 case WINED3DRTYPE_CUBETEXTURE:
5502 IWineD3DSurface *srcSurface;
5503 IWineD3DSurface *destSurface;
5504 WINED3DCUBEMAP_FACES faceType;
5506 for (i = 0 ; i < levels ; ++i) {
5507 /* Update each cube face */
5508 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5509 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5510 if (WINED3D_OK != hr) {
5511 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5512 } else {
5513 TRACE("Got srcSurface %p\n", srcSurface);
5515 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5516 if (WINED3D_OK != hr) {
5517 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5518 } else {
5519 TRACE("Got desrSurface %p\n", destSurface);
5521 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5522 IWineD3DSurface_Release(srcSurface);
5523 IWineD3DSurface_Release(destSurface);
5524 if (WINED3D_OK != hr) {
5525 WARN("(%p) : Call to update surface failed\n", This);
5526 return hr;
5531 break;
5533 case WINED3DRTYPE_VOLUMETEXTURE:
5535 IWineD3DVolume *srcVolume = NULL;
5536 IWineD3DVolume *destVolume = NULL;
5538 for (i = 0 ; i < levels ; ++i) {
5539 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5540 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5541 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5542 IWineD3DVolume_Release(srcVolume);
5543 IWineD3DVolume_Release(destVolume);
5544 if (WINED3D_OK != hr) {
5545 WARN("(%p) : Call to update volume failed\n", This);
5546 return hr;
5550 break;
5552 default:
5553 FIXME("(%p) : Unsupported source and destination type\n", This);
5554 hr = WINED3DERR_INVALIDCALL;
5558 return hr;
5561 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5562 IWineD3DSwapChain *swapChain;
5563 HRESULT hr;
5564 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5565 if(hr == WINED3D_OK) {
5566 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5567 IWineD3DSwapChain_Release(swapChain);
5569 return hr;
5572 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5574 /* return a sensible default */
5575 *pNumPasses = 1;
5576 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5577 FIXME("(%p) : stub\n", This);
5578 return WINED3D_OK;
5581 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5583 int i;
5585 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5586 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5587 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5588 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5593 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5595 int j;
5596 UINT NewSize;
5597 PALETTEENTRY **palettes;
5599 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5601 if (PaletteNumber >= MAX_PALETTES) {
5602 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5603 return WINED3DERR_INVALIDCALL;
5606 if (PaletteNumber >= This->NumberOfPalettes) {
5607 NewSize = This->NumberOfPalettes;
5608 do {
5609 NewSize *= 2;
5610 } while(PaletteNumber >= NewSize);
5611 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5612 if (!palettes) {
5613 ERR("Out of memory!\n");
5614 return E_OUTOFMEMORY;
5616 This->palettes = palettes;
5617 This->NumberOfPalettes = NewSize;
5620 if (!This->palettes[PaletteNumber]) {
5621 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5622 if (!This->palettes[PaletteNumber]) {
5623 ERR("Out of memory!\n");
5624 return E_OUTOFMEMORY;
5628 for (j = 0; j < 256; ++j) {
5629 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5630 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5631 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5632 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5634 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5635 TRACE("(%p) : returning\n", This);
5636 return WINED3D_OK;
5639 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5641 int j;
5642 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5643 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5644 /* What happens in such situation isn't documented; Native seems to silently abort
5645 on such conditions. Return Invalid Call. */
5646 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5647 return WINED3DERR_INVALIDCALL;
5649 for (j = 0; j < 256; ++j) {
5650 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5651 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5652 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5653 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5655 TRACE("(%p) : returning\n", This);
5656 return WINED3D_OK;
5659 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5661 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5662 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5663 (tested with reference rasterizer). Return Invalid Call. */
5664 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5665 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5666 return WINED3DERR_INVALIDCALL;
5668 /*TODO: stateblocks */
5669 if (This->currentPalette != PaletteNumber) {
5670 This->currentPalette = PaletteNumber;
5671 dirtify_p8_texture_samplers(This);
5673 TRACE("(%p) : returning\n", This);
5674 return WINED3D_OK;
5677 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5679 if (PaletteNumber == NULL) {
5680 WARN("(%p) : returning Invalid Call\n", This);
5681 return WINED3DERR_INVALIDCALL;
5683 /*TODO: stateblocks */
5684 *PaletteNumber = This->currentPalette;
5685 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5686 return WINED3D_OK;
5689 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5691 static BOOL showFixmes = TRUE;
5692 if (showFixmes) {
5693 FIXME("(%p) : stub\n", This);
5694 showFixmes = FALSE;
5697 This->softwareVertexProcessing = bSoftware;
5698 return WINED3D_OK;
5702 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5704 static BOOL showFixmes = TRUE;
5705 if (showFixmes) {
5706 FIXME("(%p) : stub\n", This);
5707 showFixmes = FALSE;
5709 return This->softwareVertexProcessing;
5713 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5715 IWineD3DSwapChain *swapChain;
5716 HRESULT hr;
5718 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5720 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5721 if(hr == WINED3D_OK){
5722 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5723 IWineD3DSwapChain_Release(swapChain);
5724 }else{
5725 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5727 return hr;
5731 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5733 static BOOL showfixmes = TRUE;
5734 if(nSegments != 0.0f) {
5735 if( showfixmes) {
5736 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5737 showfixmes = FALSE;
5740 return WINED3D_OK;
5743 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5745 static BOOL showfixmes = TRUE;
5746 if( showfixmes) {
5747 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5748 showfixmes = FALSE;
5750 return 0.0f;
5753 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5755 /** TODO: remove casts to IWineD3DSurfaceImpl
5756 * NOTE: move code to surface to accomplish this
5757 ****************************************/
5758 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5759 int srcWidth, srcHeight;
5760 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5761 WINED3DFORMAT destFormat, srcFormat;
5762 UINT destSize;
5763 int srcLeft, destLeft, destTop;
5764 WINED3DPOOL srcPool, destPool;
5765 int offset = 0;
5766 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5767 glDescriptor *glDescription = NULL;
5768 GLenum dummy;
5769 int sampler;
5770 int bpp;
5771 CONVERT_TYPES convert = NO_CONVERSION;
5773 WINED3DSURFACE_DESC winedesc;
5775 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5776 memset(&winedesc, 0, sizeof(winedesc));
5777 winedesc.Width = &srcSurfaceWidth;
5778 winedesc.Height = &srcSurfaceHeight;
5779 winedesc.Pool = &srcPool;
5780 winedesc.Format = &srcFormat;
5782 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5784 winedesc.Width = &destSurfaceWidth;
5785 winedesc.Height = &destSurfaceHeight;
5786 winedesc.Pool = &destPool;
5787 winedesc.Format = &destFormat;
5788 winedesc.Size = &destSize;
5790 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5792 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5793 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5794 return WINED3DERR_INVALIDCALL;
5797 /* This call loads the opengl surface directly, instead of copying the surface to the
5798 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5799 * copy in sysmem and use regular surface loading.
5801 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5802 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5803 if(convert != NO_CONVERSION) {
5804 return IWineD3DSurface_BltFast(pDestinationSurface,
5805 pDestPoint ? pDestPoint->x : 0,
5806 pDestPoint ? pDestPoint->y : 0,
5807 pSourceSurface, (RECT *) pSourceRect, 0);
5810 if (destFormat == WINED3DFMT_UNKNOWN) {
5811 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5812 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5814 /* Get the update surface description */
5815 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5818 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5820 ENTER_GL();
5822 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5823 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5824 checkGLcall("glActiveTextureARB");
5827 /* Make sure the surface is loaded and up to date */
5828 IWineD3DSurface_PreLoad(pDestinationSurface);
5830 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5832 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5833 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5834 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5835 srcLeft = pSourceRect ? pSourceRect->left : 0;
5836 destLeft = pDestPoint ? pDestPoint->x : 0;
5837 destTop = pDestPoint ? pDestPoint->y : 0;
5840 /* This function doesn't support compressed textures
5841 the pitch is just bytesPerPixel * width */
5842 if(srcWidth != srcSurfaceWidth || srcLeft ){
5843 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5844 offset += srcLeft * pSrcSurface->bytesPerPixel;
5845 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5847 /* TODO DXT formats */
5849 if(pSourceRect != NULL && pSourceRect->top != 0){
5850 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5852 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5853 ,This
5854 ,glDescription->level
5855 ,destLeft
5856 ,destTop
5857 ,srcWidth
5858 ,srcHeight
5859 ,glDescription->glFormat
5860 ,glDescription->glType
5861 ,IWineD3DSurface_GetData(pSourceSurface)
5864 /* Sanity check */
5865 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5867 /* need to lock the surface to get the data */
5868 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5871 /* TODO: Cube and volume support */
5872 if(rowoffset != 0){
5873 /* not a whole row so we have to do it a line at a time */
5874 int j;
5876 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5877 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5879 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5881 glTexSubImage2D(glDescription->target
5882 ,glDescription->level
5883 ,destLeft
5885 ,srcWidth
5887 ,glDescription->glFormat
5888 ,glDescription->glType
5889 ,data /* could be quicker using */
5891 data += rowoffset;
5894 } else { /* Full width, so just write out the whole texture */
5896 if (WINED3DFMT_DXT1 == destFormat ||
5897 WINED3DFMT_DXT2 == destFormat ||
5898 WINED3DFMT_DXT3 == destFormat ||
5899 WINED3DFMT_DXT4 == destFormat ||
5900 WINED3DFMT_DXT5 == destFormat) {
5901 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5902 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5903 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5904 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5905 } if (destFormat != srcFormat) {
5906 FIXME("Updating mixed format compressed texture is not curretly support\n");
5907 } else {
5908 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5909 glDescription->level,
5910 glDescription->glFormatInternal,
5911 srcWidth,
5912 srcHeight,
5914 destSize,
5915 IWineD3DSurface_GetData(pSourceSurface));
5917 } else {
5918 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5922 } else {
5923 glTexSubImage2D(glDescription->target
5924 ,glDescription->level
5925 ,destLeft
5926 ,destTop
5927 ,srcWidth
5928 ,srcHeight
5929 ,glDescription->glFormat
5930 ,glDescription->glType
5931 ,IWineD3DSurface_GetData(pSourceSurface)
5935 checkGLcall("glTexSubImage2D");
5937 LEAVE_GL();
5939 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5940 sampler = This->rev_tex_unit_map[0];
5941 if (sampler != -1) {
5942 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5945 return WINED3D_OK;
5948 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5950 struct WineD3DRectPatch *patch;
5951 unsigned int i;
5952 struct list *e;
5953 BOOL found;
5954 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5956 if(!(Handle || pRectPatchInfo)) {
5957 /* TODO: Write a test for the return value, thus the FIXME */
5958 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5959 return WINED3DERR_INVALIDCALL;
5962 if(Handle) {
5963 i = PATCHMAP_HASHFUNC(Handle);
5964 found = FALSE;
5965 LIST_FOR_EACH(e, &This->patches[i]) {
5966 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5967 if(patch->Handle == Handle) {
5968 found = TRUE;
5969 break;
5973 if(!found) {
5974 TRACE("Patch does not exist. Creating a new one\n");
5975 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5976 patch->Handle = Handle;
5977 list_add_head(&This->patches[i], &patch->entry);
5978 } else {
5979 TRACE("Found existing patch %p\n", patch);
5981 } else {
5982 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5983 * attributes we have to tesselate, read back, and draw. This needs a patch
5984 * management structure instance. Create one.
5986 * A possible improvement is to check if a vertex shader is used, and if not directly
5987 * draw the patch.
5989 FIXME("Drawing an uncached patch. This is slow\n");
5990 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5993 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5994 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5995 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5996 HRESULT hr;
5997 TRACE("Tesselation density or patch info changed, retesselating\n");
5999 if(pRectPatchInfo) {
6000 patch->RectPatchInfo = *pRectPatchInfo;
6002 patch->numSegs[0] = pNumSegs[0];
6003 patch->numSegs[1] = pNumSegs[1];
6004 patch->numSegs[2] = pNumSegs[2];
6005 patch->numSegs[3] = pNumSegs[3];
6007 hr = tesselate_rectpatch(This, patch);
6008 if(FAILED(hr)) {
6009 WARN("Patch tesselation failed\n");
6011 /* Do not release the handle to store the params of the patch */
6012 if(!Handle) {
6013 HeapFree(GetProcessHeap(), 0, patch);
6015 return hr;
6019 This->currentPatch = patch;
6020 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6021 This->currentPatch = NULL;
6023 /* Destroy uncached patches */
6024 if(!Handle) {
6025 HeapFree(GetProcessHeap(), 0, patch->mem);
6026 HeapFree(GetProcessHeap(), 0, patch);
6028 return WINED3D_OK;
6031 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6033 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6034 FIXME("(%p) : Stub\n", This);
6035 return WINED3D_OK;
6038 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6040 int i;
6041 struct WineD3DRectPatch *patch;
6042 struct list *e;
6043 TRACE("(%p) Handle(%d)\n", This, Handle);
6045 i = PATCHMAP_HASHFUNC(Handle);
6046 LIST_FOR_EACH(e, &This->patches[i]) {
6047 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6048 if(patch->Handle == Handle) {
6049 TRACE("Deleting patch %p\n", patch);
6050 list_remove(&patch->entry);
6051 HeapFree(GetProcessHeap(), 0, patch->mem);
6052 HeapFree(GetProcessHeap(), 0, patch);
6053 return WINED3D_OK;
6057 /* TODO: Write a test for the return value */
6058 FIXME("Attempt to destroy nonexistent patch\n");
6059 return WINED3DERR_INVALIDCALL;
6062 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6063 HRESULT hr;
6064 IWineD3DSwapChain *swapchain;
6066 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6067 if (SUCCEEDED(hr)) {
6068 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6069 return swapchain;
6072 return NULL;
6075 void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
6076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6078 if (!*fbo) {
6079 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
6080 checkGLcall("glGenFramebuffersEXT()");
6082 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
6083 checkGLcall("glBindFramebuffer()");
6086 /* TODO: Handle stencil attachments */
6087 void attach_depth_stencil_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, IWineD3DSurface *depth_stencil, BOOL use_render_buffer) {
6088 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6090 if (use_render_buffer && depth_stencil_impl->current_renderbuffer) {
6091 GL_EXTCALL(glFramebufferRenderbufferEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6092 checkGLcall("glFramebufferRenderbufferEXT()");
6093 } else {
6094 IWineD3DBaseTextureImpl *texture_impl;
6095 GLenum texttarget, target;
6096 GLint old_binding = 0;
6098 texttarget = depth_stencil_impl->glDescription.target;
6099 if(texttarget == GL_TEXTURE_2D) {
6100 target = GL_TEXTURE_2D;
6101 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6102 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6103 target = GL_TEXTURE_RECTANGLE_ARB;
6104 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6105 } else {
6106 target = GL_TEXTURE_CUBE_MAP_ARB;
6107 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6110 IWineD3DSurface_PreLoad(depth_stencil);
6112 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6113 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6114 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6115 glBindTexture(target, old_binding);
6117 /* Update base texture states array */
6118 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6119 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6120 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6121 if (texture_impl->baseTexture.bindCount) {
6122 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6125 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6128 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6129 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6130 checkGLcall("glFramebufferTexture2DEXT()");
6134 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
6135 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
6136 IWineD3DBaseTextureImpl *texture_impl;
6137 GLenum texttarget, target;
6138 GLint old_binding;
6140 texttarget = surface_impl->glDescription.target;
6141 if(texttarget == GL_TEXTURE_2D) {
6142 target = GL_TEXTURE_2D;
6143 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6144 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6145 target = GL_TEXTURE_RECTANGLE_ARB;
6146 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6147 } else {
6148 target = GL_TEXTURE_CUBE_MAP_ARB;
6149 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6152 IWineD3DSurface_PreLoad(surface);
6154 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6155 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6156 glBindTexture(target, old_binding);
6158 /* Update base texture states array */
6159 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6160 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6161 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6162 if (texture_impl->baseTexture.bindCount) {
6163 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6166 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6169 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6170 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6172 checkGLcall("attach_surface_fbo");
6175 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6177 IWineD3DSwapChain *swapchain;
6179 swapchain = get_swapchain(surface);
6180 if (swapchain) {
6181 GLenum buffer;
6183 TRACE("Surface %p is onscreen\n", surface);
6185 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6186 ENTER_GL();
6187 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6188 buffer = surface_get_gl_buffer(surface, swapchain);
6189 glDrawBuffer(buffer);
6190 checkGLcall("glDrawBuffer()");
6191 } else {
6192 TRACE("Surface %p is offscreen\n", surface);
6194 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6195 ENTER_GL();
6196 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
6197 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6198 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6199 checkGLcall("glFramebufferRenderbufferEXT");
6202 if (rect) {
6203 glEnable(GL_SCISSOR_TEST);
6204 if(!swapchain) {
6205 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6206 } else {
6207 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6208 rect->x2 - rect->x1, rect->y2 - rect->y1);
6210 checkGLcall("glScissor");
6211 } else {
6212 glDisable(GL_SCISSOR_TEST);
6214 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6216 glDisable(GL_BLEND);
6217 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6219 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6220 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6222 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6223 glClear(GL_COLOR_BUFFER_BIT);
6224 checkGLcall("glClear");
6226 if (This->render_offscreen) {
6227 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6228 } else {
6229 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6230 checkGLcall("glBindFramebuffer()");
6233 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6234 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6235 glDrawBuffer(GL_BACK);
6236 checkGLcall("glDrawBuffer()");
6239 LEAVE_GL();
6242 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6243 unsigned int r, g, b, a;
6244 DWORD ret;
6246 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6247 destfmt == WINED3DFMT_R8G8B8)
6248 return color;
6250 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6252 a = (color & 0xff000000) >> 24;
6253 r = (color & 0x00ff0000) >> 16;
6254 g = (color & 0x0000ff00) >> 8;
6255 b = (color & 0x000000ff) >> 0;
6257 switch(destfmt)
6259 case WINED3DFMT_R5G6B5:
6260 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6261 r = (r * 32) / 256;
6262 g = (g * 64) / 256;
6263 b = (b * 32) / 256;
6264 ret = r << 11;
6265 ret |= g << 5;
6266 ret |= b;
6267 TRACE("Returning %08x\n", ret);
6268 return ret;
6270 case WINED3DFMT_X1R5G5B5:
6271 case WINED3DFMT_A1R5G5B5:
6272 a = (a * 2) / 256;
6273 r = (r * 32) / 256;
6274 g = (g * 32) / 256;
6275 b = (b * 32) / 256;
6276 ret = a << 15;
6277 ret |= r << 10;
6278 ret |= g << 5;
6279 ret |= b << 0;
6280 TRACE("Returning %08x\n", ret);
6281 return ret;
6283 case WINED3DFMT_A8:
6284 TRACE("Returning %08x\n", a);
6285 return a;
6287 case WINED3DFMT_X4R4G4B4:
6288 case WINED3DFMT_A4R4G4B4:
6289 a = (a * 16) / 256;
6290 r = (r * 16) / 256;
6291 g = (g * 16) / 256;
6292 b = (b * 16) / 256;
6293 ret = a << 12;
6294 ret |= r << 8;
6295 ret |= g << 4;
6296 ret |= b << 0;
6297 TRACE("Returning %08x\n", ret);
6298 return ret;
6300 case WINED3DFMT_R3G3B2:
6301 r = (r * 8) / 256;
6302 g = (g * 8) / 256;
6303 b = (b * 4) / 256;
6304 ret = r << 5;
6305 ret |= g << 2;
6306 ret |= b << 0;
6307 TRACE("Returning %08x\n", ret);
6308 return ret;
6310 case WINED3DFMT_X8B8G8R8:
6311 case WINED3DFMT_A8B8G8R8:
6312 ret = a << 24;
6313 ret |= b << 16;
6314 ret |= g << 8;
6315 ret |= r << 0;
6316 TRACE("Returning %08x\n", ret);
6317 return ret;
6319 case WINED3DFMT_A2R10G10B10:
6320 a = (a * 4) / 256;
6321 r = (r * 1024) / 256;
6322 g = (g * 1024) / 256;
6323 b = (b * 1024) / 256;
6324 ret = a << 30;
6325 ret |= r << 20;
6326 ret |= g << 10;
6327 ret |= b << 0;
6328 TRACE("Returning %08x\n", ret);
6329 return ret;
6331 case WINED3DFMT_A2B10G10R10:
6332 a = (a * 4) / 256;
6333 r = (r * 1024) / 256;
6334 g = (g * 1024) / 256;
6335 b = (b * 1024) / 256;
6336 ret = a << 30;
6337 ret |= b << 20;
6338 ret |= g << 10;
6339 ret |= r << 0;
6340 TRACE("Returning %08x\n", ret);
6341 return ret;
6343 default:
6344 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6345 return 0;
6349 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6351 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6352 WINEDDBLTFX BltFx;
6353 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6355 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6356 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6357 return WINED3DERR_INVALIDCALL;
6360 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6361 color_fill_fbo(iface, pSurface, pRect, color);
6362 return WINED3D_OK;
6363 } else {
6364 /* Just forward this to the DirectDraw blitting engine */
6365 memset(&BltFx, 0, sizeof(BltFx));
6366 BltFx.dwSize = sizeof(BltFx);
6367 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6368 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6372 /* rendertarget and depth stencil functions */
6373 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6376 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6377 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6378 return WINED3DERR_INVALIDCALL;
6381 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6382 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6383 /* Note inc ref on returned surface */
6384 if(*ppRenderTarget != NULL)
6385 IWineD3DSurface_AddRef(*ppRenderTarget);
6386 return WINED3D_OK;
6389 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6391 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6392 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6393 IWineD3DSwapChainImpl *Swapchain;
6394 HRESULT hr;
6396 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6398 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6399 if(hr != WINED3D_OK) {
6400 ERR("Can't get the swapchain\n");
6401 return hr;
6404 /* Make sure to release the swapchain */
6405 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6407 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6408 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6409 return WINED3DERR_INVALIDCALL;
6411 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6412 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6413 return WINED3DERR_INVALIDCALL;
6416 if(Swapchain->frontBuffer != Front) {
6417 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6419 if(Swapchain->frontBuffer)
6420 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6421 Swapchain->frontBuffer = Front;
6423 if(Swapchain->frontBuffer) {
6424 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6428 if(Back && !Swapchain->backBuffer) {
6429 /* We need memory for the back buffer array - only one back buffer this way */
6430 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6431 if(!Swapchain->backBuffer) {
6432 ERR("Out of memory\n");
6433 return E_OUTOFMEMORY;
6437 if(Swapchain->backBuffer[0] != Back) {
6438 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6440 /* What to do about the context here in the case of multithreading? Not sure.
6441 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6443 ENTER_GL();
6444 if(!Swapchain->backBuffer[0]) {
6445 /* GL was told to draw to the front buffer at creation,
6446 * undo that
6448 glDrawBuffer(GL_BACK);
6449 checkGLcall("glDrawBuffer(GL_BACK)");
6450 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6451 Swapchain->presentParms.BackBufferCount = 1;
6452 } else if (!Back) {
6453 /* That makes problems - disable for now */
6454 /* glDrawBuffer(GL_FRONT); */
6455 checkGLcall("glDrawBuffer(GL_FRONT)");
6456 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6457 Swapchain->presentParms.BackBufferCount = 0;
6459 LEAVE_GL();
6461 if(Swapchain->backBuffer[0])
6462 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6463 Swapchain->backBuffer[0] = Back;
6465 if(Swapchain->backBuffer[0]) {
6466 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6467 } else {
6468 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6469 Swapchain->backBuffer = NULL;
6474 return WINED3D_OK;
6477 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6479 *ppZStencilSurface = This->stencilBufferTarget;
6480 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6482 if(*ppZStencilSurface != NULL) {
6483 /* Note inc ref on returned surface */
6484 IWineD3DSurface_AddRef(*ppZStencilSurface);
6485 return WINED3D_OK;
6486 } else {
6487 return WINED3DERR_NOTFOUND;
6491 /* TODO: Handle stencil attachments */
6492 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6495 TRACE("Set depth stencil to %p\n", depth_stencil);
6497 if (depth_stencil) {
6498 attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, depth_stencil, TRUE);
6499 } else {
6500 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6501 checkGLcall("glFramebufferTexture2DEXT()");
6505 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6508 TRACE("Set render target %u to %p\n", idx, render_target);
6510 if (render_target) {
6511 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6512 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6513 } else {
6514 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6515 checkGLcall("glFramebufferTexture2DEXT()");
6517 This->draw_buffers[idx] = GL_NONE;
6521 static void check_fbo_status(IWineD3DDevice *iface) {
6522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6523 GLenum status;
6525 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6526 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6527 TRACE("FBO complete\n");
6528 } else {
6529 IWineD3DSurfaceImpl *attachment;
6530 int i;
6531 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6533 /* Dump the FBO attachments */
6534 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6535 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6536 if (attachment) {
6537 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6538 attachment->pow2Width, attachment->pow2Height);
6541 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6542 if (attachment) {
6543 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6544 attachment->pow2Width, attachment->pow2Height);
6549 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6551 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6552 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6554 if (!ds_impl) return FALSE;
6556 if (ds_impl->current_renderbuffer) {
6557 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6558 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6561 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6562 rt_impl->pow2Height != ds_impl->pow2Height);
6565 void apply_fbo_state(IWineD3DDevice *iface) {
6566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6567 unsigned int i;
6569 if (This->render_offscreen) {
6570 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6572 /* Apply render targets */
6573 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6574 IWineD3DSurface *render_target = This->render_targets[i];
6575 if (This->fbo_color_attachments[i] != render_target) {
6576 set_render_target_fbo(iface, i, render_target);
6577 This->fbo_color_attachments[i] = render_target;
6581 /* Apply depth targets */
6582 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6583 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6584 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6586 if (This->stencilBufferTarget) {
6587 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6589 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6590 This->fbo_depth_attachment = This->stencilBufferTarget;
6593 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6594 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6595 checkGLcall("glDrawBuffers()");
6596 } else {
6597 glDrawBuffer(This->draw_buffers[0]);
6598 checkGLcall("glDrawBuffer()");
6600 } else {
6601 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6604 check_fbo_status(iface);
6607 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6608 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6610 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6611 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6612 GLenum gl_filter;
6613 POINT offset = {0, 0};
6615 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6616 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6617 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6618 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6620 switch (filter) {
6621 case WINED3DTEXF_LINEAR:
6622 gl_filter = GL_LINEAR;
6623 break;
6625 default:
6626 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6627 case WINED3DTEXF_NONE:
6628 case WINED3DTEXF_POINT:
6629 gl_filter = GL_NEAREST;
6630 break;
6633 /* Attach src surface to src fbo */
6634 src_swapchain = get_swapchain(src_surface);
6635 if (src_swapchain) {
6636 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6638 TRACE("Source surface %p is onscreen\n", src_surface);
6639 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6640 /* Make sure the drawable is up to date. In the offscreen case
6641 * attach_surface_fbo() implicitly takes care of this. */
6642 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6644 if(buffer == GL_FRONT) {
6645 RECT windowsize;
6646 UINT h;
6647 ClientToScreen(This->ddraw_window, &offset);
6648 GetClientRect(This->ddraw_window, &windowsize);
6649 h = windowsize.bottom - windowsize.top;
6650 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6651 src_rect->y1 = offset.y + h - src_rect->y1;
6652 src_rect->y2 = offset.y + h - src_rect->y2;
6653 } else {
6654 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6655 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6658 ENTER_GL();
6659 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6660 glReadBuffer(buffer);
6661 checkGLcall("glReadBuffer()");
6662 } else {
6663 TRACE("Source surface %p is offscreen\n", src_surface);
6664 ENTER_GL();
6665 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6666 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6667 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6668 checkGLcall("glReadBuffer()");
6669 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6670 checkGLcall("glFramebufferRenderbufferEXT");
6672 LEAVE_GL();
6674 /* Attach dst surface to dst fbo */
6675 dst_swapchain = get_swapchain(dst_surface);
6676 if (dst_swapchain) {
6677 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6679 TRACE("Destination surface %p is onscreen\n", dst_surface);
6680 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6681 /* Make sure the drawable is up to date. In the offscreen case
6682 * attach_surface_fbo() implicitly takes care of this. */
6683 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6685 if(buffer == GL_FRONT) {
6686 RECT windowsize;
6687 UINT h;
6688 ClientToScreen(This->ddraw_window, &offset);
6689 GetClientRect(This->ddraw_window, &windowsize);
6690 h = windowsize.bottom - windowsize.top;
6691 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6692 dst_rect->y1 = offset.y + h - dst_rect->y1;
6693 dst_rect->y2 = offset.y + h - dst_rect->y2;
6694 } else {
6695 /* Screen coords = window coords, surface height = window height */
6696 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6697 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6700 ENTER_GL();
6701 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6702 glDrawBuffer(buffer);
6703 checkGLcall("glDrawBuffer()");
6704 } else {
6705 TRACE("Destination surface %p is offscreen\n", dst_surface);
6707 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6708 if(!src_swapchain) {
6709 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6712 ENTER_GL();
6713 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6714 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6715 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6716 checkGLcall("glDrawBuffer()");
6717 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6718 checkGLcall("glFramebufferRenderbufferEXT");
6720 glDisable(GL_SCISSOR_TEST);
6721 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6723 if (flip) {
6724 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6725 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6726 checkGLcall("glBlitFramebuffer()");
6727 } else {
6728 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6729 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6730 checkGLcall("glBlitFramebuffer()");
6733 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6735 if (This->render_offscreen) {
6736 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6737 } else {
6738 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6739 checkGLcall("glBindFramebuffer()");
6742 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6743 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6744 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6745 glDrawBuffer(GL_BACK);
6746 checkGLcall("glDrawBuffer()");
6748 LEAVE_GL();
6751 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6753 WINED3DVIEWPORT viewport;
6755 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6757 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6758 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6759 This, RenderTargetIndex, GL_LIMITS(buffers));
6760 return WINED3DERR_INVALIDCALL;
6763 /* MSDN says that null disables the render target
6764 but a device must always be associated with a render target
6765 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6767 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6768 FIXME("Trying to set render target 0 to NULL\n");
6769 return WINED3DERR_INVALIDCALL;
6771 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6772 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);
6773 return WINED3DERR_INVALIDCALL;
6776 /* If we are trying to set what we already have, don't bother */
6777 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6778 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6779 return WINED3D_OK;
6781 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6782 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6783 This->render_targets[RenderTargetIndex] = pRenderTarget;
6785 /* Render target 0 is special */
6786 if(RenderTargetIndex == 0) {
6787 /* Finally, reset the viewport as the MSDN states. */
6788 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6789 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6790 viewport.X = 0;
6791 viewport.Y = 0;
6792 viewport.MaxZ = 1.0f;
6793 viewport.MinZ = 0.0f;
6794 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6795 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6796 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6798 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6800 return WINED3D_OK;
6803 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6805 HRESULT hr = WINED3D_OK;
6806 IWineD3DSurface *tmp;
6808 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6810 if (pNewZStencil == This->stencilBufferTarget) {
6811 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6812 } else {
6813 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6814 * depending on the renter target implementation being used.
6815 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6816 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6817 * stencil buffer and incur an extra memory overhead
6818 ******************************************************/
6820 if (This->stencilBufferTarget) {
6821 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6822 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6823 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6826 tmp = This->stencilBufferTarget;
6827 This->stencilBufferTarget = pNewZStencil;
6828 /* should we be calling the parent or the wined3d surface? */
6829 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6830 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6831 hr = WINED3D_OK;
6833 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6834 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6835 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6836 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6837 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6841 return hr;
6844 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6845 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6847 /* TODO: the use of Impl is deprecated. */
6848 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6849 WINED3DLOCKED_RECT lockedRect;
6851 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6853 /* some basic validation checks */
6854 if(This->cursorTexture) {
6855 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6856 ENTER_GL();
6857 glDeleteTextures(1, &This->cursorTexture);
6858 LEAVE_GL();
6859 This->cursorTexture = 0;
6862 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6863 This->haveHardwareCursor = TRUE;
6864 else
6865 This->haveHardwareCursor = FALSE;
6867 if(pCursorBitmap) {
6868 WINED3DLOCKED_RECT rect;
6870 /* MSDN: Cursor must be A8R8G8B8 */
6871 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6872 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6873 return WINED3DERR_INVALIDCALL;
6876 /* MSDN: Cursor must be smaller than the display mode */
6877 if(pSur->currentDesc.Width > This->ddraw_width ||
6878 pSur->currentDesc.Height > This->ddraw_height) {
6879 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);
6880 return WINED3DERR_INVALIDCALL;
6883 if (!This->haveHardwareCursor) {
6884 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6886 /* Do not store the surface's pointer because the application may
6887 * release it after setting the cursor image. Windows doesn't
6888 * addref the set surface, so we can't do this either without
6889 * creating circular refcount dependencies. Copy out the gl texture
6890 * instead.
6892 This->cursorWidth = pSur->currentDesc.Width;
6893 This->cursorHeight = pSur->currentDesc.Height;
6894 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6896 const GlPixelFormatDesc *glDesc;
6897 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6898 char *mem, *bits = (char *)rect.pBits;
6899 GLint intfmt = glDesc->glInternal;
6900 GLint format = glDesc->glFormat;
6901 GLint type = glDesc->glType;
6902 INT height = This->cursorHeight;
6903 INT width = This->cursorWidth;
6904 INT bpp = tableEntry->bpp;
6905 INT i, sampler;
6907 /* Reformat the texture memory (pitch and width can be
6908 * different) */
6909 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6910 for(i = 0; i < height; i++)
6911 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6912 IWineD3DSurface_UnlockRect(pCursorBitmap);
6913 ENTER_GL();
6915 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6916 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6917 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6920 /* Make sure that a proper texture unit is selected */
6921 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6922 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6923 checkGLcall("glActiveTextureARB");
6925 sampler = This->rev_tex_unit_map[0];
6926 if (sampler != -1) {
6927 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6929 /* Create a new cursor texture */
6930 glGenTextures(1, &This->cursorTexture);
6931 checkGLcall("glGenTextures");
6932 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6933 checkGLcall("glBindTexture");
6934 /* Copy the bitmap memory into the cursor texture */
6935 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6936 HeapFree(GetProcessHeap(), 0, mem);
6937 checkGLcall("glTexImage2D");
6939 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6940 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6941 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6944 LEAVE_GL();
6946 else
6948 FIXME("A cursor texture was not returned.\n");
6949 This->cursorTexture = 0;
6952 else
6954 /* Draw a hardware cursor */
6955 ICONINFO cursorInfo;
6956 HCURSOR cursor;
6957 /* Create and clear maskBits because it is not needed for
6958 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6959 * chunks. */
6960 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6961 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6962 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6963 WINED3DLOCK_NO_DIRTY_UPDATE |
6964 WINED3DLOCK_READONLY
6966 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6967 pSur->currentDesc.Height);
6969 cursorInfo.fIcon = FALSE;
6970 cursorInfo.xHotspot = XHotSpot;
6971 cursorInfo.yHotspot = YHotSpot;
6972 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6973 pSur->currentDesc.Height, 1,
6974 1, &maskBits);
6975 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6976 pSur->currentDesc.Height, 1,
6977 32, lockedRect.pBits);
6978 IWineD3DSurface_UnlockRect(pCursorBitmap);
6979 /* Create our cursor and clean up. */
6980 cursor = CreateIconIndirect(&cursorInfo);
6981 SetCursor(cursor);
6982 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6983 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6984 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6985 This->hardwareCursor = cursor;
6986 HeapFree(GetProcessHeap(), 0, maskBits);
6990 This->xHotSpot = XHotSpot;
6991 This->yHotSpot = YHotSpot;
6992 return WINED3D_OK;
6995 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6997 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6999 This->xScreenSpace = XScreenSpace;
7000 This->yScreenSpace = YScreenSpace;
7002 return;
7006 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7008 BOOL oldVisible = This->bCursorVisible;
7009 POINT pt;
7011 TRACE("(%p) : visible(%d)\n", This, bShow);
7014 * When ShowCursor is first called it should make the cursor appear at the OS's last
7015 * known cursor position. Because of this, some applications just repetitively call
7016 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7018 GetCursorPos(&pt);
7019 This->xScreenSpace = pt.x;
7020 This->yScreenSpace = pt.y;
7022 if (This->haveHardwareCursor) {
7023 This->bCursorVisible = bShow;
7024 if (bShow)
7025 SetCursor(This->hardwareCursor);
7026 else
7027 SetCursor(NULL);
7029 else
7031 if (This->cursorTexture)
7032 This->bCursorVisible = bShow;
7035 return oldVisible;
7038 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7040 IWineD3DResourceImpl *resource;
7041 TRACE("(%p) : state (%u)\n", This, This->state);
7043 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7044 switch (This->state) {
7045 case WINED3D_OK:
7046 return WINED3D_OK;
7047 case WINED3DERR_DEVICELOST:
7049 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7050 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7051 return WINED3DERR_DEVICENOTRESET;
7053 return WINED3DERR_DEVICELOST;
7055 case WINED3DERR_DRIVERINTERNALERROR:
7056 return WINED3DERR_DRIVERINTERNALERROR;
7059 /* Unknown state */
7060 return WINED3DERR_DRIVERINTERNALERROR;
7064 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7066 /** FIXME: Resource tracking needs to be done,
7067 * The closes we can do to this is set the priorities of all managed textures low
7068 * and then reset them.
7069 ***********************************************************/
7070 FIXME("(%p) : stub\n", This);
7071 return WINED3D_OK;
7074 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7075 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7077 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7078 if(surface->Flags & SFLAG_DIBSECTION) {
7079 /* Release the DC */
7080 SelectObject(surface->hDC, surface->dib.holdbitmap);
7081 DeleteDC(surface->hDC);
7082 /* Release the DIB section */
7083 DeleteObject(surface->dib.DIBsection);
7084 surface->dib.bitmap_data = NULL;
7085 surface->resource.allocatedMemory = NULL;
7086 surface->Flags &= ~SFLAG_DIBSECTION;
7088 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7089 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7090 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7091 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7092 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7093 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7094 } else {
7095 surface->pow2Width = surface->pow2Height = 1;
7096 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7097 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7099 surface->glRect.left = 0;
7100 surface->glRect.top = 0;
7101 surface->glRect.right = surface->pow2Width;
7102 surface->glRect.bottom = surface->pow2Height;
7104 if(surface->glDescription.textureName) {
7105 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7106 ENTER_GL();
7107 glDeleteTextures(1, &surface->glDescription.textureName);
7108 LEAVE_GL();
7109 surface->glDescription.textureName = 0;
7110 surface->Flags &= ~SFLAG_CLIENT;
7112 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7113 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7114 surface->Flags |= SFLAG_NONPOW2;
7115 } else {
7116 surface->Flags &= ~SFLAG_NONPOW2;
7118 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7119 surface->resource.allocatedMemory = NULL;
7120 surface->resource.heapMemory = NULL;
7121 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7122 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7123 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7124 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7125 } else {
7126 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7130 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7131 TRACE("Unloading resource %p\n", resource);
7132 IWineD3DResource_UnLoad(resource);
7133 IWineD3DResource_Release(resource);
7134 return S_OK;
7137 static void reset_fbo_state(IWineD3DDevice *iface) {
7138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7139 unsigned int i;
7141 ENTER_GL();
7142 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7143 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
7145 if (This->fbo) {
7146 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
7147 This->fbo = 0;
7149 if (This->src_fbo) {
7150 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
7151 This->src_fbo = 0;
7153 if (This->dst_fbo) {
7154 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
7155 This->dst_fbo = 0;
7157 checkGLcall("Tear down FBOs\n");
7158 LEAVE_GL();
7160 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7161 This->fbo_color_attachments[i] = NULL;
7163 This->fbo_depth_attachment = NULL;
7166 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7167 UINT i, count;
7168 WINED3DDISPLAYMODE m;
7169 HRESULT hr;
7171 /* All Windowed modes are supported, as is leaving the current mode */
7172 if(pp->Windowed) return TRUE;
7173 if(!pp->BackBufferWidth) return TRUE;
7174 if(!pp->BackBufferHeight) return TRUE;
7176 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7177 for(i = 0; i < count; i++) {
7178 memset(&m, 0, sizeof(m));
7179 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7180 if(FAILED(hr)) {
7181 ERR("EnumAdapterModes failed\n");
7183 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7184 /* Mode found, it is supported */
7185 return TRUE;
7188 /* Mode not found -> not supported */
7189 return FALSE;
7192 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7194 IWineD3DSwapChainImpl *swapchain;
7195 HRESULT hr;
7196 BOOL DisplayModeChanged = FALSE;
7197 WINED3DDISPLAYMODE mode;
7198 IWineD3DBaseShaderImpl *shader;
7199 IWineD3DSurfaceImpl *target;
7200 UINT i;
7201 TRACE("(%p)\n", This);
7203 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7204 if(FAILED(hr)) {
7205 ERR("Failed to get the first implicit swapchain\n");
7206 return hr;
7209 if(!is_display_mode_supported(This, pPresentationParameters)) {
7210 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7211 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7212 pPresentationParameters->BackBufferHeight);
7213 return WINED3DERR_INVALIDCALL;
7216 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7217 * on an existing gl context, so there's no real need for recreation.
7219 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7221 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7223 TRACE("New params:\n");
7224 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7225 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7226 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7227 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7228 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7229 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7230 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7231 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7232 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7233 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7234 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7235 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7236 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7238 /* No special treatment of these parameters. Just store them */
7239 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7240 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7241 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7242 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7244 /* What to do about these? */
7245 if(pPresentationParameters->BackBufferCount != 0 &&
7246 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7247 ERR("Cannot change the back buffer count yet\n");
7249 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7250 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7251 ERR("Cannot change the back buffer format yet\n");
7253 if(pPresentationParameters->hDeviceWindow != NULL &&
7254 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7255 ERR("Cannot change the device window yet\n");
7257 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7258 ERR("What do do about a changed auto depth stencil parameter?\n");
7261 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7262 reset_fbo_state((IWineD3DDevice *) This);
7265 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7266 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7267 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7270 ENTER_GL();
7271 if(This->depth_blt_texture) {
7272 glDeleteTextures(1, &This->depth_blt_texture);
7273 This->depth_blt_texture = 0;
7275 if (This->depth_blt_rb) {
7276 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7277 This->depth_blt_rb = 0;
7278 This->depth_blt_rb_w = 0;
7279 This->depth_blt_rb_h = 0;
7281 This->frag_pipe->free_private(iface);
7282 This->shader_backend->shader_free_private(iface);
7284 for (i = 0; i < GL_LIMITS(textures); i++) {
7285 /* Textures are recreated below */
7286 glDeleteTextures(1, &This->dummyTextureName[i]);
7287 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7288 This->dummyTextureName[i] = 0;
7290 LEAVE_GL();
7292 while(This->numContexts) {
7293 DestroyContext(This, This->contexts[0]);
7295 This->activeContext = NULL;
7296 HeapFree(GetProcessHeap(), 0, swapchain->context);
7297 swapchain->context = NULL;
7298 swapchain->num_contexts = 0;
7300 if(pPresentationParameters->Windowed) {
7301 mode.Width = swapchain->orig_width;
7302 mode.Height = swapchain->orig_height;
7303 mode.RefreshRate = 0;
7304 mode.Format = swapchain->presentParms.BackBufferFormat;
7305 } else {
7306 mode.Width = pPresentationParameters->BackBufferWidth;
7307 mode.Height = pPresentationParameters->BackBufferHeight;
7308 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7309 mode.Format = swapchain->presentParms.BackBufferFormat;
7312 /* Should Width == 800 && Height == 0 set 800x600? */
7313 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7314 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7315 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7317 WINED3DVIEWPORT vp;
7318 int i;
7320 vp.X = 0;
7321 vp.Y = 0;
7322 vp.Width = pPresentationParameters->BackBufferWidth;
7323 vp.Height = pPresentationParameters->BackBufferHeight;
7324 vp.MinZ = 0;
7325 vp.MaxZ = 1;
7327 if(!pPresentationParameters->Windowed) {
7328 DisplayModeChanged = TRUE;
7330 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7331 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7333 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7334 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7335 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7337 if(This->auto_depth_stencil_buffer) {
7338 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7342 /* Now set the new viewport */
7343 IWineD3DDevice_SetViewport(iface, &vp);
7346 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7347 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7348 DisplayModeChanged) {
7350 IWineD3DDevice_SetFullscreen(iface, !pPresentationParameters->Windowed);
7351 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7352 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7353 } else if(!pPresentationParameters->Windowed) {
7354 DWORD style = This->style, exStyle = This->exStyle;
7355 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7356 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7357 * Reset to clear up their mess. Guild Wars also loses the device during that.
7359 This->style = 0;
7360 This->exStyle = 0;
7361 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7362 This->style = style;
7363 This->exStyle = exStyle;
7366 /* Recreate the primary swapchain's context */
7367 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7368 if(swapchain->backBuffer) {
7369 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7370 } else {
7371 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7373 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7374 &swapchain->presentParms);
7375 swapchain->num_contexts = 1;
7376 This->activeContext = swapchain->context[0];
7377 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7379 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7380 if(FAILED(hr)) {
7381 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7383 create_dummy_textures(This);
7386 hr = This->shader_backend->shader_alloc_private(iface);
7387 if(FAILED(hr)) {
7388 ERR("Failed to recreate shader private data\n");
7389 return hr;
7391 hr = This->frag_pipe->alloc_private(iface);
7392 if(FAILED(hr)) {
7393 TRACE("Fragment pipeline private data couldn't be allocated\n");
7394 return hr;
7397 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7398 * first use
7400 return WINED3D_OK;
7403 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7405 /** FIXME: always true at the moment **/
7406 if(!bEnableDialogs) {
7407 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7409 return WINED3D_OK;
7413 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7414 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7415 TRACE("(%p) : pParameters %p\n", This, pParameters);
7417 *pParameters = This->createParms;
7418 return WINED3D_OK;
7421 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7422 IWineD3DSwapChain *swapchain;
7424 TRACE("Relaying to swapchain\n");
7426 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7427 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7428 IWineD3DSwapChain_Release(swapchain);
7430 return;
7433 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7434 IWineD3DSwapChain *swapchain;
7436 TRACE("Relaying to swapchain\n");
7438 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7439 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7440 IWineD3DSwapChain_Release(swapchain);
7442 return;
7446 /** ********************************************************
7447 * Notification functions
7448 ** ********************************************************/
7449 /** This function must be called in the release of a resource when ref == 0,
7450 * the contents of resource must still be correct,
7451 * any handles to other resource held by the caller must be closed
7452 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7453 *****************************************************/
7454 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7457 TRACE("(%p) : Adding Resource %p\n", This, resource);
7458 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7461 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7464 TRACE("(%p) : Removing resource %p\n", This, resource);
7466 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7470 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7472 int counter;
7474 TRACE("(%p) : resource %p\n", This, resource);
7475 switch(IWineD3DResource_GetType(resource)){
7476 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7477 case WINED3DRTYPE_SURFACE: {
7478 unsigned int i;
7480 /* Cleanup any FBO attachments if d3d is enabled */
7481 if(This->d3d_initialized) {
7482 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7483 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7485 TRACE("Last active render target destroyed\n");
7486 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7487 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7488 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7489 * and the lastActiveRenderTarget member shouldn't matter
7491 if(swapchain) {
7492 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7493 TRACE("Activating primary back buffer\n");
7494 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7495 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7496 /* Single buffering environment */
7497 TRACE("Activating primary front buffer\n");
7498 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7499 } else {
7500 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7501 /* Implicit render target destroyed, that means the device is being destroyed
7502 * whatever we set here, it shouldn't matter
7504 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7506 } else {
7507 /* May happen during ddraw uninitialization */
7508 TRACE("Render target set, but swapchain does not exist!\n");
7509 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7513 ENTER_GL();
7514 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7515 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7516 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7517 set_render_target_fbo(iface, i, NULL);
7518 This->fbo_color_attachments[i] = NULL;
7521 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7522 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7523 set_depth_stencil_fbo(iface, NULL);
7524 This->fbo_depth_attachment = NULL;
7526 LEAVE_GL();
7529 break;
7531 case WINED3DRTYPE_TEXTURE:
7532 case WINED3DRTYPE_CUBETEXTURE:
7533 case WINED3DRTYPE_VOLUMETEXTURE:
7534 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7535 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7536 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7537 This->stateBlock->textures[counter] = NULL;
7539 if (This->updateStateBlock != This->stateBlock ){
7540 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7541 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7542 This->updateStateBlock->textures[counter] = NULL;
7546 break;
7547 case WINED3DRTYPE_VOLUME:
7548 /* TODO: nothing really? */
7549 break;
7550 case WINED3DRTYPE_VERTEXBUFFER:
7551 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7553 int streamNumber;
7554 TRACE("Cleaning up stream pointers\n");
7556 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7557 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7558 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7560 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7561 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7562 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7563 This->updateStateBlock->streamSource[streamNumber] = 0;
7564 /* Set changed flag? */
7567 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) */
7568 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7569 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7570 This->stateBlock->streamSource[streamNumber] = 0;
7573 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7574 else { /* This shouldn't happen */
7575 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7577 #endif
7581 break;
7582 case WINED3DRTYPE_INDEXBUFFER:
7583 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7584 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7585 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7586 This->updateStateBlock->pIndexData = NULL;
7589 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7590 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7591 This->stateBlock->pIndexData = NULL;
7595 break;
7596 default:
7597 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7598 break;
7602 /* Remove the resource from the resourceStore */
7603 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7605 TRACE("Resource released\n");
7609 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7611 IWineD3DResourceImpl *resource, *cursor;
7612 HRESULT ret;
7613 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7615 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7616 TRACE("enumerating resource %p\n", resource);
7617 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7618 ret = pCallback((IWineD3DResource *) resource, pData);
7619 if(ret == S_FALSE) {
7620 TRACE("Canceling enumeration\n");
7621 break;
7624 return WINED3D_OK;
7627 /**********************************************************
7628 * IWineD3DDevice VTbl follows
7629 **********************************************************/
7631 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7633 /*** IUnknown methods ***/
7634 IWineD3DDeviceImpl_QueryInterface,
7635 IWineD3DDeviceImpl_AddRef,
7636 IWineD3DDeviceImpl_Release,
7637 /*** IWineD3DDevice methods ***/
7638 IWineD3DDeviceImpl_GetParent,
7639 /*** Creation methods**/
7640 IWineD3DDeviceImpl_CreateVertexBuffer,
7641 IWineD3DDeviceImpl_CreateIndexBuffer,
7642 IWineD3DDeviceImpl_CreateStateBlock,
7643 IWineD3DDeviceImpl_CreateSurface,
7644 IWineD3DDeviceImpl_CreateTexture,
7645 IWineD3DDeviceImpl_CreateVolumeTexture,
7646 IWineD3DDeviceImpl_CreateVolume,
7647 IWineD3DDeviceImpl_CreateCubeTexture,
7648 IWineD3DDeviceImpl_CreateQuery,
7649 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7650 IWineD3DDeviceImpl_CreateVertexDeclaration,
7651 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7652 IWineD3DDeviceImpl_CreateVertexShader,
7653 IWineD3DDeviceImpl_CreatePixelShader,
7654 IWineD3DDeviceImpl_CreatePalette,
7655 /*** Odd functions **/
7656 IWineD3DDeviceImpl_Init3D,
7657 IWineD3DDeviceImpl_Uninit3D,
7658 IWineD3DDeviceImpl_SetFullscreen,
7659 IWineD3DDeviceImpl_SetMultithreaded,
7660 IWineD3DDeviceImpl_EvictManagedResources,
7661 IWineD3DDeviceImpl_GetAvailableTextureMem,
7662 IWineD3DDeviceImpl_GetBackBuffer,
7663 IWineD3DDeviceImpl_GetCreationParameters,
7664 IWineD3DDeviceImpl_GetDeviceCaps,
7665 IWineD3DDeviceImpl_GetDirect3D,
7666 IWineD3DDeviceImpl_GetDisplayMode,
7667 IWineD3DDeviceImpl_SetDisplayMode,
7668 IWineD3DDeviceImpl_GetHWND,
7669 IWineD3DDeviceImpl_SetHWND,
7670 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7671 IWineD3DDeviceImpl_GetRasterStatus,
7672 IWineD3DDeviceImpl_GetSwapChain,
7673 IWineD3DDeviceImpl_Reset,
7674 IWineD3DDeviceImpl_SetDialogBoxMode,
7675 IWineD3DDeviceImpl_SetCursorProperties,
7676 IWineD3DDeviceImpl_SetCursorPosition,
7677 IWineD3DDeviceImpl_ShowCursor,
7678 IWineD3DDeviceImpl_TestCooperativeLevel,
7679 /*** Getters and setters **/
7680 IWineD3DDeviceImpl_SetClipPlane,
7681 IWineD3DDeviceImpl_GetClipPlane,
7682 IWineD3DDeviceImpl_SetClipStatus,
7683 IWineD3DDeviceImpl_GetClipStatus,
7684 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7685 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7686 IWineD3DDeviceImpl_SetDepthStencilSurface,
7687 IWineD3DDeviceImpl_GetDepthStencilSurface,
7688 IWineD3DDeviceImpl_SetFVF,
7689 IWineD3DDeviceImpl_GetFVF,
7690 IWineD3DDeviceImpl_SetGammaRamp,
7691 IWineD3DDeviceImpl_GetGammaRamp,
7692 IWineD3DDeviceImpl_SetIndices,
7693 IWineD3DDeviceImpl_GetIndices,
7694 IWineD3DDeviceImpl_SetBaseVertexIndex,
7695 IWineD3DDeviceImpl_GetBaseVertexIndex,
7696 IWineD3DDeviceImpl_SetLight,
7697 IWineD3DDeviceImpl_GetLight,
7698 IWineD3DDeviceImpl_SetLightEnable,
7699 IWineD3DDeviceImpl_GetLightEnable,
7700 IWineD3DDeviceImpl_SetMaterial,
7701 IWineD3DDeviceImpl_GetMaterial,
7702 IWineD3DDeviceImpl_SetNPatchMode,
7703 IWineD3DDeviceImpl_GetNPatchMode,
7704 IWineD3DDeviceImpl_SetPaletteEntries,
7705 IWineD3DDeviceImpl_GetPaletteEntries,
7706 IWineD3DDeviceImpl_SetPixelShader,
7707 IWineD3DDeviceImpl_GetPixelShader,
7708 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7709 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7710 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7711 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7712 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7713 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7714 IWineD3DDeviceImpl_SetRenderState,
7715 IWineD3DDeviceImpl_GetRenderState,
7716 IWineD3DDeviceImpl_SetRenderTarget,
7717 IWineD3DDeviceImpl_GetRenderTarget,
7718 IWineD3DDeviceImpl_SetFrontBackBuffers,
7719 IWineD3DDeviceImpl_SetSamplerState,
7720 IWineD3DDeviceImpl_GetSamplerState,
7721 IWineD3DDeviceImpl_SetScissorRect,
7722 IWineD3DDeviceImpl_GetScissorRect,
7723 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7724 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7725 IWineD3DDeviceImpl_SetStreamSource,
7726 IWineD3DDeviceImpl_GetStreamSource,
7727 IWineD3DDeviceImpl_SetStreamSourceFreq,
7728 IWineD3DDeviceImpl_GetStreamSourceFreq,
7729 IWineD3DDeviceImpl_SetTexture,
7730 IWineD3DDeviceImpl_GetTexture,
7731 IWineD3DDeviceImpl_SetTextureStageState,
7732 IWineD3DDeviceImpl_GetTextureStageState,
7733 IWineD3DDeviceImpl_SetTransform,
7734 IWineD3DDeviceImpl_GetTransform,
7735 IWineD3DDeviceImpl_SetVertexDeclaration,
7736 IWineD3DDeviceImpl_GetVertexDeclaration,
7737 IWineD3DDeviceImpl_SetVertexShader,
7738 IWineD3DDeviceImpl_GetVertexShader,
7739 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7740 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7741 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7742 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7743 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7744 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7745 IWineD3DDeviceImpl_SetViewport,
7746 IWineD3DDeviceImpl_GetViewport,
7747 IWineD3DDeviceImpl_MultiplyTransform,
7748 IWineD3DDeviceImpl_ValidateDevice,
7749 IWineD3DDeviceImpl_ProcessVertices,
7750 /*** State block ***/
7751 IWineD3DDeviceImpl_BeginStateBlock,
7752 IWineD3DDeviceImpl_EndStateBlock,
7753 /*** Scene management ***/
7754 IWineD3DDeviceImpl_BeginScene,
7755 IWineD3DDeviceImpl_EndScene,
7756 IWineD3DDeviceImpl_Present,
7757 IWineD3DDeviceImpl_Clear,
7758 /*** Drawing ***/
7759 IWineD3DDeviceImpl_DrawPrimitive,
7760 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7761 IWineD3DDeviceImpl_DrawPrimitiveUP,
7762 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7763 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7764 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7765 IWineD3DDeviceImpl_DrawRectPatch,
7766 IWineD3DDeviceImpl_DrawTriPatch,
7767 IWineD3DDeviceImpl_DeletePatch,
7768 IWineD3DDeviceImpl_ColorFill,
7769 IWineD3DDeviceImpl_UpdateTexture,
7770 IWineD3DDeviceImpl_UpdateSurface,
7771 IWineD3DDeviceImpl_GetFrontBufferData,
7772 /*** object tracking ***/
7773 IWineD3DDeviceImpl_ResourceReleased,
7774 IWineD3DDeviceImpl_EnumResources
7777 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7779 /*** IUnknown methods ***/
7780 IWineD3DDeviceImpl_QueryInterface,
7781 IWineD3DDeviceImpl_AddRef,
7782 IWineD3DDeviceImpl_Release,
7783 /*** IWineD3DDevice methods ***/
7784 IWineD3DDeviceImpl_GetParent,
7785 /*** Creation methods**/
7786 IWineD3DDeviceImpl_CreateVertexBuffer,
7787 IWineD3DDeviceImpl_CreateIndexBuffer,
7788 IWineD3DDeviceImpl_CreateStateBlock,
7789 IWineD3DDeviceImpl_CreateSurface,
7790 IWineD3DDeviceImpl_CreateTexture,
7791 IWineD3DDeviceImpl_CreateVolumeTexture,
7792 IWineD3DDeviceImpl_CreateVolume,
7793 IWineD3DDeviceImpl_CreateCubeTexture,
7794 IWineD3DDeviceImpl_CreateQuery,
7795 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7796 IWineD3DDeviceImpl_CreateVertexDeclaration,
7797 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7798 IWineD3DDeviceImpl_CreateVertexShader,
7799 IWineD3DDeviceImpl_CreatePixelShader,
7800 IWineD3DDeviceImpl_CreatePalette,
7801 /*** Odd functions **/
7802 IWineD3DDeviceImpl_Init3D,
7803 IWineD3DDeviceImpl_Uninit3D,
7804 IWineD3DDeviceImpl_SetFullscreen,
7805 IWineD3DDeviceImpl_SetMultithreaded,
7806 IWineD3DDeviceImpl_EvictManagedResources,
7807 IWineD3DDeviceImpl_GetAvailableTextureMem,
7808 IWineD3DDeviceImpl_GetBackBuffer,
7809 IWineD3DDeviceImpl_GetCreationParameters,
7810 IWineD3DDeviceImpl_GetDeviceCaps,
7811 IWineD3DDeviceImpl_GetDirect3D,
7812 IWineD3DDeviceImpl_GetDisplayMode,
7813 IWineD3DDeviceImpl_SetDisplayMode,
7814 IWineD3DDeviceImpl_GetHWND,
7815 IWineD3DDeviceImpl_SetHWND,
7816 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7817 IWineD3DDeviceImpl_GetRasterStatus,
7818 IWineD3DDeviceImpl_GetSwapChain,
7819 IWineD3DDeviceImpl_Reset,
7820 IWineD3DDeviceImpl_SetDialogBoxMode,
7821 IWineD3DDeviceImpl_SetCursorProperties,
7822 IWineD3DDeviceImpl_SetCursorPosition,
7823 IWineD3DDeviceImpl_ShowCursor,
7824 IWineD3DDeviceImpl_TestCooperativeLevel,
7825 /*** Getters and setters **/
7826 IWineD3DDeviceImpl_SetClipPlane,
7827 IWineD3DDeviceImpl_GetClipPlane,
7828 IWineD3DDeviceImpl_SetClipStatus,
7829 IWineD3DDeviceImpl_GetClipStatus,
7830 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7831 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7832 IWineD3DDeviceImpl_SetDepthStencilSurface,
7833 IWineD3DDeviceImpl_GetDepthStencilSurface,
7834 IWineD3DDeviceImpl_SetFVF,
7835 IWineD3DDeviceImpl_GetFVF,
7836 IWineD3DDeviceImpl_SetGammaRamp,
7837 IWineD3DDeviceImpl_GetGammaRamp,
7838 IWineD3DDeviceImpl_SetIndices,
7839 IWineD3DDeviceImpl_GetIndices,
7840 IWineD3DDeviceImpl_SetBaseVertexIndex,
7841 IWineD3DDeviceImpl_GetBaseVertexIndex,
7842 IWineD3DDeviceImpl_SetLight,
7843 IWineD3DDeviceImpl_GetLight,
7844 IWineD3DDeviceImpl_SetLightEnable,
7845 IWineD3DDeviceImpl_GetLightEnable,
7846 IWineD3DDeviceImpl_SetMaterial,
7847 IWineD3DDeviceImpl_GetMaterial,
7848 IWineD3DDeviceImpl_SetNPatchMode,
7849 IWineD3DDeviceImpl_GetNPatchMode,
7850 IWineD3DDeviceImpl_SetPaletteEntries,
7851 IWineD3DDeviceImpl_GetPaletteEntries,
7852 IWineD3DDeviceImpl_SetPixelShader,
7853 IWineD3DDeviceImpl_GetPixelShader,
7854 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7855 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7856 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7857 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7858 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7859 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7860 IWineD3DDeviceImpl_SetRenderState,
7861 IWineD3DDeviceImpl_GetRenderState,
7862 IWineD3DDeviceImpl_SetRenderTarget,
7863 IWineD3DDeviceImpl_GetRenderTarget,
7864 IWineD3DDeviceImpl_SetFrontBackBuffers,
7865 IWineD3DDeviceImpl_SetSamplerState,
7866 IWineD3DDeviceImpl_GetSamplerState,
7867 IWineD3DDeviceImpl_SetScissorRect,
7868 IWineD3DDeviceImpl_GetScissorRect,
7869 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7870 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7871 IWineD3DDeviceImpl_SetStreamSource,
7872 IWineD3DDeviceImpl_GetStreamSource,
7873 IWineD3DDeviceImpl_SetStreamSourceFreq,
7874 IWineD3DDeviceImpl_GetStreamSourceFreq,
7875 IWineD3DDeviceImpl_SetTexture,
7876 IWineD3DDeviceImpl_GetTexture,
7877 IWineD3DDeviceImpl_SetTextureStageState,
7878 IWineD3DDeviceImpl_GetTextureStageState,
7879 IWineD3DDeviceImpl_SetTransform,
7880 IWineD3DDeviceImpl_GetTransform,
7881 IWineD3DDeviceImpl_SetVertexDeclaration,
7882 IWineD3DDeviceImpl_GetVertexDeclaration,
7883 IWineD3DDeviceImpl_SetVertexShader,
7884 IWineD3DDeviceImpl_GetVertexShader,
7885 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7886 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7887 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7888 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7889 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7890 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7891 IWineD3DDeviceImpl_SetViewport,
7892 IWineD3DDeviceImpl_GetViewport,
7893 IWineD3DDeviceImpl_MultiplyTransform,
7894 IWineD3DDeviceImpl_ValidateDevice,
7895 IWineD3DDeviceImpl_ProcessVertices,
7896 /*** State block ***/
7897 IWineD3DDeviceImpl_BeginStateBlock,
7898 IWineD3DDeviceImpl_EndStateBlock,
7899 /*** Scene management ***/
7900 IWineD3DDeviceImpl_BeginScene,
7901 IWineD3DDeviceImpl_EndScene,
7902 IWineD3DDeviceImpl_Present,
7903 IWineD3DDeviceImpl_Clear,
7904 /*** Drawing ***/
7905 IWineD3DDeviceImpl_DrawPrimitive,
7906 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7907 IWineD3DDeviceImpl_DrawPrimitiveUP,
7908 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7909 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7910 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7911 IWineD3DDeviceImpl_DrawRectPatch,
7912 IWineD3DDeviceImpl_DrawTriPatch,
7913 IWineD3DDeviceImpl_DeletePatch,
7914 IWineD3DDeviceImpl_ColorFill,
7915 IWineD3DDeviceImpl_UpdateTexture,
7916 IWineD3DDeviceImpl_UpdateSurface,
7917 IWineD3DDeviceImpl_GetFrontBufferData,
7918 /*** object tracking ***/
7919 IWineD3DDeviceImpl_ResourceReleased,
7920 IWineD3DDeviceImpl_EnumResources
7923 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7924 WINED3DRS_ALPHABLENDENABLE ,
7925 WINED3DRS_ALPHAFUNC ,
7926 WINED3DRS_ALPHAREF ,
7927 WINED3DRS_ALPHATESTENABLE ,
7928 WINED3DRS_BLENDOP ,
7929 WINED3DRS_COLORWRITEENABLE ,
7930 WINED3DRS_DESTBLEND ,
7931 WINED3DRS_DITHERENABLE ,
7932 WINED3DRS_FILLMODE ,
7933 WINED3DRS_FOGDENSITY ,
7934 WINED3DRS_FOGEND ,
7935 WINED3DRS_FOGSTART ,
7936 WINED3DRS_LASTPIXEL ,
7937 WINED3DRS_SHADEMODE ,
7938 WINED3DRS_SRCBLEND ,
7939 WINED3DRS_STENCILENABLE ,
7940 WINED3DRS_STENCILFAIL ,
7941 WINED3DRS_STENCILFUNC ,
7942 WINED3DRS_STENCILMASK ,
7943 WINED3DRS_STENCILPASS ,
7944 WINED3DRS_STENCILREF ,
7945 WINED3DRS_STENCILWRITEMASK ,
7946 WINED3DRS_STENCILZFAIL ,
7947 WINED3DRS_TEXTUREFACTOR ,
7948 WINED3DRS_WRAP0 ,
7949 WINED3DRS_WRAP1 ,
7950 WINED3DRS_WRAP2 ,
7951 WINED3DRS_WRAP3 ,
7952 WINED3DRS_WRAP4 ,
7953 WINED3DRS_WRAP5 ,
7954 WINED3DRS_WRAP6 ,
7955 WINED3DRS_WRAP7 ,
7956 WINED3DRS_ZENABLE ,
7957 WINED3DRS_ZFUNC ,
7958 WINED3DRS_ZWRITEENABLE
7961 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7962 WINED3DTSS_ADDRESSW ,
7963 WINED3DTSS_ALPHAARG0 ,
7964 WINED3DTSS_ALPHAARG1 ,
7965 WINED3DTSS_ALPHAARG2 ,
7966 WINED3DTSS_ALPHAOP ,
7967 WINED3DTSS_BUMPENVLOFFSET ,
7968 WINED3DTSS_BUMPENVLSCALE ,
7969 WINED3DTSS_BUMPENVMAT00 ,
7970 WINED3DTSS_BUMPENVMAT01 ,
7971 WINED3DTSS_BUMPENVMAT10 ,
7972 WINED3DTSS_BUMPENVMAT11 ,
7973 WINED3DTSS_COLORARG0 ,
7974 WINED3DTSS_COLORARG1 ,
7975 WINED3DTSS_COLORARG2 ,
7976 WINED3DTSS_COLOROP ,
7977 WINED3DTSS_RESULTARG ,
7978 WINED3DTSS_TEXCOORDINDEX ,
7979 WINED3DTSS_TEXTURETRANSFORMFLAGS
7982 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7983 WINED3DSAMP_ADDRESSU ,
7984 WINED3DSAMP_ADDRESSV ,
7985 WINED3DSAMP_ADDRESSW ,
7986 WINED3DSAMP_BORDERCOLOR ,
7987 WINED3DSAMP_MAGFILTER ,
7988 WINED3DSAMP_MINFILTER ,
7989 WINED3DSAMP_MIPFILTER ,
7990 WINED3DSAMP_MIPMAPLODBIAS ,
7991 WINED3DSAMP_MAXMIPLEVEL ,
7992 WINED3DSAMP_MAXANISOTROPY ,
7993 WINED3DSAMP_SRGBTEXTURE ,
7994 WINED3DSAMP_ELEMENTINDEX
7997 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7998 WINED3DRS_AMBIENT ,
7999 WINED3DRS_AMBIENTMATERIALSOURCE ,
8000 WINED3DRS_CLIPPING ,
8001 WINED3DRS_CLIPPLANEENABLE ,
8002 WINED3DRS_COLORVERTEX ,
8003 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8004 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8005 WINED3DRS_FOGDENSITY ,
8006 WINED3DRS_FOGEND ,
8007 WINED3DRS_FOGSTART ,
8008 WINED3DRS_FOGTABLEMODE ,
8009 WINED3DRS_FOGVERTEXMODE ,
8010 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8011 WINED3DRS_LIGHTING ,
8012 WINED3DRS_LOCALVIEWER ,
8013 WINED3DRS_MULTISAMPLEANTIALIAS ,
8014 WINED3DRS_MULTISAMPLEMASK ,
8015 WINED3DRS_NORMALIZENORMALS ,
8016 WINED3DRS_PATCHEDGESTYLE ,
8017 WINED3DRS_POINTSCALE_A ,
8018 WINED3DRS_POINTSCALE_B ,
8019 WINED3DRS_POINTSCALE_C ,
8020 WINED3DRS_POINTSCALEENABLE ,
8021 WINED3DRS_POINTSIZE ,
8022 WINED3DRS_POINTSIZE_MAX ,
8023 WINED3DRS_POINTSIZE_MIN ,
8024 WINED3DRS_POINTSPRITEENABLE ,
8025 WINED3DRS_RANGEFOGENABLE ,
8026 WINED3DRS_SPECULARMATERIALSOURCE ,
8027 WINED3DRS_TWEENFACTOR ,
8028 WINED3DRS_VERTEXBLEND ,
8029 WINED3DRS_CULLMODE ,
8030 WINED3DRS_FOGCOLOR
8033 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8034 WINED3DTSS_TEXCOORDINDEX ,
8035 WINED3DTSS_TEXTURETRANSFORMFLAGS
8038 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8039 WINED3DSAMP_DMAPOFFSET
8042 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8043 DWORD rep = This->StateTable[state].representative;
8044 DWORD idx;
8045 BYTE shift;
8046 UINT i;
8047 WineD3DContext *context;
8049 if(!rep) return;
8050 for(i = 0; i < This->numContexts; i++) {
8051 context = This->contexts[i];
8052 if(isStateDirty(context, rep)) continue;
8054 context->dirtyArray[context->numDirtyEntries++] = rep;
8055 idx = rep >> 5;
8056 shift = rep & 0x1f;
8057 context->isStateDirty[idx] |= (1 << shift);
8061 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8062 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8063 /* The drawable size of a pbuffer render target is the current pbuffer size
8065 *width = dev->pbufferWidth;
8066 *height = dev->pbufferHeight;
8069 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8070 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8072 *width = This->pow2Width;
8073 *height = This->pow2Height;
8076 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8077 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8078 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8079 * current context's drawable, which is the size of the back buffer of the swapchain
8080 * the active context belongs to. The back buffer of the swapchain is stored as the
8081 * surface the context belongs to.
8083 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8084 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;