wined3d: Enable lights on the correct swapchain.
[wine/multimedia.git] / dlls / wined3d / device.c
blob2e1361354c1dfc24a3b314168426945c334bd1ee
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
66 object->ref = 1; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
99 *pp##type = NULL; \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 WineD3DAdapterChangeGLRam(This, _size); \
104 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
108 *pp##type = NULL; \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
139 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
140 if (IsEqualGUID(riid, &IID_IUnknown)
141 || IsEqualGUID(riid, &IID_IWineD3DBase)
142 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
143 IUnknown_AddRef(iface);
144 *ppobj = This;
145 return S_OK;
147 *ppobj = NULL;
148 return E_NOINTERFACE;
151 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 ULONG refCount = InterlockedIncrement(&This->ref);
155 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
156 return refCount;
159 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 ULONG refCount = InterlockedDecrement(&This->ref);
163 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
165 if (!refCount) {
166 /* TODO: Clean up all the surfaces and textures! */
167 /* NOTE: You must release the parent if the object was created via a callback
168 ** ***************************/
170 if (!list_empty(&This->resources)) {
171 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
172 dumpResources(&This->resources);
175 if(This->contexts) ERR("Context array not freed!\n");
176 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
177 This->haveHardwareCursor = FALSE;
179 IWineD3D_Release(This->wineD3D);
180 This->wineD3D = NULL;
181 HeapFree(GetProcessHeap(), 0, This);
182 TRACE("Freed device %p\n", This);
183 This = NULL;
185 return refCount;
188 /**********************************************************
189 * IWineD3DDevice implementation follows
190 **********************************************************/
191 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
193 *pParent = This->parent;
194 IUnknown_AddRef(This->parent);
195 return WINED3D_OK;
198 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
199 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
200 IUnknown *parent) {
201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
202 IWineD3DVertexBufferImpl *object;
203 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
204 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
205 BOOL conv;
207 if(Size == 0) {
208 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
209 *ppVertexBuffer = NULL;
210 return WINED3DERR_INVALIDCALL;
211 } else if(Pool == WINED3DPOOL_SCRATCH) {
212 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
213 * anyway, SCRATCH vertex buffers aren't usable anywhere
215 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
216 *ppVertexBuffer = NULL;
217 return WINED3DERR_INVALIDCALL;
220 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
222 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
223 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
225 object->fvf = FVF;
227 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
228 * drawStridedFast (half-life 2).
230 * Basically converting the vertices in the buffer is quite expensive, and observations
231 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
232 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
234 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
235 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
236 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
237 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
238 * dx7 apps.
239 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
240 * more. In this call we can convert dx7 buffers too.
242 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
243 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
244 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
245 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
246 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
247 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
248 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
249 } else if(dxVersion <= 7 && conv) {
250 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
251 } else {
252 object->Flags |= VBFLAG_CREATEVBO;
254 return WINED3D_OK;
257 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
258 GLenum error, glUsage;
259 TRACE("Creating VBO for Index Buffer %p\n", object);
261 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
262 * restored on the next draw
264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
266 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
267 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
268 ENTER_GL();
270 while(glGetError());
272 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
273 error = glGetError();
274 if(error != GL_NO_ERROR || object->vbo == 0) {
275 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
276 goto out;
279 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
280 error = glGetError();
281 if(error != GL_NO_ERROR) {
282 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
283 goto out;
286 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
287 * copy no readback will be needed
289 glUsage = GL_STATIC_DRAW_ARB;
290 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
291 error = glGetError();
292 if(error != GL_NO_ERROR) {
293 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
294 goto out;
296 LEAVE_GL();
297 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
298 return;
300 out:
301 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
302 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
303 LEAVE_GL();
304 object->vbo = 0;
307 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
308 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
309 HANDLE *sharedHandle, IUnknown *parent) {
310 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
311 IWineD3DIndexBufferImpl *object;
312 TRACE("(%p) Creating index buffer\n", This);
314 /* Allocate the storage for the device */
315 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
317 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
318 CreateIndexBufferVBO(This, object);
321 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
322 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
323 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
325 return WINED3D_OK;
328 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
331 IWineD3DStateBlockImpl *object;
332 int i, j;
333 HRESULT temp_result;
335 D3DCREATEOBJECTINSTANCE(object, StateBlock)
336 object->blockType = Type;
338 for(i = 0; i < LIGHTMAP_SIZE; i++) {
339 list_init(&object->lightMap[i]);
342 /* Special case - Used during initialization to produce a placeholder stateblock
343 so other functions called can update a state block */
344 if (Type == WINED3DSBT_INIT) {
345 /* Don't bother increasing the reference count otherwise a device will never
346 be freed due to circular dependencies */
347 return WINED3D_OK;
350 temp_result = allocate_shader_constants(object);
351 if (WINED3D_OK != temp_result)
352 return temp_result;
354 /* Otherwise, might as well set the whole state block to the appropriate values */
355 if (This->stateBlock != NULL)
356 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
357 else
358 memset(object->streamFreq, 1, sizeof(object->streamFreq));
360 /* Reset the ref and type after kludging it */
361 object->wineD3DDevice = This;
362 object->ref = 1;
363 object->blockType = Type;
365 TRACE("Updating changed flags appropriate for type %d\n", Type);
367 if (Type == WINED3DSBT_ALL) {
369 TRACE("ALL => Pretend everything has changed\n");
370 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
372 /* Lights are not part of the changed / set structure */
373 for(j = 0; j < LIGHTMAP_SIZE; j++) {
374 struct list *e;
375 LIST_FOR_EACH(e, &object->lightMap[j]) {
376 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
377 light->changed = TRUE;
378 light->enabledChanged = TRUE;
381 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
382 object->contained_render_states[j - 1] = j;
384 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
385 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
386 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
387 object->contained_transform_states[j - 1] = j;
389 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
390 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
391 object->contained_vs_consts_f[j] = j;
393 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
394 for(j = 0; j < MAX_CONST_I; j++) {
395 object->contained_vs_consts_i[j] = j;
397 object->num_contained_vs_consts_i = MAX_CONST_I;
398 for(j = 0; j < MAX_CONST_B; j++) {
399 object->contained_vs_consts_b[j] = j;
401 object->num_contained_vs_consts_b = MAX_CONST_B;
402 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
403 object->contained_ps_consts_f[j] = j;
405 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
406 for(j = 0; j < MAX_CONST_I; j++) {
407 object->contained_ps_consts_i[j] = j;
409 object->num_contained_ps_consts_i = MAX_CONST_I;
410 for(j = 0; j < MAX_CONST_B; j++) {
411 object->contained_ps_consts_b[j] = j;
413 object->num_contained_ps_consts_b = MAX_CONST_B;
414 for(i = 0; i < MAX_TEXTURES; i++) {
415 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
416 object->contained_tss_states[object->num_contained_tss_states].stage = i;
417 object->contained_tss_states[object->num_contained_tss_states].state = j;
418 object->num_contained_tss_states++;
421 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
422 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
423 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
424 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
425 object->num_contained_sampler_states++;
429 for(i = 0; i < MAX_STREAMS; i++) {
430 if(object->streamSource[i]) {
431 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
434 if(object->pIndexData) {
435 IWineD3DIndexBuffer_AddRef(object->pIndexData);
437 if(object->vertexShader) {
438 IWineD3DVertexShader_AddRef(object->vertexShader);
440 if(object->pixelShader) {
441 IWineD3DPixelShader_AddRef(object->pixelShader);
444 } else if (Type == WINED3DSBT_PIXELSTATE) {
446 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
447 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
449 object->changed.pixelShader = TRUE;
451 /* Pixel Shader Constants */
452 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
453 object->contained_ps_consts_f[i] = i;
454 object->changed.pixelShaderConstantsF[i] = TRUE;
456 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
457 for (i = 0; i < MAX_CONST_B; ++i) {
458 object->contained_ps_consts_b[i] = i;
459 object->changed.pixelShaderConstantsB[i] = TRUE;
461 object->num_contained_ps_consts_b = MAX_CONST_B;
462 for (i = 0; i < MAX_CONST_I; ++i) {
463 object->contained_ps_consts_i[i] = i;
464 object->changed.pixelShaderConstantsI[i] = TRUE;
466 object->num_contained_ps_consts_i = MAX_CONST_I;
468 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
469 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
470 object->contained_render_states[i] = SavedPixelStates_R[i];
472 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
473 for (j = 0; j < MAX_TEXTURES; j++) {
474 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
475 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
476 object->contained_tss_states[object->num_contained_tss_states].stage = j;
477 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
478 object->num_contained_tss_states++;
481 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
482 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
483 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
484 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
485 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
486 object->num_contained_sampler_states++;
489 if(object->pixelShader) {
490 IWineD3DPixelShader_AddRef(object->pixelShader);
493 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
494 * on them. This makes releasing the buffer easier
496 for(i = 0; i < MAX_STREAMS; i++) {
497 object->streamSource[i] = NULL;
499 object->pIndexData = NULL;
500 object->vertexShader = NULL;
502 } else if (Type == WINED3DSBT_VERTEXSTATE) {
504 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
505 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
507 object->changed.vertexShader = TRUE;
509 /* Vertex Shader Constants */
510 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
511 object->changed.vertexShaderConstantsF[i] = TRUE;
512 object->contained_vs_consts_f[i] = i;
514 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
515 for (i = 0; i < MAX_CONST_B; ++i) {
516 object->changed.vertexShaderConstantsB[i] = TRUE;
517 object->contained_vs_consts_b[i] = i;
519 object->num_contained_vs_consts_b = MAX_CONST_B;
520 for (i = 0; i < MAX_CONST_I; ++i) {
521 object->changed.vertexShaderConstantsI[i] = TRUE;
522 object->contained_vs_consts_i[i] = i;
524 object->num_contained_vs_consts_i = MAX_CONST_I;
525 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
526 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
527 object->contained_render_states[i] = SavedVertexStates_R[i];
529 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
530 for (j = 0; j < MAX_TEXTURES; j++) {
531 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
532 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
533 object->contained_tss_states[object->num_contained_tss_states].stage = j;
534 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
535 object->num_contained_tss_states++;
538 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
539 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
540 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
541 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
542 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
543 object->num_contained_sampler_states++;
547 for(j = 0; j < LIGHTMAP_SIZE; j++) {
548 struct list *e;
549 LIST_FOR_EACH(e, &object->lightMap[j]) {
550 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
551 light->changed = TRUE;
552 light->enabledChanged = TRUE;
556 for(i = 0; i < MAX_STREAMS; i++) {
557 if(object->streamSource[i]) {
558 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
561 if(object->vertexShader) {
562 IWineD3DVertexShader_AddRef(object->vertexShader);
564 object->pIndexData = NULL;
565 object->pixelShader = NULL;
566 } else {
567 FIXME("Unrecognized state block type %d\n", Type);
570 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
571 return WINED3D_OK;
574 /* ************************************
575 MSDN:
576 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
578 Discard
579 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
581 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
583 ******************************** */
585 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
587 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
588 unsigned int Size = 1;
589 const GlPixelFormatDesc *glDesc;
590 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
591 UINT mul_4w, mul_4h;
592 TRACE("(%p) Create surface\n",This);
594 /** FIXME: Check ranges on the inputs are valid
595 * MSDN
596 * MultisampleQuality
597 * [in] Quality level. The valid range is between zero and one less than the level
598 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
599 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
600 * values of paired render targets, depth stencil surfaces, and the MultiSample type
601 * must all match.
602 *******************************/
606 * TODO: Discard MSDN
607 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
609 * If this flag is set, the contents of the depth stencil buffer will be
610 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
611 * with a different depth surface.
613 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
614 ***************************/
616 if(MultisampleQuality > 0) {
617 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
618 MultisampleQuality=0;
621 /** FIXME: Check that the format is supported
622 * by the device.
623 *******************************/
625 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
626 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
627 * space!
628 *********************************/
629 mul_4w = (Width + 3) & ~3;
630 mul_4h = (Height + 3) & ~3;
631 if (WINED3DFMT_UNKNOWN == Format) {
632 Size = 0;
633 } else if (Format == WINED3DFMT_DXT1) {
634 /* DXT1 is half byte per pixel */
635 Size = (mul_4w * tableEntry->bpp * mul_4h) >> 1;
637 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
638 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
639 Format == WINED3DFMT_ATI2N) {
640 Size = (mul_4w * tableEntry->bpp * mul_4h);
641 } else {
642 /* The pitch is a multiple of 4 bytes */
643 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
644 Size *= Height;
647 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
649 /** Create and initialise the surface resource **/
650 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
651 /* "Standalone" surface */
652 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
654 object->currentDesc.Width = Width;
655 object->currentDesc.Height = Height;
656 object->currentDesc.MultiSampleType = MultiSample;
657 object->currentDesc.MultiSampleQuality = MultisampleQuality;
658 object->glDescription.level = Level;
659 object->heightscale = glDesc->heightscale != 0.0 ? glDesc->heightscale : 1.0;
660 list_init(&object->overlays);
662 /* Flags */
663 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
664 object->Flags |= Discard ? SFLAG_DISCARD : 0;
665 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
666 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
669 if (WINED3DFMT_UNKNOWN != Format) {
670 object->bytesPerPixel = tableEntry->bpp;
671 } else {
672 object->bytesPerPixel = 0;
675 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
677 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
679 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
680 * this function is too deep to need to care about things like this.
681 * Levels need to be checked too, and possibly Type since they all affect what can be done.
682 * ****************************************/
683 switch(Pool) {
684 case WINED3DPOOL_SCRATCH:
685 if(!Lockable)
686 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
687 "which are mutually exclusive, setting lockable to TRUE\n");
688 Lockable = TRUE;
689 break;
690 case WINED3DPOOL_SYSTEMMEM:
691 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
692 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
693 case WINED3DPOOL_MANAGED:
694 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
695 "Usage of DYNAMIC which are mutually exclusive, not doing "
696 "anything just telling you.\n");
697 break;
698 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
699 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
700 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
701 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
702 break;
703 default:
704 FIXME("(%p) Unknown pool %d\n", This, Pool);
705 break;
708 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
709 FIXME("Trying to create a render target that isn't in the default pool\n");
712 /* mark the texture as dirty so that it gets loaded first time around*/
713 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
714 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
715 This, Width, Height, Format, debug_d3dformat(Format),
716 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
718 /* Look at the implementation and set the correct Vtable */
719 switch(Impl) {
720 case SURFACE_OPENGL:
721 /* Check if a 3D adapter is available when creating gl surfaces */
722 if(!This->adapter) {
723 ERR("OpenGL surfaces are not available without opengl\n");
724 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
725 HeapFree(GetProcessHeap(), 0, object);
726 return WINED3DERR_NOTAVAILABLE;
728 break;
730 case SURFACE_GDI:
731 object->lpVtbl = &IWineGDISurface_Vtbl;
732 break;
734 default:
735 /* To be sure to catch this */
736 ERR("Unknown requested surface implementation %d!\n", Impl);
737 IWineD3DSurface_Release((IWineD3DSurface *) object);
738 return WINED3DERR_INVALIDCALL;
741 list_init(&object->renderbuffers);
743 /* Call the private setup routine */
744 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
748 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
749 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
750 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
751 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
754 IWineD3DTextureImpl *object;
755 unsigned int i;
756 UINT tmpW;
757 UINT tmpH;
758 HRESULT hr;
759 unsigned int pow2Width;
760 unsigned int pow2Height;
761 const GlPixelFormatDesc *glDesc;
762 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
764 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
765 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
766 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
768 /* TODO: It should only be possible to create textures for formats
769 that are reported as supported */
770 if (WINED3DFMT_UNKNOWN >= Format) {
771 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
772 return WINED3DERR_INVALIDCALL;
775 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
776 D3DINITIALIZEBASETEXTURE(object->baseTexture);
777 object->width = Width;
778 object->height = Height;
780 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
781 object->baseTexture.minMipLookup = &minMipLookup;
782 object->baseTexture.magLookup = &magLookup;
783 } else {
784 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
785 object->baseTexture.magLookup = &magLookup_noFilter;
788 /** Non-power2 support **/
789 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
790 pow2Width = Width;
791 pow2Height = Height;
792 } else {
793 /* Find the nearest pow2 match */
794 pow2Width = pow2Height = 1;
795 while (pow2Width < Width) pow2Width <<= 1;
796 while (pow2Height < Height) pow2Height <<= 1;
798 if(pow2Width != Width || pow2Height != Height) {
799 if(Levels > 1) {
800 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
801 HeapFree(GetProcessHeap(), 0, object);
802 *ppTexture = NULL;
803 return WINED3DERR_INVALIDCALL;
804 } else {
805 Levels = 1;
810 /** FIXME: add support for real non-power-two if it's provided by the video card **/
811 /* Precalculated scaling for 'faked' non power of two texture coords.
812 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
813 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
814 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
816 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
817 object->baseTexture.pow2Matrix[0] = 1.0;
818 object->baseTexture.pow2Matrix[5] = 1.0;
819 object->baseTexture.pow2Matrix[10] = 1.0;
820 object->baseTexture.pow2Matrix[15] = 1.0;
821 object->target = GL_TEXTURE_2D;
822 object->cond_np2 = TRUE;
823 pow2Width = Width;
824 pow2Height = Height;
825 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
826 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
827 (Width != pow2Width || Height != pow2Height) &&
828 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
830 object->baseTexture.pow2Matrix[0] = (float)Width;
831 object->baseTexture.pow2Matrix[5] = (float)Height;
832 object->baseTexture.pow2Matrix[10] = 1.0;
833 object->baseTexture.pow2Matrix[15] = 1.0;
834 object->target = GL_TEXTURE_RECTANGLE_ARB;
835 object->cond_np2 = TRUE;
836 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
837 } else {
838 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
839 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
840 object->baseTexture.pow2Matrix[10] = 1.0;
841 object->baseTexture.pow2Matrix[15] = 1.0;
842 object->target = GL_TEXTURE_2D;
843 object->cond_np2 = FALSE;
845 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
847 /* Calculate levels for mip mapping */
848 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
849 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
850 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
851 return WINED3DERR_INVALIDCALL;
853 if(Levels > 1) {
854 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
855 return WINED3DERR_INVALIDCALL;
857 object->baseTexture.levels = 1;
858 } else if (Levels == 0) {
859 TRACE("calculating levels %d\n", object->baseTexture.levels);
860 object->baseTexture.levels++;
861 tmpW = Width;
862 tmpH = Height;
863 while (tmpW > 1 || tmpH > 1) {
864 tmpW = max(1, tmpW >> 1);
865 tmpH = max(1, tmpH >> 1);
866 object->baseTexture.levels++;
868 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
871 /* Generate all the surfaces */
872 tmpW = Width;
873 tmpH = Height;
874 for (i = 0; i < object->baseTexture.levels; i++)
876 /* use the callback to create the texture surface */
877 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
878 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
879 FIXME("Failed to create surface %p\n", object);
880 /* clean up */
881 object->surfaces[i] = NULL;
882 IWineD3DTexture_Release((IWineD3DTexture *)object);
884 *ppTexture = NULL;
885 return hr;
888 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
889 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
890 surface_set_texture_target(object->surfaces[i], object->target);
891 /* calculate the next mipmap level */
892 tmpW = max(1, tmpW >> 1);
893 tmpH = max(1, tmpH >> 1);
895 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
897 TRACE("(%p) : Created texture %p\n", This, object);
898 return WINED3D_OK;
901 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
902 UINT Width, UINT Height, UINT Depth,
903 UINT Levels, DWORD Usage,
904 WINED3DFORMAT Format, WINED3DPOOL Pool,
905 IWineD3DVolumeTexture **ppVolumeTexture,
906 HANDLE *pSharedHandle, IUnknown *parent,
907 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
910 IWineD3DVolumeTextureImpl *object;
911 unsigned int i;
912 UINT tmpW;
913 UINT tmpH;
914 UINT tmpD;
915 const GlPixelFormatDesc *glDesc;
917 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
919 /* TODO: It should only be possible to create textures for formats
920 that are reported as supported */
921 if (WINED3DFMT_UNKNOWN >= Format) {
922 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
923 return WINED3DERR_INVALIDCALL;
925 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
926 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
927 return WINED3DERR_INVALIDCALL;
930 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
931 D3DINITIALIZEBASETEXTURE(object->baseTexture);
933 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
934 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
936 object->width = Width;
937 object->height = Height;
938 object->depth = Depth;
940 /* Is NP2 support for volumes needed? */
941 object->baseTexture.pow2Matrix[ 0] = 1.0;
942 object->baseTexture.pow2Matrix[ 5] = 1.0;
943 object->baseTexture.pow2Matrix[10] = 1.0;
944 object->baseTexture.pow2Matrix[15] = 1.0;
946 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
947 object->baseTexture.minMipLookup = &minMipLookup;
948 object->baseTexture.magLookup = &magLookup;
949 } else {
950 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
951 object->baseTexture.magLookup = &magLookup_noFilter;
954 /* Calculate levels for mip mapping */
955 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
956 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
957 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
958 return WINED3DERR_INVALIDCALL;
960 if(Levels > 1) {
961 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
962 return WINED3DERR_INVALIDCALL;
964 Levels = 1;
965 } else if (Levels == 0) {
966 object->baseTexture.levels++;
967 tmpW = Width;
968 tmpH = Height;
969 tmpD = Depth;
970 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
971 tmpW = max(1, tmpW >> 1);
972 tmpH = max(1, tmpH >> 1);
973 tmpD = max(1, tmpD >> 1);
974 object->baseTexture.levels++;
976 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
979 /* Generate all the surfaces */
980 tmpW = Width;
981 tmpH = Height;
982 tmpD = Depth;
984 for (i = 0; i < object->baseTexture.levels; i++)
986 HRESULT hr;
987 /* Create the volume */
988 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
989 &object->volumes[i], pSharedHandle);
991 if(FAILED(hr)) {
992 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
993 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
994 *ppVolumeTexture = NULL;
995 return hr;
998 /* Set its container to this object */
999 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1001 /* calculate the next mipmap level */
1002 tmpW = max(1, tmpW >> 1);
1003 tmpH = max(1, tmpH >> 1);
1004 tmpD = max(1, tmpD >> 1);
1006 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1008 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1009 TRACE("(%p) : Created volume texture %p\n", This, object);
1010 return WINED3D_OK;
1013 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1014 UINT Width, UINT Height, UINT Depth,
1015 DWORD Usage,
1016 WINED3DFORMAT Format, WINED3DPOOL Pool,
1017 IWineD3DVolume** ppVolume,
1018 HANDLE* pSharedHandle, IUnknown *parent) {
1020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1021 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1022 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1024 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1025 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1026 return WINED3DERR_INVALIDCALL;
1029 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1031 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1032 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1034 object->currentDesc.Width = Width;
1035 object->currentDesc.Height = Height;
1036 object->currentDesc.Depth = Depth;
1037 object->bytesPerPixel = formatDesc->bpp;
1039 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1040 object->lockable = TRUE;
1041 object->locked = FALSE;
1042 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1043 object->dirty = TRUE;
1045 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1048 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1049 UINT Levels, DWORD Usage,
1050 WINED3DFORMAT Format, WINED3DPOOL Pool,
1051 IWineD3DCubeTexture **ppCubeTexture,
1052 HANDLE *pSharedHandle, IUnknown *parent,
1053 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1056 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1057 unsigned int i, j;
1058 UINT tmpW;
1059 HRESULT hr;
1060 unsigned int pow2EdgeLength = EdgeLength;
1061 const GlPixelFormatDesc *glDesc;
1062 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1064 /* TODO: It should only be possible to create textures for formats
1065 that are reported as supported */
1066 if (WINED3DFMT_UNKNOWN >= Format) {
1067 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1068 return WINED3DERR_INVALIDCALL;
1071 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1072 WARN("(%p) : Tried to create not supported cube texture\n", This);
1073 return WINED3DERR_INVALIDCALL;
1076 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1077 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1079 TRACE("(%p) Create Cube Texture\n", This);
1081 /** Non-power2 support **/
1083 /* Find the nearest pow2 match */
1084 pow2EdgeLength = 1;
1085 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1087 object->edgeLength = EdgeLength;
1088 /* TODO: support for native non-power 2 */
1089 /* Precalculated scaling for 'faked' non power of two texture coords */
1090 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1091 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1092 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1093 object->baseTexture.pow2Matrix[15] = 1.0;
1095 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1096 object->baseTexture.minMipLookup = &minMipLookup;
1097 object->baseTexture.magLookup = &magLookup;
1098 } else {
1099 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
1100 object->baseTexture.magLookup = &magLookup_noFilter;
1103 /* Calculate levels for mip mapping */
1104 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1105 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1106 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1107 HeapFree(GetProcessHeap(), 0, object);
1108 *ppCubeTexture = NULL;
1110 return WINED3DERR_INVALIDCALL;
1112 if(Levels > 1) {
1113 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1114 HeapFree(GetProcessHeap(), 0, object);
1115 *ppCubeTexture = NULL;
1117 return WINED3DERR_INVALIDCALL;
1119 Levels = 1;
1120 } else if (Levels == 0) {
1121 object->baseTexture.levels++;
1122 tmpW = EdgeLength;
1123 while (tmpW > 1) {
1124 tmpW = max(1, tmpW >> 1);
1125 object->baseTexture.levels++;
1127 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1130 /* Generate all the surfaces */
1131 tmpW = EdgeLength;
1132 for (i = 0; i < object->baseTexture.levels; i++) {
1134 /* Create the 6 faces */
1135 for (j = 0; j < 6; j++) {
1136 static const GLenum cube_targets[6] = {
1137 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1138 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1139 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1140 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1141 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1142 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1145 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1146 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1148 if(hr!= WINED3D_OK) {
1149 /* clean up */
1150 int k;
1151 int l;
1152 for (l = 0; l < j; l++) {
1153 IWineD3DSurface_Release(object->surfaces[l][i]);
1155 for (k = 0; k < i; k++) {
1156 for (l = 0; l < 6; l++) {
1157 IWineD3DSurface_Release(object->surfaces[l][k]);
1161 FIXME("(%p) Failed to create surface\n",object);
1162 HeapFree(GetProcessHeap(),0,object);
1163 *ppCubeTexture = NULL;
1164 return hr;
1166 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1167 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1168 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1170 tmpW = max(1, tmpW >> 1);
1172 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1174 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1175 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1176 return WINED3D_OK;
1179 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1181 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1182 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1183 const IWineD3DQueryVtbl *vtable;
1185 /* Just a check to see if we support this type of query */
1186 switch(Type) {
1187 case WINED3DQUERYTYPE_OCCLUSION:
1188 TRACE("(%p) occlusion query\n", This);
1189 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1190 hr = WINED3D_OK;
1191 else
1192 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1194 vtable = &IWineD3DOcclusionQuery_Vtbl;
1195 break;
1197 case WINED3DQUERYTYPE_EVENT:
1198 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1199 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1200 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1202 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1204 vtable = &IWineD3DEventQuery_Vtbl;
1205 hr = WINED3D_OK;
1206 break;
1208 case WINED3DQUERYTYPE_VCACHE:
1209 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1210 case WINED3DQUERYTYPE_VERTEXSTATS:
1211 case WINED3DQUERYTYPE_TIMESTAMP:
1212 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1213 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1214 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1215 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1216 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1217 case WINED3DQUERYTYPE_PIXELTIMINGS:
1218 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1219 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1220 default:
1221 /* Use the base Query vtable until we have a special one for each query */
1222 vtable = &IWineD3DQuery_Vtbl;
1223 FIXME("(%p) Unhandled query type %d\n", This, Type);
1225 if(NULL == ppQuery || hr != WINED3D_OK) {
1226 return hr;
1229 D3DCREATEOBJECTINSTANCE(object, Query)
1230 object->lpVtbl = vtable;
1231 object->type = Type;
1232 object->state = QUERY_CREATED;
1233 /* allocated the 'extended' data based on the type of query requested */
1234 switch(Type){
1235 case WINED3DQUERYTYPE_OCCLUSION:
1236 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1237 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1239 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1240 TRACE("(%p) Allocating data for an occlusion query\n", This);
1241 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1242 break;
1244 case WINED3DQUERYTYPE_EVENT:
1245 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1246 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1248 if(GL_SUPPORT(APPLE_FENCE)) {
1249 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1250 checkGLcall("glGenFencesAPPLE");
1251 } else if(GL_SUPPORT(NV_FENCE)) {
1252 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1253 checkGLcall("glGenFencesNV");
1255 break;
1257 case WINED3DQUERYTYPE_VCACHE:
1258 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1259 case WINED3DQUERYTYPE_VERTEXSTATS:
1260 case WINED3DQUERYTYPE_TIMESTAMP:
1261 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1262 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1263 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1264 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1265 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1266 case WINED3DQUERYTYPE_PIXELTIMINGS:
1267 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1268 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1269 default:
1270 object->extendedData = 0;
1271 FIXME("(%p) Unhandled query type %d\n",This , Type);
1273 TRACE("(%p) : Created Query %p\n", This, object);
1274 return WINED3D_OK;
1277 /*****************************************************************************
1278 * IWineD3DDeviceImpl_SetupFullscreenWindow
1280 * Helper function that modifies a HWND's Style and ExStyle for proper
1281 * fullscreen use.
1283 * Params:
1284 * iface: Pointer to the IWineD3DDevice interface
1285 * window: Window to setup
1287 *****************************************************************************/
1288 static LONG fullscreen_style(LONG orig_style) {
1289 LONG style = orig_style;
1290 style &= ~WS_CAPTION;
1291 style &= ~WS_THICKFRAME;
1293 /* Make sure the window is managed, otherwise we won't get keyboard input */
1294 style |= WS_POPUP | WS_SYSMENU;
1296 return style;
1299 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1300 LONG exStyle = orig_exStyle;
1302 /* Filter out window decorations */
1303 exStyle &= ~WS_EX_WINDOWEDGE;
1304 exStyle &= ~WS_EX_CLIENTEDGE;
1306 return exStyle;
1309 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1310 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1312 LONG style, exStyle;
1313 /* Don't do anything if an original style is stored.
1314 * That shouldn't happen
1316 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1317 if (This->style || This->exStyle) {
1318 ERR("(%p): Want to change the window parameters of HWND %p, but "
1319 "another style is stored for restoration afterwards\n", This, window);
1322 /* Get the parameters and save them */
1323 style = GetWindowLongW(window, GWL_STYLE);
1324 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1325 This->style = style;
1326 This->exStyle = exStyle;
1328 style = fullscreen_style(style);
1329 exStyle = fullscreen_exStyle(exStyle);
1331 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1332 This->style, This->exStyle, style, exStyle);
1334 SetWindowLongW(window, GWL_STYLE, style);
1335 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1337 /* Inform the window about the update. */
1338 SetWindowPos(window, HWND_TOP, 0, 0,
1339 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1342 /*****************************************************************************
1343 * IWineD3DDeviceImpl_RestoreWindow
1345 * Helper function that restores a windows' properties when taking it out
1346 * of fullscreen mode
1348 * Params:
1349 * iface: Pointer to the IWineD3DDevice interface
1350 * window: Window to setup
1352 *****************************************************************************/
1353 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1355 LONG style, exStyle;
1357 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1358 * switch, do nothing
1360 if (!This->style && !This->exStyle) return;
1362 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1363 This, window, This->style, This->exStyle);
1365 style = GetWindowLongW(window, GWL_STYLE);
1366 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1368 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1369 * Some applications change it before calling Reset() when switching between windowed and
1370 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1372 if(style == fullscreen_style(This->style) &&
1373 exStyle == fullscreen_style(This->exStyle)) {
1374 SetWindowLongW(window, GWL_STYLE, This->style);
1375 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1378 /* Delete the old values */
1379 This->style = 0;
1380 This->exStyle = 0;
1382 /* Inform the window about the update */
1383 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1384 0, 0, 0, 0, /* Pos, Size, ignored */
1385 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1388 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1389 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1390 IUnknown* parent,
1391 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1392 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil,
1393 WINED3DSURFTYPE surface_type) {
1394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1396 HDC hDc;
1397 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1398 HRESULT hr = WINED3D_OK;
1399 IUnknown *bufferParent;
1400 BOOL displaymode_set = FALSE;
1401 WINED3DDISPLAYMODE Mode;
1402 const StaticPixelFormatDesc *formatDesc;
1404 TRACE("(%p) : Created Additional Swap Chain\n", This);
1406 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1407 * does a device hold a reference to a swap chain giving them a lifetime of the device
1408 * or does the swap chain notify the device of its destruction.
1409 *******************************/
1411 /* Check the params */
1412 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1413 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1414 return WINED3DERR_INVALIDCALL;
1415 } else if (pPresentationParameters->BackBufferCount > 1) {
1416 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");
1419 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1420 switch(surface_type) {
1421 case SURFACE_GDI:
1422 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1423 break;
1424 case SURFACE_OPENGL:
1425 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1426 break;
1427 case SURFACE_UNKNOWN:
1428 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1429 return WINED3DERR_INVALIDCALL;
1432 /*********************
1433 * Lookup the window Handle and the relating X window handle
1434 ********************/
1436 /* Setup hwnd we are using, plus which display this equates to */
1437 object->win_handle = pPresentationParameters->hDeviceWindow;
1438 if (!object->win_handle) {
1439 object->win_handle = This->createParms.hFocusWindow;
1441 if(!pPresentationParameters->Windowed && object->win_handle) {
1442 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1443 pPresentationParameters->BackBufferWidth,
1444 pPresentationParameters->BackBufferHeight);
1447 hDc = GetDC(object->win_handle);
1448 TRACE("Using hDc %p\n", hDc);
1450 if (NULL == hDc) {
1451 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1452 return WINED3DERR_NOTAVAILABLE;
1455 /* Get info on the current display setup */
1456 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1457 object->orig_width = Mode.Width;
1458 object->orig_height = Mode.Height;
1459 object->orig_fmt = Mode.Format;
1460 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1462 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1463 * then the corresponding dimension of the client area of the hDeviceWindow
1464 * (or the focus window, if hDeviceWindow is NULL) is taken.
1465 **********************/
1467 if (pPresentationParameters->Windowed &&
1468 ((pPresentationParameters->BackBufferWidth == 0) ||
1469 (pPresentationParameters->BackBufferHeight == 0) ||
1470 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1472 RECT Rect;
1473 GetClientRect(object->win_handle, &Rect);
1475 if (pPresentationParameters->BackBufferWidth == 0) {
1476 pPresentationParameters->BackBufferWidth = Rect.right;
1477 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1479 if (pPresentationParameters->BackBufferHeight == 0) {
1480 pPresentationParameters->BackBufferHeight = Rect.bottom;
1481 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1483 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1484 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1485 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1489 /* Put the correct figures in the presentation parameters */
1490 TRACE("Copying across presentation parameters\n");
1491 object->presentParms = *pPresentationParameters;
1493 TRACE("calling rendertarget CB\n");
1494 hr = D3DCB_CreateRenderTarget(This->parent,
1495 parent,
1496 object->presentParms.BackBufferWidth,
1497 object->presentParms.BackBufferHeight,
1498 object->presentParms.BackBufferFormat,
1499 object->presentParms.MultiSampleType,
1500 object->presentParms.MultiSampleQuality,
1501 TRUE /* Lockable */,
1502 &object->frontBuffer,
1503 NULL /* pShared (always null)*/);
1504 if (object->frontBuffer != NULL) {
1505 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1506 if(surface_type == SURFACE_OPENGL) {
1507 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1509 } else {
1510 ERR("Failed to create the front buffer\n");
1511 goto error;
1514 /*********************
1515 * Windowed / Fullscreen
1516 *******************/
1519 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1520 * so we should really check to see if there is a fullscreen swapchain already
1521 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1522 **************************************/
1524 if (!pPresentationParameters->Windowed) {
1525 WINED3DDISPLAYMODE mode;
1528 /* Change the display settings */
1529 mode.Width = pPresentationParameters->BackBufferWidth;
1530 mode.Height = pPresentationParameters->BackBufferHeight;
1531 mode.Format = pPresentationParameters->BackBufferFormat;
1532 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1534 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1535 displaymode_set = TRUE;
1539 * Create an opengl context for the display visual
1540 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1541 * use different properties after that point in time. FIXME: How to handle when requested format
1542 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1543 * it chooses is identical to the one already being used!
1544 **********************************/
1545 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1547 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1548 if(!object->context)
1549 return E_OUTOFMEMORY;
1550 object->num_contexts = 1;
1552 if(surface_type == SURFACE_OPENGL) {
1553 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1554 if (!object->context[0]) {
1555 ERR("Failed to create a new context\n");
1556 hr = WINED3DERR_NOTAVAILABLE;
1557 goto error;
1558 } else {
1559 TRACE("Context created (HWND=%p, glContext=%p)\n",
1560 object->win_handle, object->context[0]->glCtx);
1564 /*********************
1565 * Create the back, front and stencil buffers
1566 *******************/
1567 if(object->presentParms.BackBufferCount > 0) {
1568 int i;
1570 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1571 if(!object->backBuffer) {
1572 ERR("Out of memory\n");
1573 hr = E_OUTOFMEMORY;
1574 goto error;
1577 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1578 TRACE("calling rendertarget CB\n");
1579 hr = D3DCB_CreateRenderTarget(This->parent,
1580 parent,
1581 object->presentParms.BackBufferWidth,
1582 object->presentParms.BackBufferHeight,
1583 object->presentParms.BackBufferFormat,
1584 object->presentParms.MultiSampleType,
1585 object->presentParms.MultiSampleQuality,
1586 TRUE /* Lockable */,
1587 &object->backBuffer[i],
1588 NULL /* pShared (always null)*/);
1589 if(hr == WINED3D_OK && object->backBuffer[i]) {
1590 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1591 } else {
1592 ERR("Cannot create new back buffer\n");
1593 goto error;
1595 if(surface_type == SURFACE_OPENGL) {
1596 ENTER_GL();
1597 glDrawBuffer(GL_BACK);
1598 checkGLcall("glDrawBuffer(GL_BACK)");
1599 LEAVE_GL();
1602 } else {
1603 object->backBuffer = NULL;
1605 /* Single buffering - draw to front buffer */
1606 if(surface_type == SURFACE_OPENGL) {
1607 ENTER_GL();
1608 glDrawBuffer(GL_FRONT);
1609 checkGLcall("glDrawBuffer(GL_FRONT)");
1610 LEAVE_GL();
1614 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1615 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK && surface_type == SURFACE_OPENGL) {
1616 TRACE("Creating depth stencil buffer\n");
1617 if (This->auto_depth_stencil_buffer == NULL ) {
1618 hr = D3DCB_CreateDepthStencil(This->parent,
1619 parent,
1620 object->presentParms.BackBufferWidth,
1621 object->presentParms.BackBufferHeight,
1622 object->presentParms.AutoDepthStencilFormat,
1623 object->presentParms.MultiSampleType,
1624 object->presentParms.MultiSampleQuality,
1625 FALSE /* FIXME: Discard */,
1626 &This->auto_depth_stencil_buffer,
1627 NULL /* pShared (always null)*/ );
1628 if (This->auto_depth_stencil_buffer != NULL)
1629 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1633 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1635 TRACE("Created swapchain %p\n", object);
1636 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1637 return WINED3D_OK;
1639 error:
1640 if (displaymode_set) {
1641 DEVMODEW devmode;
1642 RECT clip_rc;
1644 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1645 ClipCursor(NULL);
1647 /* Change the display settings */
1648 memset(&devmode, 0, sizeof(devmode));
1649 devmode.dmSize = sizeof(devmode);
1650 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1651 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1652 devmode.dmPelsWidth = object->orig_width;
1653 devmode.dmPelsHeight = object->orig_height;
1654 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1657 if (object->backBuffer) {
1658 int i;
1659 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1660 if(object->backBuffer[i]) {
1661 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1662 IUnknown_Release(bufferParent); /* once for the get parent */
1663 if (IUnknown_Release(bufferParent) > 0) {
1664 FIXME("(%p) Something's still holding the back buffer\n",This);
1668 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1669 object->backBuffer = NULL;
1671 if(object->context[0])
1672 DestroyContext(This, object->context[0]);
1673 if(object->frontBuffer) {
1674 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1675 IUnknown_Release(bufferParent); /* once for the get parent */
1676 if (IUnknown_Release(bufferParent) > 0) {
1677 FIXME("(%p) Something's still holding the front buffer\n",This);
1680 HeapFree(GetProcessHeap(), 0, object);
1681 return hr;
1684 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1685 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1687 TRACE("(%p)\n", This);
1689 return This->NumberOfSwapChains;
1692 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1694 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1696 if(iSwapChain < This->NumberOfSwapChains) {
1697 *pSwapChain = This->swapchains[iSwapChain];
1698 IWineD3DSwapChain_AddRef(*pSwapChain);
1699 TRACE("(%p) returning %p\n", This, *pSwapChain);
1700 return WINED3D_OK;
1701 } else {
1702 TRACE("Swapchain out of range\n");
1703 *pSwapChain = NULL;
1704 return WINED3DERR_INVALIDCALL;
1708 /*****
1709 * Vertex Declaration
1710 *****/
1711 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1712 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1714 IWineD3DVertexDeclarationImpl *object = NULL;
1715 HRESULT hr = WINED3D_OK;
1717 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1718 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1720 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1722 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1723 if(FAILED(hr)) {
1724 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1725 *ppVertexDeclaration = NULL;
1728 return hr;
1731 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1732 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1734 unsigned int idx, idx2;
1735 unsigned int offset;
1736 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1737 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1738 BOOL has_blend_idx = has_blend &&
1739 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1740 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1741 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1742 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1743 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1744 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1745 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1747 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1748 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1750 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1751 WINED3DVERTEXELEMENT *elements = NULL;
1753 unsigned int size;
1754 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1755 if (has_blend_idx) num_blends--;
1757 /* Compute declaration size */
1758 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1759 has_psize + has_diffuse + has_specular + num_textures + 1;
1761 /* convert the declaration */
1762 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1763 if (!elements)
1764 return 0;
1766 elements[size-1] = end_element;
1767 idx = 0;
1768 if (has_pos) {
1769 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1770 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1771 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1773 else {
1774 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1775 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1777 elements[idx].UsageIndex = 0;
1778 idx++;
1780 if (has_blend && (num_blends > 0)) {
1781 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1782 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1783 else
1784 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1785 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1786 elements[idx].UsageIndex = 0;
1787 idx++;
1789 if (has_blend_idx) {
1790 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1791 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1792 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1793 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1794 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1795 else
1796 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1797 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1798 elements[idx].UsageIndex = 0;
1799 idx++;
1801 if (has_normal) {
1802 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1803 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1804 elements[idx].UsageIndex = 0;
1805 idx++;
1807 if (has_psize) {
1808 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1809 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1810 elements[idx].UsageIndex = 0;
1811 idx++;
1813 if (has_diffuse) {
1814 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1815 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1816 elements[idx].UsageIndex = 0;
1817 idx++;
1819 if (has_specular) {
1820 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1821 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1822 elements[idx].UsageIndex = 1;
1823 idx++;
1825 for (idx2 = 0; idx2 < num_textures; idx2++) {
1826 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1827 switch (numcoords) {
1828 case WINED3DFVF_TEXTUREFORMAT1:
1829 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1830 break;
1831 case WINED3DFVF_TEXTUREFORMAT2:
1832 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1833 break;
1834 case WINED3DFVF_TEXTUREFORMAT3:
1835 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1836 break;
1837 case WINED3DFVF_TEXTUREFORMAT4:
1838 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1839 break;
1841 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1842 elements[idx].UsageIndex = idx2;
1843 idx++;
1846 /* Now compute offsets, and initialize the rest of the fields */
1847 for (idx = 0, offset = 0; idx < size-1; idx++) {
1848 elements[idx].Stream = 0;
1849 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1850 elements[idx].Offset = offset;
1851 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1854 *ppVertexElements = elements;
1855 return size;
1858 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1859 WINED3DVERTEXELEMENT* elements = NULL;
1860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1861 unsigned int size;
1862 DWORD hr;
1864 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1865 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1867 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1868 HeapFree(GetProcessHeap(), 0, elements);
1869 if (hr != S_OK) return hr;
1871 return WINED3D_OK;
1874 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1876 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1877 HRESULT hr = WINED3D_OK;
1878 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1879 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1881 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1883 if (vertex_declaration) {
1884 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1887 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1889 if (WINED3D_OK != hr) {
1890 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1891 IWineD3DVertexShader_Release(*ppVertexShader);
1892 return WINED3DERR_INVALIDCALL;
1894 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1896 return WINED3D_OK;
1899 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1901 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1902 HRESULT hr = WINED3D_OK;
1904 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1905 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1906 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1907 if (WINED3D_OK == hr) {
1908 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1909 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1910 } else {
1911 WARN("(%p) : Failed to create pixel shader\n", This);
1914 return hr;
1917 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1919 IWineD3DPaletteImpl *object;
1920 HRESULT hr;
1921 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1923 /* Create the new object */
1924 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1925 if(!object) {
1926 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1927 return E_OUTOFMEMORY;
1930 object->lpVtbl = &IWineD3DPalette_Vtbl;
1931 object->ref = 1;
1932 object->Flags = Flags;
1933 object->parent = Parent;
1934 object->wineD3DDevice = This;
1935 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1937 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1939 if(!object->hpal) {
1940 HeapFree( GetProcessHeap(), 0, object);
1941 return E_OUTOFMEMORY;
1944 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1945 if(FAILED(hr)) {
1946 IWineD3DPalette_Release((IWineD3DPalette *) object);
1947 return hr;
1950 *Palette = (IWineD3DPalette *) object;
1952 return WINED3D_OK;
1955 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1956 HBITMAP hbm;
1957 BITMAP bm;
1958 HRESULT hr;
1959 HDC dcb = NULL, dcs = NULL;
1960 WINEDDCOLORKEY colorkey;
1962 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1963 if(hbm)
1965 GetObjectA(hbm, sizeof(BITMAP), &bm);
1966 dcb = CreateCompatibleDC(NULL);
1967 if(!dcb) goto out;
1968 SelectObject(dcb, hbm);
1970 else
1972 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1973 * couldn't be loaded
1975 memset(&bm, 0, sizeof(bm));
1976 bm.bmWidth = 32;
1977 bm.bmHeight = 32;
1980 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1981 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1982 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1983 if(FAILED(hr)) {
1984 ERR("Wine logo requested, but failed to create surface\n");
1985 goto out;
1988 if(dcb) {
1989 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1990 if(FAILED(hr)) goto out;
1991 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1992 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1994 colorkey.dwColorSpaceLowValue = 0;
1995 colorkey.dwColorSpaceHighValue = 0;
1996 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1997 } else {
1998 /* Fill the surface with a white color to show that wined3d is there */
1999 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2002 out:
2003 if(dcb) {
2004 DeleteDC(dcb);
2006 if(hbm) {
2007 DeleteObject(hbm);
2009 return;
2012 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2013 unsigned int i;
2014 /* Under DirectX you can have texture stage operations even if no texture is
2015 bound, whereas opengl will only do texture operations when a valid texture is
2016 bound. We emulate this by creating dummy textures and binding them to each
2017 texture stage, but disable all stages by default. Hence if a stage is enabled
2018 then the default texture will kick in until replaced by a SetTexture call */
2019 ENTER_GL();
2021 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2022 /* The dummy texture does not have client storage backing */
2023 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2024 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2026 for (i = 0; i < GL_LIMITS(textures); i++) {
2027 GLubyte white = 255;
2029 /* Make appropriate texture active */
2030 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2031 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2032 checkGLcall("glActiveTextureARB");
2033 } else if (i > 0) {
2034 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2037 /* Generate an opengl texture name */
2038 glGenTextures(1, &This->dummyTextureName[i]);
2039 checkGLcall("glGenTextures");
2040 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2042 /* Generate a dummy 2d texture (not using 1d because they cause many
2043 * DRI drivers fall back to sw) */
2044 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2045 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2046 checkGLcall("glBindTexture");
2048 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2049 checkGLcall("glTexImage2D");
2051 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2052 /* Reenable because if supported it is enabled by default */
2053 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2054 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2057 LEAVE_GL();
2060 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2062 IWineD3DSwapChainImpl *swapchain = NULL;
2063 HRESULT hr;
2064 DWORD state;
2065 unsigned int i;
2067 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2068 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2069 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2071 /* TODO: Test if OpenGL is compiled in and loaded */
2073 TRACE("(%p) : Creating stateblock\n", This);
2074 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2075 hr = IWineD3DDevice_CreateStateBlock(iface,
2076 WINED3DSBT_INIT,
2077 (IWineD3DStateBlock **)&This->stateBlock,
2078 NULL);
2079 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2080 WARN("Failed to create stateblock\n");
2081 goto err_out;
2083 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2084 This->updateStateBlock = This->stateBlock;
2085 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2087 hr = allocate_shader_constants(This->updateStateBlock);
2088 if (WINED3D_OK != hr) {
2089 goto err_out;
2092 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2093 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2095 This->NumberOfPalettes = 1;
2096 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2097 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2098 ERR("Out of memory!\n");
2099 goto err_out;
2101 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2102 if(!This->palettes[0]) {
2103 ERR("Out of memory!\n");
2104 goto err_out;
2106 for (i = 0; i < 256; ++i) {
2107 This->palettes[0][i].peRed = 0xFF;
2108 This->palettes[0][i].peGreen = 0xFF;
2109 This->palettes[0][i].peBlue = 0xFF;
2110 This->palettes[0][i].peFlags = 0xFF;
2112 This->currentPalette = 0;
2114 /* Initialize the texture unit mapping to a 1:1 mapping */
2115 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2116 if (state < GL_LIMITS(fragment_samplers)) {
2117 This->texUnitMap[state] = state;
2118 This->rev_tex_unit_map[state] = state;
2119 } else {
2120 This->texUnitMap[state] = -1;
2121 This->rev_tex_unit_map[state] = -1;
2125 /* Setup the implicit swapchain */
2126 TRACE("Creating implicit swapchain\n");
2127 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2128 if (FAILED(hr) || !swapchain) {
2129 WARN("Failed to create implicit swapchain\n");
2130 goto err_out;
2133 This->NumberOfSwapChains = 1;
2134 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2135 if(!This->swapchains) {
2136 ERR("Out of memory!\n");
2137 goto err_out;
2139 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2141 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2142 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2143 This->render_targets[0] = swapchain->backBuffer[0];
2144 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2146 else {
2147 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2148 This->render_targets[0] = swapchain->frontBuffer;
2149 This->lastActiveRenderTarget = swapchain->frontBuffer;
2151 IWineD3DSurface_AddRef(This->render_targets[0]);
2152 This->activeContext = swapchain->context[0];
2153 This->lastThread = GetCurrentThreadId();
2155 /* Depth Stencil support */
2156 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2157 if (NULL != This->stencilBufferTarget) {
2158 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2161 hr = This->shader_backend->shader_alloc_private(iface);
2162 if(FAILED(hr)) {
2163 TRACE("Shader private data couldn't be allocated\n");
2164 goto err_out;
2166 hr = This->frag_pipe->alloc_private(iface);
2167 if(FAILED(hr)) {
2168 TRACE("Fragment pipeline private data couldn't be allocated\n");
2169 goto err_out;
2171 hr = This->blitter->alloc_private(iface);
2172 if(FAILED(hr)) {
2173 TRACE("Blitter private data couldn't be allocated\n");
2174 goto err_out;
2177 /* Set up some starting GL setup */
2179 /* Setup all the devices defaults */
2180 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2181 create_dummy_textures(This);
2183 ENTER_GL();
2185 { /* Set a default viewport */
2186 WINED3DVIEWPORT vp;
2187 vp.X = 0;
2188 vp.Y = 0;
2189 vp.Width = pPresentationParameters->BackBufferWidth;
2190 vp.Height = pPresentationParameters->BackBufferHeight;
2191 vp.MinZ = 0.0f;
2192 vp.MaxZ = 1.0f;
2193 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2196 /* Initialize the current view state */
2197 This->view_ident = 1;
2198 This->contexts[0]->last_was_rhw = 0;
2199 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2200 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2202 switch(wined3d_settings.offscreen_rendering_mode) {
2203 case ORM_FBO:
2204 case ORM_PBUFFER:
2205 This->offscreenBuffer = GL_BACK;
2206 break;
2208 case ORM_BACKBUFFER:
2210 if(This->activeContext->aux_buffers > 0) {
2211 TRACE("Using auxilliary buffer for offscreen rendering\n");
2212 This->offscreenBuffer = GL_AUX0;
2213 } else {
2214 TRACE("Using back buffer for offscreen rendering\n");
2215 This->offscreenBuffer = GL_BACK;
2220 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2221 LEAVE_GL();
2223 /* Clear the screen */
2224 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2225 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2226 0x00, 1.0, 0);
2228 This->d3d_initialized = TRUE;
2230 if(wined3d_settings.logo) {
2231 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2233 This->highest_dirty_ps_const = 0;
2234 This->highest_dirty_vs_const = 0;
2235 return WINED3D_OK;
2237 err_out:
2238 HeapFree(GetProcessHeap(), 0, This->render_targets);
2239 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2240 HeapFree(GetProcessHeap(), 0, This->swapchains);
2241 This->NumberOfSwapChains = 0;
2242 if(This->palettes) {
2243 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2244 HeapFree(GetProcessHeap(), 0, This->palettes);
2246 This->NumberOfPalettes = 0;
2247 if(swapchain) {
2248 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2250 if(This->stateBlock) {
2251 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2252 This->stateBlock = NULL;
2254 if (This->blit_priv) {
2255 This->blitter->free_private(iface);
2257 if (This->fragment_priv) {
2258 This->frag_pipe->free_private(iface);
2260 if (This->shader_priv) {
2261 This->shader_backend->shader_free_private(iface);
2263 return hr;
2266 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2268 IWineD3DSwapChainImpl *swapchain = NULL;
2269 HRESULT hr;
2271 /* Setup the implicit swapchain */
2272 TRACE("Creating implicit swapchain\n");
2273 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2274 if (FAILED(hr) || !swapchain) {
2275 WARN("Failed to create implicit swapchain\n");
2276 goto err_out;
2279 This->NumberOfSwapChains = 1;
2280 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2281 if(!This->swapchains) {
2282 ERR("Out of memory!\n");
2283 goto err_out;
2285 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2286 return WINED3D_OK;
2288 err_out:
2289 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2290 return hr;
2293 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2295 int sampler;
2296 UINT i;
2297 TRACE("(%p)\n", This);
2299 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2301 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2302 * it was created. Thus make sure a context is active for the glDelete* calls
2304 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2306 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2308 TRACE("Deleting high order patches\n");
2309 for(i = 0; i < PATCHMAP_SIZE; i++) {
2310 struct list *e1, *e2;
2311 struct WineD3DRectPatch *patch;
2312 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2313 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2314 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2318 /* Delete the palette conversion shader if it is around */
2319 if(This->paletteConversionShader) {
2320 ENTER_GL();
2321 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2322 LEAVE_GL();
2323 This->paletteConversionShader = 0;
2326 /* Delete the pbuffer context if there is any */
2327 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2329 /* Delete the mouse cursor texture */
2330 if(This->cursorTexture) {
2331 ENTER_GL();
2332 glDeleteTextures(1, &This->cursorTexture);
2333 LEAVE_GL();
2334 This->cursorTexture = 0;
2337 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2338 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2340 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2341 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2344 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2345 * private data, it might contain opengl pointers
2347 if(This->depth_blt_texture) {
2348 glDeleteTextures(1, &This->depth_blt_texture);
2349 This->depth_blt_texture = 0;
2351 if (This->depth_blt_rb) {
2352 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2353 This->depth_blt_rb = 0;
2354 This->depth_blt_rb_w = 0;
2355 This->depth_blt_rb_h = 0;
2358 /* Release the update stateblock */
2359 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2360 if(This->updateStateBlock != This->stateBlock)
2361 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2363 This->updateStateBlock = NULL;
2365 { /* because were not doing proper internal refcounts releasing the primary state block
2366 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2367 to set this->stateBlock = NULL; first */
2368 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2369 This->stateBlock = NULL;
2371 /* Release the stateblock */
2372 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2373 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2377 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2378 This->blitter->free_private(iface);
2379 This->frag_pipe->free_private(iface);
2380 This->shader_backend->shader_free_private(iface);
2382 /* Release the buffers (with sanity checks)*/
2383 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2384 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2385 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2386 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2388 This->stencilBufferTarget = NULL;
2390 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2391 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2392 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2394 TRACE("Setting rendertarget to NULL\n");
2395 This->render_targets[0] = NULL;
2397 if (This->auto_depth_stencil_buffer) {
2398 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2399 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2401 This->auto_depth_stencil_buffer = NULL;
2404 for(i=0; i < This->NumberOfSwapChains; i++) {
2405 TRACE("Releasing the implicit swapchain %d\n", i);
2406 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2407 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2411 HeapFree(GetProcessHeap(), 0, This->swapchains);
2412 This->swapchains = NULL;
2413 This->NumberOfSwapChains = 0;
2415 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2416 HeapFree(GetProcessHeap(), 0, This->palettes);
2417 This->palettes = NULL;
2418 This->NumberOfPalettes = 0;
2420 HeapFree(GetProcessHeap(), 0, This->render_targets);
2421 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2422 This->render_targets = NULL;
2423 This->draw_buffers = NULL;
2425 This->d3d_initialized = FALSE;
2426 return WINED3D_OK;
2429 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2431 unsigned int i;
2433 for(i=0; i < This->NumberOfSwapChains; i++) {
2434 TRACE("Releasing the implicit swapchain %d\n", i);
2435 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2436 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2440 HeapFree(GetProcessHeap(), 0, This->swapchains);
2441 This->swapchains = NULL;
2442 This->NumberOfSwapChains = 0;
2443 return WINED3D_OK;
2446 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2447 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2448 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2450 * There is no way to deactivate thread safety once it is enabled.
2452 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2455 /*For now just store the flag(needed in case of ddraw) */
2456 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2458 return;
2461 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2462 DEVMODEW devmode;
2463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2464 LONG ret;
2465 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2466 RECT clip_rc;
2468 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2470 /* Resize the screen even without a window:
2471 * The app could have unset it with SetCooperativeLevel, but not called
2472 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2473 * but we don't have any hwnd
2476 memset(&devmode, 0, sizeof(devmode));
2477 devmode.dmSize = sizeof(devmode);
2478 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2479 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2480 devmode.dmPelsWidth = pMode->Width;
2481 devmode.dmPelsHeight = pMode->Height;
2483 devmode.dmDisplayFrequency = pMode->RefreshRate;
2484 if (pMode->RefreshRate != 0) {
2485 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2488 /* Only change the mode if necessary */
2489 if( (This->ddraw_width == pMode->Width) &&
2490 (This->ddraw_height == pMode->Height) &&
2491 (This->ddraw_format == pMode->Format) &&
2492 (pMode->RefreshRate == 0) ) {
2493 return WINED3D_OK;
2496 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2497 if (ret != DISP_CHANGE_SUCCESSFUL) {
2498 if(devmode.dmDisplayFrequency != 0) {
2499 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2500 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2501 devmode.dmDisplayFrequency = 0;
2502 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2504 if(ret != DISP_CHANGE_SUCCESSFUL) {
2505 return WINED3DERR_NOTAVAILABLE;
2509 /* Store the new values */
2510 This->ddraw_width = pMode->Width;
2511 This->ddraw_height = pMode->Height;
2512 This->ddraw_format = pMode->Format;
2514 /* And finally clip mouse to our screen */
2515 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2516 ClipCursor(&clip_rc);
2518 return WINED3D_OK;
2521 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2523 *ppD3D= This->wineD3D;
2524 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2525 IWineD3D_AddRef(*ppD3D);
2526 return WINED3D_OK;
2529 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2532 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2533 (This->adapter->TextureRam/(1024*1024)),
2534 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2535 /* return simulated texture memory left */
2536 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2541 /*****
2542 * Get / Set FVF
2543 *****/
2544 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2547 /* Update the current state block */
2548 This->updateStateBlock->changed.fvf = TRUE;
2550 if(This->updateStateBlock->fvf == fvf) {
2551 TRACE("Application is setting the old fvf over, nothing to do\n");
2552 return WINED3D_OK;
2555 This->updateStateBlock->fvf = fvf;
2556 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2557 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2558 return WINED3D_OK;
2562 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2564 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2565 *pfvf = This->stateBlock->fvf;
2566 return WINED3D_OK;
2569 /*****
2570 * Get / Set Stream Source
2571 *****/
2572 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2574 IWineD3DVertexBuffer *oldSrc;
2576 if (StreamNumber >= MAX_STREAMS) {
2577 WARN("Stream out of range %d\n", StreamNumber);
2578 return WINED3DERR_INVALIDCALL;
2579 } else if(OffsetInBytes & 0x3) {
2580 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2581 return WINED3DERR_INVALIDCALL;
2584 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2585 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2587 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2589 if(oldSrc == pStreamData &&
2590 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2591 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2592 TRACE("Application is setting the old values over, nothing to do\n");
2593 return WINED3D_OK;
2596 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2597 if (pStreamData) {
2598 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2599 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2602 /* Handle recording of state blocks */
2603 if (This->isRecordingState) {
2604 TRACE("Recording... not performing anything\n");
2605 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2606 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2607 return WINED3D_OK;
2610 /* Need to do a getParent and pass the references up */
2611 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2612 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2613 so for now, just count internally */
2614 if (pStreamData != NULL) {
2615 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2616 InterlockedIncrement(&vbImpl->bindCount);
2617 IWineD3DVertexBuffer_AddRef(pStreamData);
2619 if (oldSrc != NULL) {
2620 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2621 IWineD3DVertexBuffer_Release(oldSrc);
2624 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2626 return WINED3D_OK;
2629 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2632 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2633 This->stateBlock->streamSource[StreamNumber],
2634 This->stateBlock->streamOffset[StreamNumber],
2635 This->stateBlock->streamStride[StreamNumber]);
2637 if (StreamNumber >= MAX_STREAMS) {
2638 WARN("Stream out of range %d\n", StreamNumber);
2639 return WINED3DERR_INVALIDCALL;
2641 *pStream = This->stateBlock->streamSource[StreamNumber];
2642 *pStride = This->stateBlock->streamStride[StreamNumber];
2643 if (pOffset) {
2644 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2647 if (*pStream != NULL) {
2648 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2650 return WINED3D_OK;
2653 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2655 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2656 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2658 /* Verify input at least in d3d9 this is invalid*/
2659 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2660 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2661 return WINED3DERR_INVALIDCALL;
2663 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2664 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2665 return WINED3DERR_INVALIDCALL;
2667 if( Divider == 0 ){
2668 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2669 return WINED3DERR_INVALIDCALL;
2672 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2673 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2675 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2676 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2678 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2679 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2680 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2683 return WINED3D_OK;
2686 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2689 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2690 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2692 TRACE("(%p) : returning %d\n", This, *Divider);
2694 return WINED3D_OK;
2697 /*****
2698 * Get / Set & Multiply Transform
2699 *****/
2700 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2703 /* Most of this routine, comments included copied from ddraw tree initially: */
2704 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2706 /* Handle recording of state blocks */
2707 if (This->isRecordingState) {
2708 TRACE("Recording... not performing anything\n");
2709 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2710 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2711 return WINED3D_OK;
2715 * If the new matrix is the same as the current one,
2716 * we cut off any further processing. this seems to be a reasonable
2717 * optimization because as was noticed, some apps (warcraft3 for example)
2718 * tend towards setting the same matrix repeatedly for some reason.
2720 * From here on we assume that the new matrix is different, wherever it matters.
2722 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2723 TRACE("The app is setting the same matrix over again\n");
2724 return WINED3D_OK;
2725 } else {
2726 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2730 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2731 where ViewMat = Camera space, WorldMat = world space.
2733 In OpenGL, camera and world space is combined into GL_MODELVIEW
2734 matrix. The Projection matrix stay projection matrix.
2737 /* Capture the times we can just ignore the change for now */
2738 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2739 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2740 /* Handled by the state manager */
2743 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2744 return WINED3D_OK;
2747 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2748 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2749 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2750 *pMatrix = This->stateBlock->transforms[State];
2751 return WINED3D_OK;
2754 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2755 WINED3DMATRIX *mat = NULL;
2756 WINED3DMATRIX temp;
2758 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2759 * below means it will be recorded in a state block change, but it
2760 * works regardless where it is recorded.
2761 * If this is found to be wrong, change to StateBlock.
2763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2764 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2766 if (State < HIGHEST_TRANSFORMSTATE)
2768 mat = &This->updateStateBlock->transforms[State];
2769 } else {
2770 FIXME("Unhandled transform state!!\n");
2773 multiply_matrix(&temp, mat, pMatrix);
2775 /* Apply change via set transform - will reapply to eg. lights this way */
2776 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2779 /*****
2780 * Get / Set Light
2781 *****/
2782 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2783 you can reference any indexes you want as long as that number max are enabled at any
2784 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2785 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2786 but when recording, just build a chain pretty much of commands to be replayed. */
2788 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2789 float rho;
2790 PLIGHTINFOEL *object = NULL;
2791 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2792 struct list *e;
2794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2795 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2797 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2798 * the gl driver.
2800 if(!pLight) {
2801 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2802 return WINED3DERR_INVALIDCALL;
2805 switch(pLight->Type) {
2806 case WINED3DLIGHT_POINT:
2807 case WINED3DLIGHT_SPOT:
2808 case WINED3DLIGHT_PARALLELPOINT:
2809 case WINED3DLIGHT_GLSPOT:
2810 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2811 * most wanted
2813 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2814 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2815 return WINED3DERR_INVALIDCALL;
2817 break;
2819 case WINED3DLIGHT_DIRECTIONAL:
2820 /* Ignores attenuation */
2821 break;
2823 default:
2824 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2825 return WINED3DERR_INVALIDCALL;
2828 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2829 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2830 if(object->OriginalIndex == Index) break;
2831 object = NULL;
2834 if(!object) {
2835 TRACE("Adding new light\n");
2836 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2837 if(!object) {
2838 ERR("Out of memory error when allocating a light\n");
2839 return E_OUTOFMEMORY;
2841 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2842 object->glIndex = -1;
2843 object->OriginalIndex = Index;
2844 object->changed = TRUE;
2847 /* Initialize the object */
2848 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,
2849 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2850 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2851 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2852 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2853 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2854 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2856 /* Save away the information */
2857 object->OriginalParms = *pLight;
2859 switch (pLight->Type) {
2860 case WINED3DLIGHT_POINT:
2861 /* Position */
2862 object->lightPosn[0] = pLight->Position.x;
2863 object->lightPosn[1] = pLight->Position.y;
2864 object->lightPosn[2] = pLight->Position.z;
2865 object->lightPosn[3] = 1.0f;
2866 object->cutoff = 180.0f;
2867 /* FIXME: Range */
2868 break;
2870 case WINED3DLIGHT_DIRECTIONAL:
2871 /* Direction */
2872 object->lightPosn[0] = -pLight->Direction.x;
2873 object->lightPosn[1] = -pLight->Direction.y;
2874 object->lightPosn[2] = -pLight->Direction.z;
2875 object->lightPosn[3] = 0.0;
2876 object->exponent = 0.0f;
2877 object->cutoff = 180.0f;
2878 break;
2880 case WINED3DLIGHT_SPOT:
2881 /* Position */
2882 object->lightPosn[0] = pLight->Position.x;
2883 object->lightPosn[1] = pLight->Position.y;
2884 object->lightPosn[2] = pLight->Position.z;
2885 object->lightPosn[3] = 1.0;
2887 /* Direction */
2888 object->lightDirn[0] = pLight->Direction.x;
2889 object->lightDirn[1] = pLight->Direction.y;
2890 object->lightDirn[2] = pLight->Direction.z;
2891 object->lightDirn[3] = 1.0;
2894 * opengl-ish and d3d-ish spot lights use too different models for the
2895 * light "intensity" as a function of the angle towards the main light direction,
2896 * so we only can approximate very roughly.
2897 * however spot lights are rather rarely used in games (if ever used at all).
2898 * furthermore if still used, probably nobody pays attention to such details.
2900 if (pLight->Falloff == 0) {
2901 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2902 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2903 * will always be 1.0 for both of them, and we don't have to care for the
2904 * rest of the rather complex calculation
2906 object->exponent = 0;
2907 } else {
2908 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2909 if (rho < 0.0001) rho = 0.0001f;
2910 object->exponent = -0.3/log(cos(rho/2));
2912 if (object->exponent > 128.0) {
2913 object->exponent = 128.0;
2915 object->cutoff = pLight->Phi*90/M_PI;
2917 /* FIXME: Range */
2918 break;
2920 default:
2921 FIXME("Unrecognized light type %d\n", pLight->Type);
2924 /* Update the live definitions if the light is currently assigned a glIndex */
2925 if (object->glIndex != -1 && !This->isRecordingState) {
2926 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2928 return WINED3D_OK;
2931 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2932 PLIGHTINFOEL *lightInfo = NULL;
2933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2934 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2935 struct list *e;
2936 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2938 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2939 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2940 if(lightInfo->OriginalIndex == Index) break;
2941 lightInfo = NULL;
2944 if (lightInfo == NULL) {
2945 TRACE("Light information requested but light not defined\n");
2946 return WINED3DERR_INVALIDCALL;
2949 *pLight = lightInfo->OriginalParms;
2950 return WINED3D_OK;
2953 /*****
2954 * Get / Set Light Enable
2955 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2956 *****/
2957 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2958 PLIGHTINFOEL *lightInfo = NULL;
2959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2960 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2961 struct list *e;
2962 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2964 /* Tests show true = 128...not clear why */
2965 Enable = Enable? 128: 0;
2967 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2968 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2969 if(lightInfo->OriginalIndex == Index) break;
2970 lightInfo = NULL;
2972 TRACE("Found light: %p\n", lightInfo);
2974 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2975 if (lightInfo == NULL) {
2977 TRACE("Light enabled requested but light not defined, so defining one!\n");
2978 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2980 /* Search for it again! Should be fairly quick as near head of list */
2981 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2982 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2983 if(lightInfo->OriginalIndex == Index) break;
2984 lightInfo = NULL;
2986 if (lightInfo == NULL) {
2987 FIXME("Adding default lights has failed dismally\n");
2988 return WINED3DERR_INVALIDCALL;
2992 lightInfo->enabledChanged = TRUE;
2993 if(!Enable) {
2994 if(lightInfo->glIndex != -1) {
2995 if(!This->isRecordingState) {
2996 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2999 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3000 lightInfo->glIndex = -1;
3001 } else {
3002 TRACE("Light already disabled, nothing to do\n");
3004 lightInfo->enabled = FALSE;
3005 } else {
3006 lightInfo->enabled = TRUE;
3007 if (lightInfo->glIndex != -1) {
3008 /* nop */
3009 TRACE("Nothing to do as light was enabled\n");
3010 } else {
3011 int i;
3012 /* Find a free gl light */
3013 for(i = 0; i < This->maxConcurrentLights; i++) {
3014 if(This->updateStateBlock->activeLights[i] == NULL) {
3015 This->updateStateBlock->activeLights[i] = lightInfo;
3016 lightInfo->glIndex = i;
3017 break;
3020 if(lightInfo->glIndex == -1) {
3021 /* Our tests show that Windows returns D3D_OK in this situation, even with
3022 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3023 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3024 * as well for those lights.
3026 * TODO: Test how this affects rendering
3028 FIXME("Too many concurrently active lights\n");
3029 return WINED3D_OK;
3032 /* i == lightInfo->glIndex */
3033 if(!This->isRecordingState) {
3034 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3039 return WINED3D_OK;
3042 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3044 PLIGHTINFOEL *lightInfo = NULL;
3045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3046 struct list *e;
3047 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3048 TRACE("(%p) : for idx(%d)\n", This, Index);
3050 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3051 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3052 if(lightInfo->OriginalIndex == Index) break;
3053 lightInfo = NULL;
3056 if (lightInfo == NULL) {
3057 TRACE("Light enabled state requested but light not defined\n");
3058 return WINED3DERR_INVALIDCALL;
3060 /* true is 128 according to SetLightEnable */
3061 *pEnable = lightInfo->enabled ? 128 : 0;
3062 return WINED3D_OK;
3065 /*****
3066 * Get / Set Clip Planes
3067 *****/
3068 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3070 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3072 /* Validate Index */
3073 if (Index >= GL_LIMITS(clipplanes)) {
3074 TRACE("Application has requested clipplane this device doesn't support\n");
3075 return WINED3DERR_INVALIDCALL;
3078 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3080 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3081 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3082 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3083 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3084 TRACE("Application is setting old values over, nothing to do\n");
3085 return WINED3D_OK;
3088 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3089 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3090 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3091 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3093 /* Handle recording of state blocks */
3094 if (This->isRecordingState) {
3095 TRACE("Recording... not performing anything\n");
3096 return WINED3D_OK;
3099 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3101 return WINED3D_OK;
3104 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3106 TRACE("(%p) : for idx %d\n", This, Index);
3108 /* Validate Index */
3109 if (Index >= GL_LIMITS(clipplanes)) {
3110 TRACE("Application has requested clipplane this device doesn't support\n");
3111 return WINED3DERR_INVALIDCALL;
3114 pPlane[0] = This->stateBlock->clipplane[Index][0];
3115 pPlane[1] = This->stateBlock->clipplane[Index][1];
3116 pPlane[2] = This->stateBlock->clipplane[Index][2];
3117 pPlane[3] = This->stateBlock->clipplane[Index][3];
3118 return WINED3D_OK;
3121 /*****
3122 * Get / Set Clip Plane Status
3123 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3124 *****/
3125 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3127 FIXME("(%p) : stub\n", This);
3128 if (NULL == pClipStatus) {
3129 return WINED3DERR_INVALIDCALL;
3131 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3132 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3133 return WINED3D_OK;
3136 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3138 FIXME("(%p) : stub\n", This);
3139 if (NULL == pClipStatus) {
3140 return WINED3DERR_INVALIDCALL;
3142 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3143 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3144 return WINED3D_OK;
3147 /*****
3148 * Get / Set Material
3149 *****/
3150 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3153 This->updateStateBlock->changed.material = TRUE;
3154 This->updateStateBlock->material = *pMaterial;
3156 /* Handle recording of state blocks */
3157 if (This->isRecordingState) {
3158 TRACE("Recording... not performing anything\n");
3159 return WINED3D_OK;
3162 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3163 return WINED3D_OK;
3166 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3168 *pMaterial = This->updateStateBlock->material;
3169 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3170 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3171 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3172 pMaterial->Ambient.b, pMaterial->Ambient.a);
3173 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3174 pMaterial->Specular.b, pMaterial->Specular.a);
3175 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3176 pMaterial->Emissive.b, pMaterial->Emissive.a);
3177 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3179 return WINED3D_OK;
3182 /*****
3183 * Get / Set Indices
3184 *****/
3185 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3187 IWineD3DIndexBuffer *oldIdxs;
3189 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3190 oldIdxs = This->updateStateBlock->pIndexData;
3192 This->updateStateBlock->changed.indices = TRUE;
3193 This->updateStateBlock->pIndexData = pIndexData;
3195 /* Handle recording of state blocks */
3196 if (This->isRecordingState) {
3197 TRACE("Recording... not performing anything\n");
3198 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3199 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3200 return WINED3D_OK;
3203 if(oldIdxs != pIndexData) {
3204 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3205 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3206 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3208 return WINED3D_OK;
3211 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3214 *ppIndexData = This->stateBlock->pIndexData;
3216 /* up ref count on ppindexdata */
3217 if (*ppIndexData) {
3218 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3219 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3220 }else{
3221 TRACE("(%p) No index data set\n", This);
3223 TRACE("Returning %p\n", *ppIndexData);
3225 return WINED3D_OK;
3228 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3229 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3231 TRACE("(%p)->(%d)\n", This, BaseIndex);
3233 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3234 TRACE("Application is setting the old value over, nothing to do\n");
3235 return WINED3D_OK;
3238 This->updateStateBlock->baseVertexIndex = BaseIndex;
3240 if (This->isRecordingState) {
3241 TRACE("Recording... not performing anything\n");
3242 return WINED3D_OK;
3244 /* The base vertex index affects the stream sources */
3245 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3246 return WINED3D_OK;
3249 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3251 TRACE("(%p) : base_index %p\n", This, base_index);
3253 *base_index = This->stateBlock->baseVertexIndex;
3255 TRACE("Returning %u\n", *base_index);
3257 return WINED3D_OK;
3260 /*****
3261 * Get / Set Viewports
3262 *****/
3263 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3266 TRACE("(%p)\n", This);
3267 This->updateStateBlock->changed.viewport = TRUE;
3268 This->updateStateBlock->viewport = *pViewport;
3270 /* Handle recording of state blocks */
3271 if (This->isRecordingState) {
3272 TRACE("Recording... not performing anything\n");
3273 return WINED3D_OK;
3276 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3277 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3279 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3280 return WINED3D_OK;
3284 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3286 TRACE("(%p)\n", This);
3287 *pViewport = This->stateBlock->viewport;
3288 return WINED3D_OK;
3291 /*****
3292 * Get / Set Render States
3293 * TODO: Verify against dx9 definitions
3294 *****/
3295 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3298 DWORD oldValue = This->stateBlock->renderState[State];
3300 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3302 This->updateStateBlock->changed.renderState[State] = TRUE;
3303 This->updateStateBlock->renderState[State] = Value;
3305 /* Handle recording of state blocks */
3306 if (This->isRecordingState) {
3307 TRACE("Recording... not performing anything\n");
3308 return WINED3D_OK;
3311 /* Compared here and not before the assignment to allow proper stateblock recording */
3312 if(Value == oldValue) {
3313 TRACE("Application is setting the old value over, nothing to do\n");
3314 } else {
3315 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3318 return WINED3D_OK;
3321 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3323 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3324 *pValue = This->stateBlock->renderState[State];
3325 return WINED3D_OK;
3328 /*****
3329 * Get / Set Sampler States
3330 * TODO: Verify against dx9 definitions
3331 *****/
3333 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3335 DWORD oldValue;
3337 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3338 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3340 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3341 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3344 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3345 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3346 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3349 * SetSampler is designed to allow for more than the standard up to 8 textures
3350 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3351 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3353 * http://developer.nvidia.com/object/General_FAQ.html#t6
3355 * There are two new settings for GForce
3356 * the sampler one:
3357 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3358 * and the texture one:
3359 * GL_MAX_TEXTURE_COORDS_ARB.
3360 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3361 ******************/
3363 oldValue = This->stateBlock->samplerState[Sampler][Type];
3364 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3365 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3367 /* Handle recording of state blocks */
3368 if (This->isRecordingState) {
3369 TRACE("Recording... not performing anything\n");
3370 return WINED3D_OK;
3373 if(oldValue == Value) {
3374 TRACE("Application is setting the old value over, nothing to do\n");
3375 return WINED3D_OK;
3378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3380 return WINED3D_OK;
3383 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3386 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3387 This, Sampler, debug_d3dsamplerstate(Type), Type);
3389 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3390 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3393 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3394 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3395 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3397 *Value = This->stateBlock->samplerState[Sampler][Type];
3398 TRACE("(%p) : Returning %#x\n", This, *Value);
3400 return WINED3D_OK;
3403 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3406 This->updateStateBlock->changed.scissorRect = TRUE;
3407 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3408 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3409 return WINED3D_OK;
3411 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3413 if(This->isRecordingState) {
3414 TRACE("Recording... not performing anything\n");
3415 return WINED3D_OK;
3418 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3420 return WINED3D_OK;
3423 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3426 *pRect = This->updateStateBlock->scissorRect;
3427 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3428 return WINED3D_OK;
3431 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3433 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3435 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3437 This->updateStateBlock->vertexDecl = pDecl;
3438 This->updateStateBlock->changed.vertexDecl = TRUE;
3440 if (This->isRecordingState) {
3441 TRACE("Recording... not performing anything\n");
3442 return WINED3D_OK;
3443 } else if(pDecl == oldDecl) {
3444 /* Checked after the assignment to allow proper stateblock recording */
3445 TRACE("Application is setting the old declaration over, nothing to do\n");
3446 return WINED3D_OK;
3449 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3450 return WINED3D_OK;
3453 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3456 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3458 *ppDecl = This->stateBlock->vertexDecl;
3459 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3460 return WINED3D_OK;
3463 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3465 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3467 This->updateStateBlock->vertexShader = pShader;
3468 This->updateStateBlock->changed.vertexShader = TRUE;
3470 if (This->isRecordingState) {
3471 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3472 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3473 TRACE("Recording... not performing anything\n");
3474 return WINED3D_OK;
3475 } else if(oldShader == pShader) {
3476 /* Checked here to allow proper stateblock recording */
3477 TRACE("App is setting the old shader over, nothing to do\n");
3478 return WINED3D_OK;
3481 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3482 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3483 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3485 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3487 return WINED3D_OK;
3490 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3493 if (NULL == ppShader) {
3494 return WINED3DERR_INVALIDCALL;
3496 *ppShader = This->stateBlock->vertexShader;
3497 if( NULL != *ppShader)
3498 IWineD3DVertexShader_AddRef(*ppShader);
3500 TRACE("(%p) : returning %p\n", This, *ppShader);
3501 return WINED3D_OK;
3504 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3505 IWineD3DDevice *iface,
3506 UINT start,
3507 CONST BOOL *srcData,
3508 UINT count) {
3510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3511 int i, cnt = min(count, MAX_CONST_B - start);
3513 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3514 iface, srcData, start, count);
3516 if (srcData == NULL || cnt < 0)
3517 return WINED3DERR_INVALIDCALL;
3519 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3520 for (i = 0; i < cnt; i++)
3521 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3523 for (i = start; i < cnt + start; ++i) {
3524 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3527 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3529 return WINED3D_OK;
3532 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3533 IWineD3DDevice *iface,
3534 UINT start,
3535 BOOL *dstData,
3536 UINT count) {
3538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3539 int cnt = min(count, MAX_CONST_B - start);
3541 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3542 iface, dstData, start, count);
3544 if (dstData == NULL || cnt < 0)
3545 return WINED3DERR_INVALIDCALL;
3547 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3548 return WINED3D_OK;
3551 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3552 IWineD3DDevice *iface,
3553 UINT start,
3554 CONST int *srcData,
3555 UINT count) {
3557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3558 int i, cnt = min(count, MAX_CONST_I - start);
3560 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3561 iface, srcData, start, count);
3563 if (srcData == NULL || cnt < 0)
3564 return WINED3DERR_INVALIDCALL;
3566 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3567 for (i = 0; i < cnt; i++)
3568 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3569 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3571 for (i = start; i < cnt + start; ++i) {
3572 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3575 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3577 return WINED3D_OK;
3580 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3581 IWineD3DDevice *iface,
3582 UINT start,
3583 int *dstData,
3584 UINT count) {
3586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3587 int cnt = min(count, MAX_CONST_I - start);
3589 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3590 iface, dstData, start, count);
3592 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3593 return WINED3DERR_INVALIDCALL;
3595 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3596 return WINED3D_OK;
3599 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3600 IWineD3DDevice *iface,
3601 UINT start,
3602 CONST float *srcData,
3603 UINT count) {
3605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3606 int i;
3608 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3609 iface, srcData, start, count);
3611 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3612 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3613 return WINED3DERR_INVALIDCALL;
3615 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3616 if(TRACE_ON(d3d)) {
3617 for (i = 0; i < count; i++)
3618 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3619 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3622 for (i = start; i < count + start; ++i) {
3623 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3624 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3625 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3626 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3627 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3629 ptr->idx[ptr->count++] = i;
3630 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3634 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3636 return WINED3D_OK;
3639 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3640 IWineD3DDevice *iface,
3641 UINT start,
3642 CONST float *srcData,
3643 UINT count) {
3645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3646 int i;
3648 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3649 iface, srcData, start, count);
3651 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3652 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3653 return WINED3DERR_INVALIDCALL;
3655 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3656 if(TRACE_ON(d3d)) {
3657 for (i = 0; i < count; i++)
3658 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3659 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3662 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3663 * context. On a context switch the old context will be fully dirtified
3665 memset(This->activeContext->vshader_const_dirty + start, 1,
3666 sizeof(*This->activeContext->vshader_const_dirty) * count);
3667 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3669 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3671 return WINED3D_OK;
3674 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3675 IWineD3DDevice *iface,
3676 UINT start,
3677 float *dstData,
3678 UINT count) {
3680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3681 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3683 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3684 iface, dstData, start, count);
3686 if (dstData == NULL || cnt < 0)
3687 return WINED3DERR_INVALIDCALL;
3689 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3690 return WINED3D_OK;
3693 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3694 DWORD i;
3695 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3696 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3700 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3701 int i = This->rev_tex_unit_map[unit];
3702 int j = This->texUnitMap[stage];
3704 This->texUnitMap[stage] = unit;
3705 if (i != -1 && i != stage) {
3706 This->texUnitMap[i] = -1;
3709 This->rev_tex_unit_map[unit] = stage;
3710 if (j != -1 && j != unit) {
3711 This->rev_tex_unit_map[j] = -1;
3715 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3716 int i;
3718 for (i = 0; i < MAX_TEXTURES; ++i) {
3719 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3720 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3721 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3722 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3723 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3724 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3725 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3726 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3728 if (color_op == WINED3DTOP_DISABLE) {
3729 /* Not used, and disable higher stages */
3730 while (i < MAX_TEXTURES) {
3731 This->fixed_function_usage_map[i] = FALSE;
3732 ++i;
3734 break;
3737 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3738 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3739 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3740 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3741 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3742 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3743 This->fixed_function_usage_map[i] = TRUE;
3744 } else {
3745 This->fixed_function_usage_map[i] = FALSE;
3748 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3749 This->fixed_function_usage_map[i+1] = TRUE;
3754 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3755 int i, tex;
3757 device_update_fixed_function_usage_map(This);
3759 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3760 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3761 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3762 if (!This->fixed_function_usage_map[i]) continue;
3764 if (This->texUnitMap[i] != i) {
3765 device_map_stage(This, i, i);
3766 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3767 markTextureStagesDirty(This, i);
3770 return;
3773 /* Now work out the mapping */
3774 tex = 0;
3775 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3776 if (!This->fixed_function_usage_map[i]) continue;
3778 if (This->texUnitMap[i] != tex) {
3779 device_map_stage(This, i, tex);
3780 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3781 markTextureStagesDirty(This, i);
3784 ++tex;
3788 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3789 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3790 int i;
3792 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3793 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3794 device_map_stage(This, i, i);
3795 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3796 if (i < MAX_TEXTURES) {
3797 markTextureStagesDirty(This, i);
3803 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3804 int current_mapping = This->rev_tex_unit_map[unit];
3806 if (current_mapping == -1) {
3807 /* Not currently used */
3808 return TRUE;
3811 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3812 /* Used by a fragment sampler */
3814 if (!pshader_sampler_tokens) {
3815 /* No pixel shader, check fixed function */
3816 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3819 /* Pixel shader, check the shader's sampler map */
3820 return !pshader_sampler_tokens[current_mapping];
3823 /* Used by a vertex sampler */
3824 return !vshader_sampler_tokens[current_mapping];
3827 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3828 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3829 DWORD *pshader_sampler_tokens = NULL;
3830 int start = GL_LIMITS(combined_samplers) - 1;
3831 int i;
3833 if (ps) {
3834 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3836 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3837 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3838 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3841 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3842 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3843 if (vshader_sampler_tokens[i]) {
3844 if (This->texUnitMap[vsampler_idx] != -1) {
3845 /* Already mapped somewhere */
3846 continue;
3849 while (start >= 0) {
3850 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3851 device_map_stage(This, vsampler_idx, start);
3852 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3854 --start;
3855 break;
3858 --start;
3864 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3865 BOOL vs = use_vs(This);
3866 BOOL ps = use_ps(This);
3868 * Rules are:
3869 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3870 * that would be really messy and require shader recompilation
3871 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3872 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3874 if (ps) {
3875 device_map_psamplers(This);
3876 } else {
3877 device_map_fixed_function_samplers(This);
3880 if (vs) {
3881 device_map_vsamplers(This, ps);
3885 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3887 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3888 This->updateStateBlock->pixelShader = pShader;
3889 This->updateStateBlock->changed.pixelShader = TRUE;
3891 /* Handle recording of state blocks */
3892 if (This->isRecordingState) {
3893 TRACE("Recording... not performing anything\n");
3896 if (This->isRecordingState) {
3897 TRACE("Recording... not performing anything\n");
3898 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3899 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3900 return WINED3D_OK;
3903 if(pShader == oldShader) {
3904 TRACE("App is setting the old pixel shader over, nothing to do\n");
3905 return WINED3D_OK;
3908 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3909 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3911 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3914 return WINED3D_OK;
3917 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3920 if (NULL == ppShader) {
3921 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3922 return WINED3DERR_INVALIDCALL;
3925 *ppShader = This->stateBlock->pixelShader;
3926 if (NULL != *ppShader) {
3927 IWineD3DPixelShader_AddRef(*ppShader);
3929 TRACE("(%p) : returning %p\n", This, *ppShader);
3930 return WINED3D_OK;
3933 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3934 IWineD3DDevice *iface,
3935 UINT start,
3936 CONST BOOL *srcData,
3937 UINT count) {
3939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3940 int i, cnt = min(count, MAX_CONST_B - start);
3942 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3943 iface, srcData, start, count);
3945 if (srcData == NULL || cnt < 0)
3946 return WINED3DERR_INVALIDCALL;
3948 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3949 for (i = 0; i < cnt; i++)
3950 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3952 for (i = start; i < cnt + start; ++i) {
3953 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3956 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3958 return WINED3D_OK;
3961 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3962 IWineD3DDevice *iface,
3963 UINT start,
3964 BOOL *dstData,
3965 UINT count) {
3967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3968 int cnt = min(count, MAX_CONST_B - start);
3970 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3971 iface, dstData, start, count);
3973 if (dstData == NULL || cnt < 0)
3974 return WINED3DERR_INVALIDCALL;
3976 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3977 return WINED3D_OK;
3980 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3981 IWineD3DDevice *iface,
3982 UINT start,
3983 CONST int *srcData,
3984 UINT count) {
3986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3987 int i, cnt = min(count, MAX_CONST_I - start);
3989 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3990 iface, srcData, start, count);
3992 if (srcData == NULL || cnt < 0)
3993 return WINED3DERR_INVALIDCALL;
3995 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3996 for (i = 0; i < cnt; i++)
3997 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3998 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4000 for (i = start; i < cnt + start; ++i) {
4001 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4004 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4006 return WINED3D_OK;
4009 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4010 IWineD3DDevice *iface,
4011 UINT start,
4012 int *dstData,
4013 UINT count) {
4015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4016 int cnt = min(count, MAX_CONST_I - start);
4018 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4019 iface, dstData, start, count);
4021 if (dstData == NULL || cnt < 0)
4022 return WINED3DERR_INVALIDCALL;
4024 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4025 return WINED3D_OK;
4028 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4029 IWineD3DDevice *iface,
4030 UINT start,
4031 CONST float *srcData,
4032 UINT count) {
4034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4035 int i;
4037 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4038 iface, srcData, start, count);
4040 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4041 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4042 return WINED3DERR_INVALIDCALL;
4044 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4045 if(TRACE_ON(d3d)) {
4046 for (i = 0; i < count; i++)
4047 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4048 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4051 for (i = start; i < count + start; ++i) {
4052 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
4053 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
4054 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
4055 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
4056 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
4058 ptr->idx[ptr->count++] = i;
4059 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4063 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4065 return WINED3D_OK;
4068 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4069 IWineD3DDevice *iface,
4070 UINT start,
4071 CONST float *srcData,
4072 UINT count) {
4074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4075 int i;
4077 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4078 iface, srcData, start, count);
4080 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4081 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4082 return WINED3DERR_INVALIDCALL;
4084 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4085 if(TRACE_ON(d3d)) {
4086 for (i = 0; i < count; i++)
4087 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4088 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4091 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4092 * context. On a context switch the old context will be fully dirtified
4094 memset(This->activeContext->pshader_const_dirty + start, 1,
4095 sizeof(*This->activeContext->pshader_const_dirty) * count);
4096 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4098 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4100 return WINED3D_OK;
4103 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4104 IWineD3DDevice *iface,
4105 UINT start,
4106 float *dstData,
4107 UINT count) {
4109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4110 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4112 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4113 iface, dstData, start, count);
4115 if (dstData == NULL || cnt < 0)
4116 return WINED3DERR_INVALIDCALL;
4118 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4119 return WINED3D_OK;
4122 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4123 static HRESULT
4124 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4125 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4126 unsigned int i;
4127 DWORD DestFVF = dest->fvf;
4128 WINED3DVIEWPORT vp;
4129 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4130 BOOL doClip;
4131 int numTextures;
4133 if (lpStrideData->u.s.normal.lpData) {
4134 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4137 if (lpStrideData->u.s.position.lpData == NULL) {
4138 ERR("Source has no position mask\n");
4139 return WINED3DERR_INVALIDCALL;
4142 /* We might access VBOs from this code, so hold the lock */
4143 ENTER_GL();
4145 if (dest->resource.allocatedMemory == NULL) {
4146 /* This may happen if we do direct locking into a vbo. Unlikely,
4147 * but theoretically possible(ddraw processvertices test)
4149 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4150 if(!dest->resource.allocatedMemory) {
4151 LEAVE_GL();
4152 ERR("Out of memory\n");
4153 return E_OUTOFMEMORY;
4155 if(dest->vbo) {
4156 void *src;
4157 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4158 checkGLcall("glBindBufferARB");
4159 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4160 if(src) {
4161 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4163 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4164 checkGLcall("glUnmapBufferARB");
4168 /* Get a pointer into the destination vbo(create one if none exists) and
4169 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4171 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4172 dest->Flags |= VBFLAG_CREATEVBO;
4173 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4176 if(dest->vbo) {
4177 unsigned char extrabytes = 0;
4178 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4179 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4180 * this may write 4 extra bytes beyond the area that should be written
4182 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4183 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4184 if(!dest_conv_addr) {
4185 ERR("Out of memory\n");
4186 /* Continue without storing converted vertices */
4188 dest_conv = dest_conv_addr;
4191 /* Should I clip?
4192 * a) WINED3DRS_CLIPPING is enabled
4193 * b) WINED3DVOP_CLIP is passed
4195 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4196 static BOOL warned = FALSE;
4198 * The clipping code is not quite correct. Some things need
4199 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4200 * so disable clipping for now.
4201 * (The graphics in Half-Life are broken, and my processvertices
4202 * test crashes with IDirect3DDevice3)
4203 doClip = TRUE;
4205 doClip = FALSE;
4206 if(!warned) {
4207 warned = TRUE;
4208 FIXME("Clipping is broken and disabled for now\n");
4210 } else doClip = FALSE;
4211 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4213 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4214 WINED3DTS_VIEW,
4215 &view_mat);
4216 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4217 WINED3DTS_PROJECTION,
4218 &proj_mat);
4219 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4220 WINED3DTS_WORLDMATRIX(0),
4221 &world_mat);
4223 TRACE("View mat:\n");
4224 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);
4225 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);
4226 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);
4227 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);
4229 TRACE("Proj mat:\n");
4230 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);
4231 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);
4232 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);
4233 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);
4235 TRACE("World mat:\n");
4236 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);
4237 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);
4238 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);
4239 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);
4241 /* Get the viewport */
4242 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4243 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4244 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4246 multiply_matrix(&mat,&view_mat,&world_mat);
4247 multiply_matrix(&mat,&proj_mat,&mat);
4249 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4251 for (i = 0; i < dwCount; i+= 1) {
4252 unsigned int tex_index;
4254 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4255 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4256 /* The position first */
4257 float *p =
4258 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4259 float x, y, z, rhw;
4260 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4262 /* Multiplication with world, view and projection matrix */
4263 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);
4264 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);
4265 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);
4266 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);
4268 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4270 /* WARNING: The following things are taken from d3d7 and were not yet checked
4271 * against d3d8 or d3d9!
4274 /* Clipping conditions: From msdn
4276 * A vertex is clipped if it does not match the following requirements
4277 * -rhw < x <= rhw
4278 * -rhw < y <= rhw
4279 * 0 < z <= rhw
4280 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4282 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4283 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4287 if( !doClip ||
4288 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4289 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4290 ( rhw > eps ) ) ) {
4292 /* "Normal" viewport transformation (not clipped)
4293 * 1) The values are divided by rhw
4294 * 2) The y axis is negative, so multiply it with -1
4295 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4296 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4297 * 4) Multiply x with Width/2 and add Width/2
4298 * 5) The same for the height
4299 * 6) Add the viewpoint X and Y to the 2D coordinates and
4300 * The minimum Z value to z
4301 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4303 * Well, basically it's simply a linear transformation into viewport
4304 * coordinates
4307 x /= rhw;
4308 y /= rhw;
4309 z /= rhw;
4311 y *= -1;
4313 x *= vp.Width / 2;
4314 y *= vp.Height / 2;
4315 z *= vp.MaxZ - vp.MinZ;
4317 x += vp.Width / 2 + vp.X;
4318 y += vp.Height / 2 + vp.Y;
4319 z += vp.MinZ;
4321 rhw = 1 / rhw;
4322 } else {
4323 /* That vertex got clipped
4324 * Contrary to OpenGL it is not dropped completely, it just
4325 * undergoes a different calculation.
4327 TRACE("Vertex got clipped\n");
4328 x += rhw;
4329 y += rhw;
4331 x /= 2;
4332 y /= 2;
4334 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4335 * outside of the main vertex buffer memory. That needs some more
4336 * investigation...
4340 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4343 ( (float *) dest_ptr)[0] = x;
4344 ( (float *) dest_ptr)[1] = y;
4345 ( (float *) dest_ptr)[2] = z;
4346 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4348 dest_ptr += 3 * sizeof(float);
4350 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4351 dest_ptr += sizeof(float);
4354 if(dest_conv) {
4355 float w = 1 / rhw;
4356 ( (float *) dest_conv)[0] = x * w;
4357 ( (float *) dest_conv)[1] = y * w;
4358 ( (float *) dest_conv)[2] = z * w;
4359 ( (float *) dest_conv)[3] = w;
4361 dest_conv += 3 * sizeof(float);
4363 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4364 dest_conv += sizeof(float);
4368 if (DestFVF & WINED3DFVF_PSIZE) {
4369 dest_ptr += sizeof(DWORD);
4370 if(dest_conv) dest_conv += sizeof(DWORD);
4372 if (DestFVF & WINED3DFVF_NORMAL) {
4373 float *normal =
4374 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4375 /* AFAIK this should go into the lighting information */
4376 FIXME("Didn't expect the destination to have a normal\n");
4377 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4378 if(dest_conv) {
4379 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4383 if (DestFVF & WINED3DFVF_DIFFUSE) {
4384 DWORD *color_d =
4385 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4386 if(!color_d) {
4387 static BOOL warned = FALSE;
4389 if(!warned) {
4390 ERR("No diffuse color in source, but destination has one\n");
4391 warned = TRUE;
4394 *( (DWORD *) dest_ptr) = 0xffffffff;
4395 dest_ptr += sizeof(DWORD);
4397 if(dest_conv) {
4398 *( (DWORD *) dest_conv) = 0xffffffff;
4399 dest_conv += sizeof(DWORD);
4402 else {
4403 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4404 if(dest_conv) {
4405 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4406 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4407 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4408 dest_conv += sizeof(DWORD);
4413 if (DestFVF & WINED3DFVF_SPECULAR) {
4414 /* What's the color value in the feedback buffer? */
4415 DWORD *color_s =
4416 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4417 if(!color_s) {
4418 static BOOL warned = FALSE;
4420 if(!warned) {
4421 ERR("No specular color in source, but destination has one\n");
4422 warned = TRUE;
4425 *( (DWORD *) dest_ptr) = 0xFF000000;
4426 dest_ptr += sizeof(DWORD);
4428 if(dest_conv) {
4429 *( (DWORD *) dest_conv) = 0xFF000000;
4430 dest_conv += sizeof(DWORD);
4433 else {
4434 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4435 if(dest_conv) {
4436 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4437 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4438 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4439 dest_conv += sizeof(DWORD);
4444 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4445 float *tex_coord =
4446 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4447 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4448 if(!tex_coord) {
4449 ERR("No source texture, but destination requests one\n");
4450 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4451 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4453 else {
4454 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4455 if(dest_conv) {
4456 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4462 if(dest_conv) {
4463 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4464 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4465 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4466 dwCount * get_flexible_vertex_size(DestFVF),
4467 dest_conv_addr));
4468 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4469 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4472 LEAVE_GL();
4474 return WINED3D_OK;
4476 #undef copy_and_next
4478 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4480 WineDirect3DVertexStridedData strided;
4481 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4482 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4484 if(pVertexDecl) {
4485 ERR("Output vertex declaration not implemented yet\n");
4488 /* Need any context to write to the vbo. */
4489 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4491 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4492 * control the streamIsUP flag, thus restore it afterwards.
4494 This->stateBlock->streamIsUP = FALSE;
4495 memset(&strided, 0, sizeof(strided));
4496 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4497 This->stateBlock->streamIsUP = streamWasUP;
4499 if(vbo || SrcStartIndex) {
4500 unsigned int i;
4501 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4502 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4504 * Also get the start index in, but only loop over all elements if there's something to add at all.
4506 #define FIXSRC(type) \
4507 if(strided.u.s.type.VBO) { \
4508 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4509 strided.u.s.type.VBO = 0; \
4510 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4511 ENTER_GL(); \
4512 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4513 vb->vbo = 0; \
4514 LEAVE_GL(); \
4516 if(strided.u.s.type.lpData) { \
4517 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4519 FIXSRC(position);
4520 FIXSRC(blendWeights);
4521 FIXSRC(blendMatrixIndices);
4522 FIXSRC(normal);
4523 FIXSRC(pSize);
4524 FIXSRC(diffuse);
4525 FIXSRC(specular);
4526 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4527 FIXSRC(texCoords[i]);
4529 FIXSRC(position2);
4530 FIXSRC(normal2);
4531 FIXSRC(tangent);
4532 FIXSRC(binormal);
4533 FIXSRC(tessFactor);
4534 FIXSRC(fog);
4535 FIXSRC(depth);
4536 FIXSRC(sample);
4537 #undef FIXSRC
4540 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4543 /*****
4544 * Get / Set Texture Stage States
4545 * TODO: Verify against dx9 definitions
4546 *****/
4547 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4549 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4551 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4553 if (Stage >= MAX_TEXTURES) {
4554 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4555 return WINED3D_OK;
4558 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4559 This->updateStateBlock->textureState[Stage][Type] = Value;
4561 if (This->isRecordingState) {
4562 TRACE("Recording... not performing anything\n");
4563 return WINED3D_OK;
4566 /* Checked after the assignments to allow proper stateblock recording */
4567 if(oldValue == Value) {
4568 TRACE("App is setting the old value over, nothing to do\n");
4569 return WINED3D_OK;
4572 if(Stage > This->stateBlock->lowest_disabled_stage &&
4573 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4574 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4575 * Changes in other states are important on disabled stages too
4577 return WINED3D_OK;
4580 if(Type == WINED3DTSS_COLOROP) {
4581 int i;
4583 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4584 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4585 * they have to be disabled
4587 * The current stage is dirtified below.
4589 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4590 TRACE("Additionally dirtifying stage %d\n", i);
4591 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4593 This->stateBlock->lowest_disabled_stage = Stage;
4594 TRACE("New lowest disabled: %d\n", Stage);
4595 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4596 /* Previously disabled stage enabled. Stages above it may need enabling
4597 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4598 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4600 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4603 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4604 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4605 break;
4607 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4608 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4610 This->stateBlock->lowest_disabled_stage = i;
4611 TRACE("New lowest disabled: %d\n", i);
4615 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4617 return WINED3D_OK;
4620 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4622 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4623 *pValue = This->updateStateBlock->textureState[Stage][Type];
4624 return WINED3D_OK;
4627 /*****
4628 * Get / Set Texture
4629 *****/
4630 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4632 IWineD3DBaseTexture *oldTexture;
4634 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4636 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4637 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4640 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4641 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4642 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4645 oldTexture = This->updateStateBlock->textures[Stage];
4647 if(pTexture != NULL) {
4648 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4650 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4651 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4652 return WINED3DERR_INVALIDCALL;
4654 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4657 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4658 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4660 This->updateStateBlock->changed.textures[Stage] = TRUE;
4661 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4662 This->updateStateBlock->textures[Stage] = pTexture;
4664 /* Handle recording of state blocks */
4665 if (This->isRecordingState) {
4666 TRACE("Recording... not performing anything\n");
4667 return WINED3D_OK;
4670 if(oldTexture == pTexture) {
4671 TRACE("App is setting the same texture again, nothing to do\n");
4672 return WINED3D_OK;
4675 /** NOTE: MSDN says that setTexture increases the reference count,
4676 * and that the application must set the texture back to null (or have a leaky application),
4677 * This means we should pass the refcount up to the parent
4678 *******************************/
4679 if (NULL != This->updateStateBlock->textures[Stage]) {
4680 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4681 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4683 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4684 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4685 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4686 * so the COLOROP and ALPHAOP have to be dirtified.
4688 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4689 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4691 if(bindCount == 1) {
4692 new->baseTexture.sampler = Stage;
4694 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4698 if (NULL != oldTexture) {
4699 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4700 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4702 IWineD3DBaseTexture_Release(oldTexture);
4703 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4704 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4705 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4708 if(bindCount && old->baseTexture.sampler == Stage) {
4709 int i;
4710 /* Have to do a search for the other sampler(s) where the texture is bound to
4711 * Shouldn't happen as long as apps bind a texture only to one stage
4713 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4714 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4715 if(This->updateStateBlock->textures[i] == oldTexture) {
4716 old->baseTexture.sampler = i;
4717 break;
4723 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4725 return WINED3D_OK;
4728 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4731 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4733 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4734 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4737 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4738 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4739 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4742 *ppTexture=This->stateBlock->textures[Stage];
4743 if (*ppTexture)
4744 IWineD3DBaseTexture_AddRef(*ppTexture);
4746 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4748 return WINED3D_OK;
4751 /*****
4752 * Get Back Buffer
4753 *****/
4754 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4755 IWineD3DSurface **ppBackBuffer) {
4756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4757 IWineD3DSwapChain *swapChain;
4758 HRESULT hr;
4760 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4762 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4763 if (hr == WINED3D_OK) {
4764 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4765 IWineD3DSwapChain_Release(swapChain);
4766 } else {
4767 *ppBackBuffer = NULL;
4769 return hr;
4772 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4774 WARN("(%p) : stub, calling idirect3d for now\n", This);
4775 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4778 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4780 IWineD3DSwapChain *swapChain;
4781 HRESULT hr;
4783 if(iSwapChain > 0) {
4784 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4785 if (hr == WINED3D_OK) {
4786 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4787 IWineD3DSwapChain_Release(swapChain);
4788 } else {
4789 FIXME("(%p) Error getting display mode\n", This);
4791 } else {
4792 /* Don't read the real display mode,
4793 but return the stored mode instead. X11 can't change the color
4794 depth, and some apps are pretty angry if they SetDisplayMode from
4795 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4797 Also don't relay to the swapchain because with ddraw it's possible
4798 that there isn't a swapchain at all */
4799 pMode->Width = This->ddraw_width;
4800 pMode->Height = This->ddraw_height;
4801 pMode->Format = This->ddraw_format;
4802 pMode->RefreshRate = 0;
4803 hr = WINED3D_OK;
4806 return hr;
4809 /*****
4810 * Stateblock related functions
4811 *****/
4813 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4815 IWineD3DStateBlockImpl *object;
4816 HRESULT temp_result;
4817 int i;
4819 TRACE("(%p)\n", This);
4821 if (This->isRecordingState) {
4822 return WINED3DERR_INVALIDCALL;
4825 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4826 if (NULL == object ) {
4827 FIXME("(%p)Error allocating memory for stateblock\n", This);
4828 return E_OUTOFMEMORY;
4830 TRACE("(%p) created object %p\n", This, object);
4831 object->wineD3DDevice= This;
4832 /** FIXME: object->parent = parent; **/
4833 object->parent = NULL;
4834 object->blockType = WINED3DSBT_RECORDED;
4835 object->ref = 1;
4836 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4838 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4839 list_init(&object->lightMap[i]);
4842 temp_result = allocate_shader_constants(object);
4843 if (WINED3D_OK != temp_result)
4844 return temp_result;
4846 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4847 This->updateStateBlock = object;
4848 This->isRecordingState = TRUE;
4850 TRACE("(%p) recording stateblock %p\n",This , object);
4851 return WINED3D_OK;
4854 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4856 unsigned int i, j;
4857 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4859 if (!This->isRecordingState) {
4860 FIXME("(%p) not recording! returning error\n", This);
4861 *ppStateBlock = NULL;
4862 return WINED3DERR_INVALIDCALL;
4865 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4866 if(object->changed.renderState[i]) {
4867 object->contained_render_states[object->num_contained_render_states] = i;
4868 object->num_contained_render_states++;
4871 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4872 if(object->changed.transform[i]) {
4873 object->contained_transform_states[object->num_contained_transform_states] = i;
4874 object->num_contained_transform_states++;
4877 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4878 if(object->changed.vertexShaderConstantsF[i]) {
4879 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4880 object->num_contained_vs_consts_f++;
4883 for(i = 0; i < MAX_CONST_I; i++) {
4884 if(object->changed.vertexShaderConstantsI[i]) {
4885 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4886 object->num_contained_vs_consts_i++;
4889 for(i = 0; i < MAX_CONST_B; i++) {
4890 if(object->changed.vertexShaderConstantsB[i]) {
4891 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4892 object->num_contained_vs_consts_b++;
4895 for(i = 0; i < MAX_CONST_I; i++) {
4896 if(object->changed.pixelShaderConstantsI[i]) {
4897 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4898 object->num_contained_ps_consts_i++;
4901 for(i = 0; i < MAX_CONST_B; i++) {
4902 if(object->changed.pixelShaderConstantsB[i]) {
4903 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4904 object->num_contained_ps_consts_b++;
4907 for(i = 0; i < MAX_TEXTURES; i++) {
4908 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4909 if(object->changed.textureState[i][j]) {
4910 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4911 object->contained_tss_states[object->num_contained_tss_states].state = j;
4912 object->num_contained_tss_states++;
4916 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4917 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4918 if(object->changed.samplerState[i][j]) {
4919 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4920 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4921 object->num_contained_sampler_states++;
4926 *ppStateBlock = (IWineD3DStateBlock*) object;
4927 This->isRecordingState = FALSE;
4928 This->updateStateBlock = This->stateBlock;
4929 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4930 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4931 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4932 return WINED3D_OK;
4935 /*****
4936 * Scene related functions
4937 *****/
4938 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4939 /* At the moment we have no need for any functionality at the beginning
4940 of a scene */
4941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4942 TRACE("(%p)\n", This);
4944 if(This->inScene) {
4945 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4946 return WINED3DERR_INVALIDCALL;
4948 This->inScene = TRUE;
4949 return WINED3D_OK;
4952 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4954 TRACE("(%p)\n", This);
4956 if(!This->inScene) {
4957 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4958 return WINED3DERR_INVALIDCALL;
4961 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4962 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4963 glFlush();
4964 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4965 * fails
4968 This->inScene = FALSE;
4969 return WINED3D_OK;
4972 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4973 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4974 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4976 IWineD3DSwapChain *swapChain = NULL;
4977 int i;
4978 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4980 TRACE("(%p) Presenting the frame\n", This);
4982 for(i = 0 ; i < swapchains ; i ++) {
4984 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4985 TRACE("presentinng chain %d, %p\n", i, swapChain);
4986 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4987 IWineD3DSwapChain_Release(swapChain);
4990 return WINED3D_OK;
4993 /* Not called from the VTable (internal subroutine) */
4994 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4995 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4996 float Z, DWORD Stencil) {
4997 GLbitfield glMask = 0;
4998 unsigned int i;
4999 WINED3DRECT curRect;
5000 RECT vp_rect;
5001 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5002 UINT drawable_width, drawable_height;
5003 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5004 IWineD3DSwapChainImpl *swapchain = NULL;
5006 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5007 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5008 * for the cleared parts, and the untouched parts.
5010 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5011 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5012 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5013 * checking all this if the dest surface is in the drawable anyway.
5015 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5016 while(1) {
5017 if(vp->X != 0 || vp->Y != 0 ||
5018 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5019 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5020 break;
5022 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5023 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5024 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5025 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5026 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5027 break;
5029 if(Count > 0 && pRects && (
5030 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5031 pRects[0].x2 < target->currentDesc.Width ||
5032 pRects[0].y2 < target->currentDesc.Height)) {
5033 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5034 break;
5036 break;
5040 target->get_drawable_size(target, &drawable_width, &drawable_height);
5042 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5043 ENTER_GL();
5045 /* Only set the values up once, as they are not changing */
5046 if (Flags & WINED3DCLEAR_STENCIL) {
5047 glClearStencil(Stencil);
5048 checkGLcall("glClearStencil");
5049 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5050 glStencilMask(0xFFFFFFFF);
5053 if (Flags & WINED3DCLEAR_ZBUFFER) {
5054 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5055 glDepthMask(GL_TRUE);
5056 glClearDepth(Z);
5057 checkGLcall("glClearDepth");
5058 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5061 if (vp->X != 0 || vp->Y != 0 ||
5062 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5063 surface_load_ds_location(This->stencilBufferTarget, location);
5065 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5066 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5067 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5068 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5069 surface_load_ds_location(This->stencilBufferTarget, location);
5071 else if (Count > 0 && pRects && (
5072 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5073 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5074 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5075 surface_load_ds_location(This->stencilBufferTarget, location);
5079 if (Flags & WINED3DCLEAR_TARGET) {
5080 TRACE("Clearing screen with glClear to color %x\n", Color);
5081 glClearColor(D3DCOLOR_R(Color),
5082 D3DCOLOR_G(Color),
5083 D3DCOLOR_B(Color),
5084 D3DCOLOR_A(Color));
5085 checkGLcall("glClearColor");
5087 /* Clear ALL colors! */
5088 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5089 glMask = glMask | GL_COLOR_BUFFER_BIT;
5092 vp_rect.left = vp->X;
5093 vp_rect.top = vp->Y;
5094 vp_rect.right = vp->X + vp->Width;
5095 vp_rect.bottom = vp->Y + vp->Height;
5096 if (!(Count > 0 && pRects)) {
5097 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5098 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5100 if(This->render_offscreen) {
5101 glScissor(vp_rect.left, vp_rect.top,
5102 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5103 } else {
5104 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5105 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5107 checkGLcall("glScissor");
5108 glClear(glMask);
5109 checkGLcall("glClear");
5110 } else {
5111 /* Now process each rect in turn */
5112 for (i = 0; i < Count; i++) {
5113 /* Note gl uses lower left, width/height */
5114 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5115 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5116 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5118 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5119 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5120 curRect.x1, (target->currentDesc.Height - curRect.y2),
5121 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5123 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5124 * The rectangle is not cleared, no error is returned, but further rectanlges are
5125 * still cleared if they are valid
5127 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5128 TRACE("Rectangle with negative dimensions, ignoring\n");
5129 continue;
5132 if(This->render_offscreen) {
5133 glScissor(curRect.x1, curRect.y1,
5134 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5135 } else {
5136 glScissor(curRect.x1, drawable_height - curRect.y2,
5137 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5139 checkGLcall("glScissor");
5141 glClear(glMask);
5142 checkGLcall("glClear");
5146 /* Restore the old values (why..?) */
5147 if (Flags & WINED3DCLEAR_STENCIL) {
5148 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5150 if (Flags & WINED3DCLEAR_TARGET) {
5151 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5152 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5153 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5154 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5155 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5157 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5158 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5160 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5162 if (Flags & WINED3DCLEAR_ZBUFFER) {
5163 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5164 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5165 surface_modify_ds_location(This->stencilBufferTarget, location);
5168 LEAVE_GL();
5170 IWineD3DSurface_GetContainer( (IWineD3DSurface *) target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5171 if (swapchain) {
5172 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5173 glFlush();
5175 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5178 return WINED3D_OK;
5181 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5182 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5184 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5186 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5187 Count, pRects, Flags, Color, Z, Stencil);
5189 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5190 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5191 /* TODO: What about depth stencil buffers without stencil bits? */
5192 return WINED3DERR_INVALIDCALL;
5195 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5198 /*****
5199 * Drawing functions
5200 *****/
5201 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5202 UINT PrimitiveCount) {
5204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5206 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5207 debug_d3dprimitivetype(PrimitiveType),
5208 StartVertex, PrimitiveCount);
5210 if(!This->stateBlock->vertexDecl) {
5211 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5212 return WINED3DERR_INVALIDCALL;
5215 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5216 if(This->stateBlock->streamIsUP) {
5217 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5218 This->stateBlock->streamIsUP = FALSE;
5221 if(This->stateBlock->loadBaseVertexIndex != 0) {
5222 This->stateBlock->loadBaseVertexIndex = 0;
5223 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5225 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5226 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5227 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5228 return WINED3D_OK;
5231 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5232 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5233 WINED3DPRIMITIVETYPE PrimitiveType,
5234 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5237 UINT idxStride = 2;
5238 IWineD3DIndexBuffer *pIB;
5239 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5240 GLuint vbo;
5242 pIB = This->stateBlock->pIndexData;
5243 if (!pIB) {
5244 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5245 * without an index buffer set. (The first time at least...)
5246 * D3D8 simply dies, but I doubt it can do much harm to return
5247 * D3DERR_INVALIDCALL there as well. */
5248 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5249 return WINED3DERR_INVALIDCALL;
5252 if(!This->stateBlock->vertexDecl) {
5253 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5254 return WINED3DERR_INVALIDCALL;
5257 if(This->stateBlock->streamIsUP) {
5258 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5259 This->stateBlock->streamIsUP = FALSE;
5261 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5263 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5264 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5265 minIndex, NumVertices, startIndex, primCount);
5267 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5268 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5269 idxStride = 2;
5270 } else {
5271 idxStride = 4;
5274 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5275 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5276 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5279 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5280 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5282 return WINED3D_OK;
5285 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5286 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5287 UINT VertexStreamZeroStride) {
5288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5289 IWineD3DVertexBuffer *vb;
5291 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5292 debug_d3dprimitivetype(PrimitiveType),
5293 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5295 if(!This->stateBlock->vertexDecl) {
5296 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5297 return WINED3DERR_INVALIDCALL;
5300 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5301 vb = This->stateBlock->streamSource[0];
5302 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5303 if(vb) IWineD3DVertexBuffer_Release(vb);
5304 This->stateBlock->streamOffset[0] = 0;
5305 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5306 This->stateBlock->streamIsUP = TRUE;
5307 This->stateBlock->loadBaseVertexIndex = 0;
5309 /* TODO: Only mark dirty if drawing from a different UP address */
5310 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5312 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5313 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5315 /* MSDN specifies stream zero settings must be set to NULL */
5316 This->stateBlock->streamStride[0] = 0;
5317 This->stateBlock->streamSource[0] = NULL;
5319 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5320 * the new stream sources or use UP drawing again
5322 return WINED3D_OK;
5325 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5326 UINT MinVertexIndex, UINT NumVertices,
5327 UINT PrimitiveCount, CONST void* pIndexData,
5328 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5329 UINT VertexStreamZeroStride) {
5330 int idxStride;
5331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5332 IWineD3DVertexBuffer *vb;
5333 IWineD3DIndexBuffer *ib;
5335 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5336 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5337 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5338 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5340 if(!This->stateBlock->vertexDecl) {
5341 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5342 return WINED3DERR_INVALIDCALL;
5345 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5346 idxStride = 2;
5347 } else {
5348 idxStride = 4;
5351 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5352 vb = This->stateBlock->streamSource[0];
5353 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5354 if(vb) IWineD3DVertexBuffer_Release(vb);
5355 This->stateBlock->streamIsUP = TRUE;
5356 This->stateBlock->streamOffset[0] = 0;
5357 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5359 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5360 This->stateBlock->baseVertexIndex = 0;
5361 This->stateBlock->loadBaseVertexIndex = 0;
5362 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5363 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5364 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5366 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5368 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5369 This->stateBlock->streamSource[0] = NULL;
5370 This->stateBlock->streamStride[0] = 0;
5371 ib = This->stateBlock->pIndexData;
5372 if(ib) {
5373 IWineD3DIndexBuffer_Release(ib);
5374 This->stateBlock->pIndexData = NULL;
5376 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5377 * SetStreamSource to specify a vertex buffer
5380 return WINED3D_OK;
5383 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5386 /* Mark the state dirty until we have nicer tracking
5387 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5388 * that value.
5390 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5391 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5392 This->stateBlock->baseVertexIndex = 0;
5393 This->up_strided = DrawPrimStrideData;
5394 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5395 This->up_strided = NULL;
5396 return WINED3D_OK;
5399 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5401 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5403 /* Mark the state dirty until we have nicer tracking
5404 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5405 * that value.
5407 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5408 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5409 This->stateBlock->streamIsUP = TRUE;
5410 This->stateBlock->baseVertexIndex = 0;
5411 This->up_strided = DrawPrimStrideData;
5412 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5413 This->up_strided = NULL;
5414 return WINED3D_OK;
5417 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5418 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5419 * not callable by the app directly no parameter validation checks are needed here.
5421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5422 WINED3DLOCKED_BOX src;
5423 WINED3DLOCKED_BOX dst;
5424 HRESULT hr;
5425 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5427 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5428 * dirtification to improve loading performance.
5430 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5431 if(FAILED(hr)) return hr;
5432 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5433 if(FAILED(hr)) {
5434 IWineD3DVolume_UnlockBox(pSourceVolume);
5435 return hr;
5438 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5440 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5441 if(FAILED(hr)) {
5442 IWineD3DVolume_UnlockBox(pSourceVolume);
5443 } else {
5444 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5446 return hr;
5449 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5450 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5452 HRESULT hr = WINED3D_OK;
5453 WINED3DRESOURCETYPE sourceType;
5454 WINED3DRESOURCETYPE destinationType;
5455 int i ,levels;
5457 /* TODO: think about moving the code into IWineD3DBaseTexture */
5459 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5461 /* verify that the source and destination textures aren't NULL */
5462 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5463 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5464 This, pSourceTexture, pDestinationTexture);
5465 hr = WINED3DERR_INVALIDCALL;
5468 if (pSourceTexture == pDestinationTexture) {
5469 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5470 This, pSourceTexture, pDestinationTexture);
5471 hr = WINED3DERR_INVALIDCALL;
5473 /* Verify that the source and destination textures are the same type */
5474 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5475 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5477 if (sourceType != destinationType) {
5478 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5479 This);
5480 hr = WINED3DERR_INVALIDCALL;
5483 /* check that both textures have the identical numbers of levels */
5484 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5485 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5486 hr = WINED3DERR_INVALIDCALL;
5489 if (WINED3D_OK == hr) {
5491 /* Make sure that the destination texture is loaded */
5492 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5494 /* Update every surface level of the texture */
5495 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5497 switch (sourceType) {
5498 case WINED3DRTYPE_TEXTURE:
5500 IWineD3DSurface *srcSurface;
5501 IWineD3DSurface *destSurface;
5503 for (i = 0 ; i < levels ; ++i) {
5504 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5505 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5506 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5507 IWineD3DSurface_Release(srcSurface);
5508 IWineD3DSurface_Release(destSurface);
5509 if (WINED3D_OK != hr) {
5510 WARN("(%p) : Call to update surface failed\n", This);
5511 return hr;
5515 break;
5516 case WINED3DRTYPE_CUBETEXTURE:
5518 IWineD3DSurface *srcSurface;
5519 IWineD3DSurface *destSurface;
5520 WINED3DCUBEMAP_FACES faceType;
5522 for (i = 0 ; i < levels ; ++i) {
5523 /* Update each cube face */
5524 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5525 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5526 if (WINED3D_OK != hr) {
5527 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5528 } else {
5529 TRACE("Got srcSurface %p\n", srcSurface);
5531 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5532 if (WINED3D_OK != hr) {
5533 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5534 } else {
5535 TRACE("Got desrSurface %p\n", destSurface);
5537 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5538 IWineD3DSurface_Release(srcSurface);
5539 IWineD3DSurface_Release(destSurface);
5540 if (WINED3D_OK != hr) {
5541 WARN("(%p) : Call to update surface failed\n", This);
5542 return hr;
5547 break;
5549 case WINED3DRTYPE_VOLUMETEXTURE:
5551 IWineD3DVolume *srcVolume = NULL;
5552 IWineD3DVolume *destVolume = NULL;
5554 for (i = 0 ; i < levels ; ++i) {
5555 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5556 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5557 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5558 IWineD3DVolume_Release(srcVolume);
5559 IWineD3DVolume_Release(destVolume);
5560 if (WINED3D_OK != hr) {
5561 WARN("(%p) : Call to update volume failed\n", This);
5562 return hr;
5566 break;
5568 default:
5569 FIXME("(%p) : Unsupported source and destination type\n", This);
5570 hr = WINED3DERR_INVALIDCALL;
5574 return hr;
5577 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5578 IWineD3DSwapChain *swapChain;
5579 HRESULT hr;
5580 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5581 if(hr == WINED3D_OK) {
5582 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5583 IWineD3DSwapChain_Release(swapChain);
5585 return hr;
5588 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5590 IWineD3DBaseTextureImpl *texture;
5591 const GlPixelFormatDesc *gl_info;
5592 DWORD i;
5594 TRACE("(%p) : %p\n", This, pNumPasses);
5596 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5597 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5598 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5599 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5601 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5602 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5603 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5606 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5607 if(!texture) continue;
5608 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5609 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5611 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5612 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5613 return E_FAIL;
5615 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5616 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5617 return E_FAIL;
5619 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5620 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5621 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5622 return E_FAIL;
5626 /* return a sensible default */
5627 *pNumPasses = 1;
5629 TRACE("returning D3D_OK\n");
5630 return WINED3D_OK;
5633 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5635 int i;
5637 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5638 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5639 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5640 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5645 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5647 int j;
5648 UINT NewSize;
5649 PALETTEENTRY **palettes;
5651 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5653 if (PaletteNumber >= MAX_PALETTES) {
5654 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5655 return WINED3DERR_INVALIDCALL;
5658 if (PaletteNumber >= This->NumberOfPalettes) {
5659 NewSize = This->NumberOfPalettes;
5660 do {
5661 NewSize *= 2;
5662 } while(PaletteNumber >= NewSize);
5663 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5664 if (!palettes) {
5665 ERR("Out of memory!\n");
5666 return E_OUTOFMEMORY;
5668 This->palettes = palettes;
5669 This->NumberOfPalettes = NewSize;
5672 if (!This->palettes[PaletteNumber]) {
5673 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5674 if (!This->palettes[PaletteNumber]) {
5675 ERR("Out of memory!\n");
5676 return E_OUTOFMEMORY;
5680 for (j = 0; j < 256; ++j) {
5681 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5682 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5683 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5684 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5686 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5687 TRACE("(%p) : returning\n", This);
5688 return WINED3D_OK;
5691 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5693 int j;
5694 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5695 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5696 /* What happens in such situation isn't documented; Native seems to silently abort
5697 on such conditions. Return Invalid Call. */
5698 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5699 return WINED3DERR_INVALIDCALL;
5701 for (j = 0; j < 256; ++j) {
5702 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5703 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5704 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5705 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5707 TRACE("(%p) : returning\n", This);
5708 return WINED3D_OK;
5711 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5713 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5714 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5715 (tested with reference rasterizer). Return Invalid Call. */
5716 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5717 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5718 return WINED3DERR_INVALIDCALL;
5720 /*TODO: stateblocks */
5721 if (This->currentPalette != PaletteNumber) {
5722 This->currentPalette = PaletteNumber;
5723 dirtify_p8_texture_samplers(This);
5725 TRACE("(%p) : returning\n", This);
5726 return WINED3D_OK;
5729 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5731 if (PaletteNumber == NULL) {
5732 WARN("(%p) : returning Invalid Call\n", This);
5733 return WINED3DERR_INVALIDCALL;
5735 /*TODO: stateblocks */
5736 *PaletteNumber = This->currentPalette;
5737 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5738 return WINED3D_OK;
5741 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5743 static BOOL showFixmes = TRUE;
5744 if (showFixmes) {
5745 FIXME("(%p) : stub\n", This);
5746 showFixmes = FALSE;
5749 This->softwareVertexProcessing = bSoftware;
5750 return WINED3D_OK;
5754 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5756 static BOOL showFixmes = TRUE;
5757 if (showFixmes) {
5758 FIXME("(%p) : stub\n", This);
5759 showFixmes = FALSE;
5761 return This->softwareVertexProcessing;
5765 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5767 IWineD3DSwapChain *swapChain;
5768 HRESULT hr;
5770 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5772 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5773 if(hr == WINED3D_OK){
5774 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5775 IWineD3DSwapChain_Release(swapChain);
5776 }else{
5777 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5779 return hr;
5783 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5785 static BOOL showfixmes = TRUE;
5786 if(nSegments != 0.0f) {
5787 if( showfixmes) {
5788 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5789 showfixmes = FALSE;
5792 return WINED3D_OK;
5795 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5797 static BOOL showfixmes = TRUE;
5798 if( showfixmes) {
5799 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5800 showfixmes = FALSE;
5802 return 0.0f;
5805 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5807 /** TODO: remove casts to IWineD3DSurfaceImpl
5808 * NOTE: move code to surface to accomplish this
5809 ****************************************/
5810 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5811 int srcWidth, srcHeight;
5812 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5813 WINED3DFORMAT destFormat, srcFormat;
5814 UINT destSize;
5815 int srcLeft, destLeft, destTop;
5816 WINED3DPOOL srcPool, destPool;
5817 int offset = 0;
5818 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5819 glDescriptor *glDescription = NULL;
5820 GLenum dummy;
5821 int sampler;
5822 int bpp;
5823 CONVERT_TYPES convert = NO_CONVERSION;
5825 WINED3DSURFACE_DESC winedesc;
5827 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5828 memset(&winedesc, 0, sizeof(winedesc));
5829 winedesc.Width = &srcSurfaceWidth;
5830 winedesc.Height = &srcSurfaceHeight;
5831 winedesc.Pool = &srcPool;
5832 winedesc.Format = &srcFormat;
5834 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5836 winedesc.Width = &destSurfaceWidth;
5837 winedesc.Height = &destSurfaceHeight;
5838 winedesc.Pool = &destPool;
5839 winedesc.Format = &destFormat;
5840 winedesc.Size = &destSize;
5842 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5844 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5845 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5846 return WINED3DERR_INVALIDCALL;
5849 /* This call loads the opengl surface directly, instead of copying the surface to the
5850 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5851 * copy in sysmem and use regular surface loading.
5853 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5854 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5855 if(convert != NO_CONVERSION) {
5856 return IWineD3DSurface_BltFast(pDestinationSurface,
5857 pDestPoint ? pDestPoint->x : 0,
5858 pDestPoint ? pDestPoint->y : 0,
5859 pSourceSurface, (RECT *) pSourceRect, 0);
5862 if (destFormat == WINED3DFMT_UNKNOWN) {
5863 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5864 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5866 /* Get the update surface description */
5867 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5870 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5872 ENTER_GL();
5874 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5875 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5876 checkGLcall("glActiveTextureARB");
5879 /* Make sure the surface is loaded and up to date */
5880 IWineD3DSurface_PreLoad(pDestinationSurface);
5881 IWineD3DSurface_BindTexture(pDestinationSurface);
5883 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5885 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5886 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5887 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5888 srcLeft = pSourceRect ? pSourceRect->left : 0;
5889 destLeft = pDestPoint ? pDestPoint->x : 0;
5890 destTop = pDestPoint ? pDestPoint->y : 0;
5893 /* This function doesn't support compressed textures
5894 the pitch is just bytesPerPixel * width */
5895 if(srcWidth != srcSurfaceWidth || srcLeft ){
5896 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5897 offset += srcLeft * pSrcSurface->bytesPerPixel;
5898 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5900 /* TODO DXT formats */
5902 if(pSourceRect != NULL && pSourceRect->top != 0){
5903 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5905 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5906 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
5907 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5909 /* Sanity check */
5910 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5912 /* need to lock the surface to get the data */
5913 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5916 /* TODO: Cube and volume support */
5917 if(rowoffset != 0){
5918 /* not a whole row so we have to do it a line at a time */
5919 int j;
5921 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5922 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5924 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5926 glTexSubImage2D(glDescription->target
5927 ,glDescription->level
5928 ,destLeft
5930 ,srcWidth
5932 ,glDescription->glFormat
5933 ,glDescription->glType
5934 ,data /* could be quicker using */
5936 data += rowoffset;
5939 } else { /* Full width, so just write out the whole texture */
5940 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5942 if (WINED3DFMT_DXT1 == destFormat ||
5943 WINED3DFMT_DXT2 == destFormat ||
5944 WINED3DFMT_DXT3 == destFormat ||
5945 WINED3DFMT_DXT4 == destFormat ||
5946 WINED3DFMT_DXT5 == destFormat) {
5947 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5948 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5949 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5950 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5951 } if (destFormat != srcFormat) {
5952 FIXME("Updating mixed format compressed texture is not curretly support\n");
5953 } else {
5954 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
5955 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
5957 } else {
5958 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5962 } else {
5963 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
5964 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
5967 checkGLcall("glTexSubImage2D");
5969 LEAVE_GL();
5971 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5972 sampler = This->rev_tex_unit_map[0];
5973 if (sampler != -1) {
5974 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5977 return WINED3D_OK;
5980 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5982 struct WineD3DRectPatch *patch;
5983 unsigned int i;
5984 struct list *e;
5985 BOOL found;
5986 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5988 if(!(Handle || pRectPatchInfo)) {
5989 /* TODO: Write a test for the return value, thus the FIXME */
5990 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5991 return WINED3DERR_INVALIDCALL;
5994 if(Handle) {
5995 i = PATCHMAP_HASHFUNC(Handle);
5996 found = FALSE;
5997 LIST_FOR_EACH(e, &This->patches[i]) {
5998 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5999 if(patch->Handle == Handle) {
6000 found = TRUE;
6001 break;
6005 if(!found) {
6006 TRACE("Patch does not exist. Creating a new one\n");
6007 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6008 patch->Handle = Handle;
6009 list_add_head(&This->patches[i], &patch->entry);
6010 } else {
6011 TRACE("Found existing patch %p\n", patch);
6013 } else {
6014 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6015 * attributes we have to tesselate, read back, and draw. This needs a patch
6016 * management structure instance. Create one.
6018 * A possible improvement is to check if a vertex shader is used, and if not directly
6019 * draw the patch.
6021 FIXME("Drawing an uncached patch. This is slow\n");
6022 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6025 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6026 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6027 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6028 HRESULT hr;
6029 TRACE("Tesselation density or patch info changed, retesselating\n");
6031 if(pRectPatchInfo) {
6032 patch->RectPatchInfo = *pRectPatchInfo;
6034 patch->numSegs[0] = pNumSegs[0];
6035 patch->numSegs[1] = pNumSegs[1];
6036 patch->numSegs[2] = pNumSegs[2];
6037 patch->numSegs[3] = pNumSegs[3];
6039 hr = tesselate_rectpatch(This, patch);
6040 if(FAILED(hr)) {
6041 WARN("Patch tesselation failed\n");
6043 /* Do not release the handle to store the params of the patch */
6044 if(!Handle) {
6045 HeapFree(GetProcessHeap(), 0, patch);
6047 return hr;
6051 This->currentPatch = patch;
6052 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6053 This->currentPatch = NULL;
6055 /* Destroy uncached patches */
6056 if(!Handle) {
6057 HeapFree(GetProcessHeap(), 0, patch->mem);
6058 HeapFree(GetProcessHeap(), 0, patch);
6060 return WINED3D_OK;
6063 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6065 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6066 FIXME("(%p) : Stub\n", This);
6067 return WINED3D_OK;
6070 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6072 int i;
6073 struct WineD3DRectPatch *patch;
6074 struct list *e;
6075 TRACE("(%p) Handle(%d)\n", This, Handle);
6077 i = PATCHMAP_HASHFUNC(Handle);
6078 LIST_FOR_EACH(e, &This->patches[i]) {
6079 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6080 if(patch->Handle == Handle) {
6081 TRACE("Deleting patch %p\n", patch);
6082 list_remove(&patch->entry);
6083 HeapFree(GetProcessHeap(), 0, patch->mem);
6084 HeapFree(GetProcessHeap(), 0, patch);
6085 return WINED3D_OK;
6089 /* TODO: Write a test for the return value */
6090 FIXME("Attempt to destroy nonexistent patch\n");
6091 return WINED3DERR_INVALIDCALL;
6094 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6095 HRESULT hr;
6096 IWineD3DSwapChain *swapchain;
6098 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6099 if (SUCCEEDED(hr)) {
6100 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6101 return swapchain;
6104 return NULL;
6107 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6109 IWineD3DSwapChain *swapchain;
6111 swapchain = get_swapchain(surface);
6112 if (swapchain) {
6113 GLenum buffer;
6115 TRACE("Surface %p is onscreen\n", surface);
6117 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6118 ENTER_GL();
6119 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6120 buffer = surface_get_gl_buffer(surface, swapchain);
6121 glDrawBuffer(buffer);
6122 checkGLcall("glDrawBuffer()");
6123 } else {
6124 TRACE("Surface %p is offscreen\n", surface);
6126 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6127 ENTER_GL();
6128 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6129 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6130 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6131 checkGLcall("glFramebufferRenderbufferEXT");
6134 if (rect) {
6135 glEnable(GL_SCISSOR_TEST);
6136 if(!swapchain) {
6137 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6138 } else {
6139 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6140 rect->x2 - rect->x1, rect->y2 - rect->y1);
6142 checkGLcall("glScissor");
6143 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6144 } else {
6145 glDisable(GL_SCISSOR_TEST);
6147 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6149 glDisable(GL_BLEND);
6150 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6152 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6153 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6155 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6156 glClear(GL_COLOR_BUFFER_BIT);
6157 checkGLcall("glClear");
6159 if (This->activeContext->current_fbo) {
6160 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6161 } else {
6162 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6163 checkGLcall("glBindFramebuffer()");
6166 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6167 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6168 glDrawBuffer(GL_BACK);
6169 checkGLcall("glDrawBuffer()");
6172 LEAVE_GL();
6175 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6176 unsigned int r, g, b, a;
6177 DWORD ret;
6179 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6180 destfmt == WINED3DFMT_R8G8B8)
6181 return color;
6183 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6185 a = (color & 0xff000000) >> 24;
6186 r = (color & 0x00ff0000) >> 16;
6187 g = (color & 0x0000ff00) >> 8;
6188 b = (color & 0x000000ff) >> 0;
6190 switch(destfmt)
6192 case WINED3DFMT_R5G6B5:
6193 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6194 r = (r * 32) / 256;
6195 g = (g * 64) / 256;
6196 b = (b * 32) / 256;
6197 ret = r << 11;
6198 ret |= g << 5;
6199 ret |= b;
6200 TRACE("Returning %08x\n", ret);
6201 return ret;
6203 case WINED3DFMT_X1R5G5B5:
6204 case WINED3DFMT_A1R5G5B5:
6205 a = (a * 2) / 256;
6206 r = (r * 32) / 256;
6207 g = (g * 32) / 256;
6208 b = (b * 32) / 256;
6209 ret = a << 15;
6210 ret |= r << 10;
6211 ret |= g << 5;
6212 ret |= b << 0;
6213 TRACE("Returning %08x\n", ret);
6214 return ret;
6216 case WINED3DFMT_A8:
6217 TRACE("Returning %08x\n", a);
6218 return a;
6220 case WINED3DFMT_X4R4G4B4:
6221 case WINED3DFMT_A4R4G4B4:
6222 a = (a * 16) / 256;
6223 r = (r * 16) / 256;
6224 g = (g * 16) / 256;
6225 b = (b * 16) / 256;
6226 ret = a << 12;
6227 ret |= r << 8;
6228 ret |= g << 4;
6229 ret |= b << 0;
6230 TRACE("Returning %08x\n", ret);
6231 return ret;
6233 case WINED3DFMT_R3G3B2:
6234 r = (r * 8) / 256;
6235 g = (g * 8) / 256;
6236 b = (b * 4) / 256;
6237 ret = r << 5;
6238 ret |= g << 2;
6239 ret |= b << 0;
6240 TRACE("Returning %08x\n", ret);
6241 return ret;
6243 case WINED3DFMT_X8B8G8R8:
6244 case WINED3DFMT_A8B8G8R8:
6245 ret = a << 24;
6246 ret |= b << 16;
6247 ret |= g << 8;
6248 ret |= r << 0;
6249 TRACE("Returning %08x\n", ret);
6250 return ret;
6252 case WINED3DFMT_A2R10G10B10:
6253 a = (a * 4) / 256;
6254 r = (r * 1024) / 256;
6255 g = (g * 1024) / 256;
6256 b = (b * 1024) / 256;
6257 ret = a << 30;
6258 ret |= r << 20;
6259 ret |= g << 10;
6260 ret |= b << 0;
6261 TRACE("Returning %08x\n", ret);
6262 return ret;
6264 case WINED3DFMT_A2B10G10R10:
6265 a = (a * 4) / 256;
6266 r = (r * 1024) / 256;
6267 g = (g * 1024) / 256;
6268 b = (b * 1024) / 256;
6269 ret = a << 30;
6270 ret |= b << 20;
6271 ret |= g << 10;
6272 ret |= r << 0;
6273 TRACE("Returning %08x\n", ret);
6274 return ret;
6276 default:
6277 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6278 return 0;
6282 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6284 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6285 WINEDDBLTFX BltFx;
6286 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6288 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6289 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6290 return WINED3DERR_INVALIDCALL;
6293 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6294 color_fill_fbo(iface, pSurface, pRect, color);
6295 return WINED3D_OK;
6296 } else {
6297 /* Just forward this to the DirectDraw blitting engine */
6298 memset(&BltFx, 0, sizeof(BltFx));
6299 BltFx.dwSize = sizeof(BltFx);
6300 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6301 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6305 /* rendertarget and depth stencil functions */
6306 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6309 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6310 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6311 return WINED3DERR_INVALIDCALL;
6314 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6315 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6316 /* Note inc ref on returned surface */
6317 if(*ppRenderTarget != NULL)
6318 IWineD3DSurface_AddRef(*ppRenderTarget);
6319 return WINED3D_OK;
6322 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6324 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6325 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6326 IWineD3DSwapChainImpl *Swapchain;
6327 HRESULT hr;
6329 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6331 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6332 if(hr != WINED3D_OK) {
6333 ERR("Can't get the swapchain\n");
6334 return hr;
6337 /* Make sure to release the swapchain */
6338 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6340 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6341 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6342 return WINED3DERR_INVALIDCALL;
6344 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6345 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6346 return WINED3DERR_INVALIDCALL;
6349 if(Swapchain->frontBuffer != Front) {
6350 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6352 if(Swapchain->frontBuffer)
6353 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6354 Swapchain->frontBuffer = Front;
6356 if(Swapchain->frontBuffer) {
6357 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6361 if(Back && !Swapchain->backBuffer) {
6362 /* We need memory for the back buffer array - only one back buffer this way */
6363 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6364 if(!Swapchain->backBuffer) {
6365 ERR("Out of memory\n");
6366 return E_OUTOFMEMORY;
6370 if(Swapchain->backBuffer[0] != Back) {
6371 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6373 /* What to do about the context here in the case of multithreading? Not sure.
6374 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6376 ENTER_GL();
6377 if(!Swapchain->backBuffer[0]) {
6378 /* GL was told to draw to the front buffer at creation,
6379 * undo that
6381 glDrawBuffer(GL_BACK);
6382 checkGLcall("glDrawBuffer(GL_BACK)");
6383 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6384 Swapchain->presentParms.BackBufferCount = 1;
6385 } else if (!Back) {
6386 /* That makes problems - disable for now */
6387 /* glDrawBuffer(GL_FRONT); */
6388 checkGLcall("glDrawBuffer(GL_FRONT)");
6389 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6390 Swapchain->presentParms.BackBufferCount = 0;
6392 LEAVE_GL();
6394 if(Swapchain->backBuffer[0])
6395 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6396 Swapchain->backBuffer[0] = Back;
6398 if(Swapchain->backBuffer[0]) {
6399 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6400 } else {
6401 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6402 Swapchain->backBuffer = NULL;
6407 return WINED3D_OK;
6410 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6412 *ppZStencilSurface = This->stencilBufferTarget;
6413 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6415 if(*ppZStencilSurface != NULL) {
6416 /* Note inc ref on returned surface */
6417 IWineD3DSurface_AddRef(*ppZStencilSurface);
6418 return WINED3D_OK;
6419 } else {
6420 return WINED3DERR_NOTFOUND;
6424 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6425 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6427 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6428 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6429 GLenum gl_filter;
6430 POINT offset = {0, 0};
6432 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6433 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6434 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6435 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6437 switch (filter) {
6438 case WINED3DTEXF_LINEAR:
6439 gl_filter = GL_LINEAR;
6440 break;
6442 default:
6443 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6444 case WINED3DTEXF_NONE:
6445 case WINED3DTEXF_POINT:
6446 gl_filter = GL_NEAREST;
6447 break;
6450 /* Attach src surface to src fbo */
6451 src_swapchain = get_swapchain(src_surface);
6452 if (src_swapchain) {
6453 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6455 TRACE("Source surface %p is onscreen\n", src_surface);
6456 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6457 /* Make sure the drawable is up to date. In the offscreen case
6458 * attach_surface_fbo() implicitly takes care of this. */
6459 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6461 if(buffer == GL_FRONT) {
6462 RECT windowsize;
6463 UINT h;
6464 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6465 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6466 h = windowsize.bottom - windowsize.top;
6467 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6468 src_rect->y1 = offset.y + h - src_rect->y1;
6469 src_rect->y2 = offset.y + h - src_rect->y2;
6470 } else {
6471 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6472 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6475 ENTER_GL();
6476 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6477 glReadBuffer(buffer);
6478 checkGLcall("glReadBuffer()");
6479 } else {
6480 TRACE("Source surface %p is offscreen\n", src_surface);
6481 ENTER_GL();
6482 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6483 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6484 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6485 checkGLcall("glReadBuffer()");
6486 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6487 checkGLcall("glFramebufferRenderbufferEXT");
6489 LEAVE_GL();
6491 /* Attach dst surface to dst fbo */
6492 dst_swapchain = get_swapchain(dst_surface);
6493 if (dst_swapchain) {
6494 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6496 TRACE("Destination surface %p is onscreen\n", dst_surface);
6497 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6498 /* Make sure the drawable is up to date. In the offscreen case
6499 * attach_surface_fbo() implicitly takes care of this. */
6500 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6502 if(buffer == GL_FRONT) {
6503 RECT windowsize;
6504 UINT h;
6505 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6506 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6507 h = windowsize.bottom - windowsize.top;
6508 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6509 dst_rect->y1 = offset.y + h - dst_rect->y1;
6510 dst_rect->y2 = offset.y + h - dst_rect->y2;
6511 } else {
6512 /* Screen coords = window coords, surface height = window height */
6513 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6514 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6517 ENTER_GL();
6518 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6519 glDrawBuffer(buffer);
6520 checkGLcall("glDrawBuffer()");
6521 } else {
6522 TRACE("Destination surface %p is offscreen\n", dst_surface);
6524 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6525 if(!src_swapchain) {
6526 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6529 ENTER_GL();
6530 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6531 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6532 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6533 checkGLcall("glDrawBuffer()");
6534 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6535 checkGLcall("glFramebufferRenderbufferEXT");
6537 glDisable(GL_SCISSOR_TEST);
6538 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6540 if (flip) {
6541 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6542 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6543 checkGLcall("glBlitFramebuffer()");
6544 } else {
6545 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6546 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6547 checkGLcall("glBlitFramebuffer()");
6550 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6552 if (This->activeContext->current_fbo) {
6553 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6554 } else {
6555 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6556 checkGLcall("glBindFramebuffer()");
6559 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6560 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6561 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6562 glDrawBuffer(GL_BACK);
6563 checkGLcall("glDrawBuffer()");
6565 LEAVE_GL();
6568 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6570 WINED3DVIEWPORT viewport;
6572 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6574 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6575 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6576 This, RenderTargetIndex, GL_LIMITS(buffers));
6577 return WINED3DERR_INVALIDCALL;
6580 /* MSDN says that null disables the render target
6581 but a device must always be associated with a render target
6582 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6584 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6585 FIXME("Trying to set render target 0 to NULL\n");
6586 return WINED3DERR_INVALIDCALL;
6588 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6589 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);
6590 return WINED3DERR_INVALIDCALL;
6593 /* If we are trying to set what we already have, don't bother */
6594 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6595 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6596 return WINED3D_OK;
6598 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6599 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6600 This->render_targets[RenderTargetIndex] = pRenderTarget;
6602 /* Render target 0 is special */
6603 if(RenderTargetIndex == 0) {
6604 /* Finally, reset the viewport as the MSDN states. */
6605 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6606 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6607 viewport.X = 0;
6608 viewport.Y = 0;
6609 viewport.MaxZ = 1.0f;
6610 viewport.MinZ = 0.0f;
6611 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6612 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6613 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6615 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6617 return WINED3D_OK;
6620 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6622 HRESULT hr = WINED3D_OK;
6623 IWineD3DSurface *tmp;
6625 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6627 if (pNewZStencil == This->stencilBufferTarget) {
6628 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6629 } else {
6630 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6631 * depending on the renter target implementation being used.
6632 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6633 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6634 * stencil buffer and incur an extra memory overhead
6635 ******************************************************/
6637 if (This->stencilBufferTarget) {
6638 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6639 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6640 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6641 } else {
6642 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6643 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6644 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6648 tmp = This->stencilBufferTarget;
6649 This->stencilBufferTarget = pNewZStencil;
6650 /* should we be calling the parent or the wined3d surface? */
6651 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6652 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6653 hr = WINED3D_OK;
6655 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6656 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6657 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6658 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6659 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6663 return hr;
6666 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6667 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6669 /* TODO: the use of Impl is deprecated. */
6670 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6671 WINED3DLOCKED_RECT lockedRect;
6673 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6675 /* some basic validation checks */
6676 if(This->cursorTexture) {
6677 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6678 ENTER_GL();
6679 glDeleteTextures(1, &This->cursorTexture);
6680 LEAVE_GL();
6681 This->cursorTexture = 0;
6684 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6685 This->haveHardwareCursor = TRUE;
6686 else
6687 This->haveHardwareCursor = FALSE;
6689 if(pCursorBitmap) {
6690 WINED3DLOCKED_RECT rect;
6692 /* MSDN: Cursor must be A8R8G8B8 */
6693 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6694 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6695 return WINED3DERR_INVALIDCALL;
6698 /* MSDN: Cursor must be smaller than the display mode */
6699 if(pSur->currentDesc.Width > This->ddraw_width ||
6700 pSur->currentDesc.Height > This->ddraw_height) {
6701 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);
6702 return WINED3DERR_INVALIDCALL;
6705 if (!This->haveHardwareCursor) {
6706 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6708 /* Do not store the surface's pointer because the application may
6709 * release it after setting the cursor image. Windows doesn't
6710 * addref the set surface, so we can't do this either without
6711 * creating circular refcount dependencies. Copy out the gl texture
6712 * instead.
6714 This->cursorWidth = pSur->currentDesc.Width;
6715 This->cursorHeight = pSur->currentDesc.Height;
6716 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6718 const GlPixelFormatDesc *glDesc;
6719 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6720 char *mem, *bits = (char *)rect.pBits;
6721 GLint intfmt = glDesc->glInternal;
6722 GLint format = glDesc->glFormat;
6723 GLint type = glDesc->glType;
6724 INT height = This->cursorHeight;
6725 INT width = This->cursorWidth;
6726 INT bpp = tableEntry->bpp;
6727 INT i, sampler;
6729 /* Reformat the texture memory (pitch and width can be
6730 * different) */
6731 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6732 for(i = 0; i < height; i++)
6733 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6734 IWineD3DSurface_UnlockRect(pCursorBitmap);
6735 ENTER_GL();
6737 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6738 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6739 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6742 /* Make sure that a proper texture unit is selected */
6743 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6744 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6745 checkGLcall("glActiveTextureARB");
6747 sampler = This->rev_tex_unit_map[0];
6748 if (sampler != -1) {
6749 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6751 /* Create a new cursor texture */
6752 glGenTextures(1, &This->cursorTexture);
6753 checkGLcall("glGenTextures");
6754 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6755 checkGLcall("glBindTexture");
6756 /* Copy the bitmap memory into the cursor texture */
6757 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6758 HeapFree(GetProcessHeap(), 0, mem);
6759 checkGLcall("glTexImage2D");
6761 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6762 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6763 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6766 LEAVE_GL();
6768 else
6770 FIXME("A cursor texture was not returned.\n");
6771 This->cursorTexture = 0;
6774 else
6776 /* Draw a hardware cursor */
6777 ICONINFO cursorInfo;
6778 HCURSOR cursor;
6779 /* Create and clear maskBits because it is not needed for
6780 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6781 * chunks. */
6782 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6783 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6784 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6785 WINED3DLOCK_NO_DIRTY_UPDATE |
6786 WINED3DLOCK_READONLY
6788 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6789 pSur->currentDesc.Height);
6791 cursorInfo.fIcon = FALSE;
6792 cursorInfo.xHotspot = XHotSpot;
6793 cursorInfo.yHotspot = YHotSpot;
6794 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6795 pSur->currentDesc.Height, 1,
6796 1, &maskBits);
6797 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6798 pSur->currentDesc.Height, 1,
6799 32, lockedRect.pBits);
6800 IWineD3DSurface_UnlockRect(pCursorBitmap);
6801 /* Create our cursor and clean up. */
6802 cursor = CreateIconIndirect(&cursorInfo);
6803 SetCursor(cursor);
6804 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6805 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6806 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6807 This->hardwareCursor = cursor;
6808 HeapFree(GetProcessHeap(), 0, maskBits);
6812 This->xHotSpot = XHotSpot;
6813 This->yHotSpot = YHotSpot;
6814 return WINED3D_OK;
6817 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6819 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6821 This->xScreenSpace = XScreenSpace;
6822 This->yScreenSpace = YScreenSpace;
6824 return;
6828 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6830 BOOL oldVisible = This->bCursorVisible;
6831 POINT pt;
6833 TRACE("(%p) : visible(%d)\n", This, bShow);
6836 * When ShowCursor is first called it should make the cursor appear at the OS's last
6837 * known cursor position. Because of this, some applications just repetitively call
6838 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6840 GetCursorPos(&pt);
6841 This->xScreenSpace = pt.x;
6842 This->yScreenSpace = pt.y;
6844 if (This->haveHardwareCursor) {
6845 This->bCursorVisible = bShow;
6846 if (bShow)
6847 SetCursor(This->hardwareCursor);
6848 else
6849 SetCursor(NULL);
6851 else
6853 if (This->cursorTexture)
6854 This->bCursorVisible = bShow;
6857 return oldVisible;
6860 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6862 IWineD3DResourceImpl *resource;
6863 TRACE("(%p) : state (%u)\n", This, This->state);
6865 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6866 switch (This->state) {
6867 case WINED3D_OK:
6868 return WINED3D_OK;
6869 case WINED3DERR_DEVICELOST:
6871 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6872 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6873 return WINED3DERR_DEVICENOTRESET;
6875 return WINED3DERR_DEVICELOST;
6877 case WINED3DERR_DRIVERINTERNALERROR:
6878 return WINED3DERR_DRIVERINTERNALERROR;
6881 /* Unknown state */
6882 return WINED3DERR_DRIVERINTERNALERROR;
6886 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6888 /** FIXME: Resource tracking needs to be done,
6889 * The closes we can do to this is set the priorities of all managed textures low
6890 * and then reset them.
6891 ***********************************************************/
6892 FIXME("(%p) : stub\n", This);
6893 return WINED3D_OK;
6896 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6897 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6899 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6900 if(surface->Flags & SFLAG_DIBSECTION) {
6901 /* Release the DC */
6902 SelectObject(surface->hDC, surface->dib.holdbitmap);
6903 DeleteDC(surface->hDC);
6904 /* Release the DIB section */
6905 DeleteObject(surface->dib.DIBsection);
6906 surface->dib.bitmap_data = NULL;
6907 surface->resource.allocatedMemory = NULL;
6908 surface->Flags &= ~SFLAG_DIBSECTION;
6910 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6911 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6912 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6913 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6914 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6915 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6916 } else {
6917 surface->pow2Width = surface->pow2Height = 1;
6918 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6919 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6921 surface->glRect.left = 0;
6922 surface->glRect.top = 0;
6923 surface->glRect.right = surface->pow2Width;
6924 surface->glRect.bottom = surface->pow2Height;
6926 if(surface->glDescription.textureName) {
6927 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6928 ENTER_GL();
6929 glDeleteTextures(1, &surface->glDescription.textureName);
6930 LEAVE_GL();
6931 surface->glDescription.textureName = 0;
6932 surface->Flags &= ~SFLAG_CLIENT;
6934 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6935 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6936 surface->Flags |= SFLAG_NONPOW2;
6937 } else {
6938 surface->Flags &= ~SFLAG_NONPOW2;
6940 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6941 surface->resource.allocatedMemory = NULL;
6942 surface->resource.heapMemory = NULL;
6943 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6944 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6945 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6946 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6947 } else {
6948 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6952 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6953 TRACE("Unloading resource %p\n", resource);
6954 IWineD3DResource_UnLoad(resource);
6955 IWineD3DResource_Release(resource);
6956 return S_OK;
6959 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
6960 UINT i, count;
6961 WINED3DDISPLAYMODE m;
6962 HRESULT hr;
6964 /* All Windowed modes are supported, as is leaving the current mode */
6965 if(pp->Windowed) return TRUE;
6966 if(!pp->BackBufferWidth) return TRUE;
6967 if(!pp->BackBufferHeight) return TRUE;
6969 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6970 for(i = 0; i < count; i++) {
6971 memset(&m, 0, sizeof(m));
6972 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6973 if(FAILED(hr)) {
6974 ERR("EnumAdapterModes failed\n");
6976 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6977 /* Mode found, it is supported */
6978 return TRUE;
6981 /* Mode not found -> not supported */
6982 return FALSE;
6985 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6987 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6988 UINT i;
6989 IWineD3DBaseShaderImpl *shader;
6991 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6992 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6993 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6996 ENTER_GL();
6997 if(This->depth_blt_texture) {
6998 glDeleteTextures(1, &This->depth_blt_texture);
6999 This->depth_blt_texture = 0;
7001 if (This->depth_blt_rb) {
7002 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7003 This->depth_blt_rb = 0;
7004 This->depth_blt_rb_w = 0;
7005 This->depth_blt_rb_h = 0;
7007 This->blitter->free_private(iface);
7008 This->frag_pipe->free_private(iface);
7009 This->shader_backend->shader_free_private(iface);
7011 for (i = 0; i < GL_LIMITS(textures); i++) {
7012 /* Textures are recreated below */
7013 glDeleteTextures(1, &This->dummyTextureName[i]);
7014 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7015 This->dummyTextureName[i] = 0;
7017 LEAVE_GL();
7019 while(This->numContexts) {
7020 DestroyContext(This, This->contexts[0]);
7022 This->activeContext = NULL;
7023 HeapFree(GetProcessHeap(), 0, swapchain->context);
7024 swapchain->context = NULL;
7025 swapchain->num_contexts = 0;
7028 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7030 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7031 HRESULT hr;
7032 IWineD3DSurfaceImpl *target;
7034 /* Recreate the primary swapchain's context */
7035 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7036 if(swapchain->backBuffer) {
7037 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7038 } else {
7039 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7041 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7042 &swapchain->presentParms);
7043 swapchain->num_contexts = 1;
7044 This->activeContext = swapchain->context[0];
7046 create_dummy_textures(This);
7048 hr = This->shader_backend->shader_alloc_private(iface);
7049 if(FAILED(hr)) {
7050 ERR("Failed to recreate shader private data\n");
7051 goto err_out;
7053 hr = This->frag_pipe->alloc_private(iface);
7054 if(FAILED(hr)) {
7055 TRACE("Fragment pipeline private data couldn't be allocated\n");
7056 goto err_out;
7058 hr = This->blitter->alloc_private(iface);
7059 if(FAILED(hr)) {
7060 TRACE("Blitter private data couldn't be allocated\n");
7061 goto err_out;
7064 return WINED3D_OK;
7066 err_out:
7067 This->blitter->free_private(iface);
7068 This->frag_pipe->free_private(iface);
7069 This->shader_backend->shader_free_private(iface);
7070 return hr;
7073 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7075 IWineD3DSwapChainImpl *swapchain;
7076 HRESULT hr;
7077 BOOL DisplayModeChanged = FALSE;
7078 WINED3DDISPLAYMODE mode;
7079 TRACE("(%p)\n", This);
7081 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7082 if(FAILED(hr)) {
7083 ERR("Failed to get the first implicit swapchain\n");
7084 return hr;
7087 if(!is_display_mode_supported(This, pPresentationParameters)) {
7088 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7089 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7090 pPresentationParameters->BackBufferHeight);
7091 return WINED3DERR_INVALIDCALL;
7094 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7095 * on an existing gl context, so there's no real need for recreation.
7097 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7099 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7101 TRACE("New params:\n");
7102 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7103 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7104 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7105 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7106 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7107 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7108 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7109 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7110 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7111 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7112 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7113 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7114 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7116 /* No special treatment of these parameters. Just store them */
7117 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7118 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7119 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7120 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7122 /* What to do about these? */
7123 if(pPresentationParameters->BackBufferCount != 0 &&
7124 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7125 ERR("Cannot change the back buffer count yet\n");
7127 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7128 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7129 ERR("Cannot change the back buffer format yet\n");
7131 if(pPresentationParameters->hDeviceWindow != NULL &&
7132 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7133 ERR("Cannot change the device window yet\n");
7135 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7136 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7137 return WINED3DERR_INVALIDCALL;
7140 /* Reset the depth stencil */
7141 if (pPresentationParameters->EnableAutoDepthStencil)
7142 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7143 else
7144 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7146 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7148 if(pPresentationParameters->Windowed) {
7149 mode.Width = swapchain->orig_width;
7150 mode.Height = swapchain->orig_height;
7151 mode.RefreshRate = 0;
7152 mode.Format = swapchain->presentParms.BackBufferFormat;
7153 } else {
7154 mode.Width = pPresentationParameters->BackBufferWidth;
7155 mode.Height = pPresentationParameters->BackBufferHeight;
7156 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7157 mode.Format = swapchain->presentParms.BackBufferFormat;
7160 /* Should Width == 800 && Height == 0 set 800x600? */
7161 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7162 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7163 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7165 WINED3DVIEWPORT vp;
7166 int i;
7168 vp.X = 0;
7169 vp.Y = 0;
7170 vp.Width = pPresentationParameters->BackBufferWidth;
7171 vp.Height = pPresentationParameters->BackBufferHeight;
7172 vp.MinZ = 0;
7173 vp.MaxZ = 1;
7175 if(!pPresentationParameters->Windowed) {
7176 DisplayModeChanged = TRUE;
7178 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7179 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7181 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7182 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7183 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7185 if(This->auto_depth_stencil_buffer) {
7186 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7190 /* Now set the new viewport */
7191 IWineD3DDevice_SetViewport(iface, &vp);
7194 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7195 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7196 DisplayModeChanged) {
7198 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7200 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7201 if(swapchain->presentParms.Windowed) {
7202 /* switch from windowed to fs */
7203 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7204 pPresentationParameters->BackBufferWidth,
7205 pPresentationParameters->BackBufferHeight);
7206 } else {
7207 /* Fullscreen -> fullscreen mode change */
7208 MoveWindow(swapchain->win_handle, 0, 0,
7209 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7210 TRUE);
7212 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7213 /* Fullscreen -> windowed switch */
7214 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7216 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7217 } else if(!pPresentationParameters->Windowed) {
7218 DWORD style = This->style, exStyle = This->exStyle;
7219 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7220 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7221 * Reset to clear up their mess. Guild Wars also loses the device during that.
7223 This->style = 0;
7224 This->exStyle = 0;
7225 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7226 pPresentationParameters->BackBufferWidth,
7227 pPresentationParameters->BackBufferHeight);
7228 This->style = style;
7229 This->exStyle = exStyle;
7232 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7233 if(FAILED(hr)) {
7234 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7237 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7238 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7240 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7241 * first use
7243 return hr;
7246 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7248 /** FIXME: always true at the moment **/
7249 if(!bEnableDialogs) {
7250 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7252 return WINED3D_OK;
7256 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7258 TRACE("(%p) : pParameters %p\n", This, pParameters);
7260 *pParameters = This->createParms;
7261 return WINED3D_OK;
7264 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7265 IWineD3DSwapChain *swapchain;
7267 TRACE("Relaying to swapchain\n");
7269 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7270 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7271 IWineD3DSwapChain_Release(swapchain);
7273 return;
7276 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7277 IWineD3DSwapChain *swapchain;
7279 TRACE("Relaying to swapchain\n");
7281 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7282 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7283 IWineD3DSwapChain_Release(swapchain);
7285 return;
7289 /** ********************************************************
7290 * Notification functions
7291 ** ********************************************************/
7292 /** This function must be called in the release of a resource when ref == 0,
7293 * the contents of resource must still be correct,
7294 * any handles to other resource held by the caller must be closed
7295 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7296 *****************************************************/
7297 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7300 TRACE("(%p) : Adding Resource %p\n", This, resource);
7301 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7304 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7307 TRACE("(%p) : Removing resource %p\n", This, resource);
7309 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7313 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7315 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7316 int counter;
7318 TRACE("(%p) : resource %p\n", This, resource);
7320 context_resource_released(iface, resource, type);
7322 switch (type) {
7323 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7324 case WINED3DRTYPE_SURFACE: {
7325 unsigned int i;
7327 /* Cleanup any FBO attachments if d3d is enabled */
7328 if(This->d3d_initialized) {
7329 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7330 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7332 TRACE("Last active render target destroyed\n");
7333 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7334 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7335 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7336 * and the lastActiveRenderTarget member shouldn't matter
7338 if(swapchain) {
7339 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7340 TRACE("Activating primary back buffer\n");
7341 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7342 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7343 /* Single buffering environment */
7344 TRACE("Activating primary front buffer\n");
7345 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7346 } else {
7347 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7348 /* Implicit render target destroyed, that means the device is being destroyed
7349 * whatever we set here, it shouldn't matter
7351 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7353 } else {
7354 /* May happen during ddraw uninitialization */
7355 TRACE("Render target set, but swapchain does not exist!\n");
7356 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7360 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7361 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7362 This->render_targets[i] = NULL;
7365 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7366 This->stencilBufferTarget = NULL;
7370 break;
7372 case WINED3DRTYPE_TEXTURE:
7373 case WINED3DRTYPE_CUBETEXTURE:
7374 case WINED3DRTYPE_VOLUMETEXTURE:
7375 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7376 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7377 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7378 This->stateBlock->textures[counter] = NULL;
7380 if (This->updateStateBlock != This->stateBlock ){
7381 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7382 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7383 This->updateStateBlock->textures[counter] = NULL;
7387 break;
7388 case WINED3DRTYPE_VOLUME:
7389 /* TODO: nothing really? */
7390 break;
7391 case WINED3DRTYPE_VERTEXBUFFER:
7392 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7394 int streamNumber;
7395 TRACE("Cleaning up stream pointers\n");
7397 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7398 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7399 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7401 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7402 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7403 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7404 This->updateStateBlock->streamSource[streamNumber] = 0;
7405 /* Set changed flag? */
7408 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) */
7409 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7410 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7411 This->stateBlock->streamSource[streamNumber] = 0;
7416 break;
7417 case WINED3DRTYPE_INDEXBUFFER:
7418 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7419 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7420 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7421 This->updateStateBlock->pIndexData = NULL;
7424 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7425 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7426 This->stateBlock->pIndexData = NULL;
7430 break;
7431 default:
7432 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7433 break;
7437 /* Remove the resource from the resourceStore */
7438 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7440 TRACE("Resource released\n");
7444 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7446 IWineD3DResourceImpl *resource, *cursor;
7447 HRESULT ret;
7448 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7450 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7451 TRACE("enumerating resource %p\n", resource);
7452 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7453 ret = pCallback((IWineD3DResource *) resource, pData);
7454 if(ret == S_FALSE) {
7455 TRACE("Canceling enumeration\n");
7456 break;
7459 return WINED3D_OK;
7462 /**********************************************************
7463 * IWineD3DDevice VTbl follows
7464 **********************************************************/
7466 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7468 /*** IUnknown methods ***/
7469 IWineD3DDeviceImpl_QueryInterface,
7470 IWineD3DDeviceImpl_AddRef,
7471 IWineD3DDeviceImpl_Release,
7472 /*** IWineD3DDevice methods ***/
7473 IWineD3DDeviceImpl_GetParent,
7474 /*** Creation methods**/
7475 IWineD3DDeviceImpl_CreateVertexBuffer,
7476 IWineD3DDeviceImpl_CreateIndexBuffer,
7477 IWineD3DDeviceImpl_CreateStateBlock,
7478 IWineD3DDeviceImpl_CreateSurface,
7479 IWineD3DDeviceImpl_CreateTexture,
7480 IWineD3DDeviceImpl_CreateVolumeTexture,
7481 IWineD3DDeviceImpl_CreateVolume,
7482 IWineD3DDeviceImpl_CreateCubeTexture,
7483 IWineD3DDeviceImpl_CreateQuery,
7484 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7485 IWineD3DDeviceImpl_CreateVertexDeclaration,
7486 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7487 IWineD3DDeviceImpl_CreateVertexShader,
7488 IWineD3DDeviceImpl_CreatePixelShader,
7489 IWineD3DDeviceImpl_CreatePalette,
7490 /*** Odd functions **/
7491 IWineD3DDeviceImpl_Init3D,
7492 IWineD3DDeviceImpl_InitGDI,
7493 IWineD3DDeviceImpl_Uninit3D,
7494 IWineD3DDeviceImpl_UninitGDI,
7495 IWineD3DDeviceImpl_SetMultithreaded,
7496 IWineD3DDeviceImpl_EvictManagedResources,
7497 IWineD3DDeviceImpl_GetAvailableTextureMem,
7498 IWineD3DDeviceImpl_GetBackBuffer,
7499 IWineD3DDeviceImpl_GetCreationParameters,
7500 IWineD3DDeviceImpl_GetDeviceCaps,
7501 IWineD3DDeviceImpl_GetDirect3D,
7502 IWineD3DDeviceImpl_GetDisplayMode,
7503 IWineD3DDeviceImpl_SetDisplayMode,
7504 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7505 IWineD3DDeviceImpl_GetRasterStatus,
7506 IWineD3DDeviceImpl_GetSwapChain,
7507 IWineD3DDeviceImpl_Reset,
7508 IWineD3DDeviceImpl_SetDialogBoxMode,
7509 IWineD3DDeviceImpl_SetCursorProperties,
7510 IWineD3DDeviceImpl_SetCursorPosition,
7511 IWineD3DDeviceImpl_ShowCursor,
7512 IWineD3DDeviceImpl_TestCooperativeLevel,
7513 /*** Getters and setters **/
7514 IWineD3DDeviceImpl_SetClipPlane,
7515 IWineD3DDeviceImpl_GetClipPlane,
7516 IWineD3DDeviceImpl_SetClipStatus,
7517 IWineD3DDeviceImpl_GetClipStatus,
7518 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7519 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7520 IWineD3DDeviceImpl_SetDepthStencilSurface,
7521 IWineD3DDeviceImpl_GetDepthStencilSurface,
7522 IWineD3DDeviceImpl_SetFVF,
7523 IWineD3DDeviceImpl_GetFVF,
7524 IWineD3DDeviceImpl_SetGammaRamp,
7525 IWineD3DDeviceImpl_GetGammaRamp,
7526 IWineD3DDeviceImpl_SetIndices,
7527 IWineD3DDeviceImpl_GetIndices,
7528 IWineD3DDeviceImpl_SetBaseVertexIndex,
7529 IWineD3DDeviceImpl_GetBaseVertexIndex,
7530 IWineD3DDeviceImpl_SetLight,
7531 IWineD3DDeviceImpl_GetLight,
7532 IWineD3DDeviceImpl_SetLightEnable,
7533 IWineD3DDeviceImpl_GetLightEnable,
7534 IWineD3DDeviceImpl_SetMaterial,
7535 IWineD3DDeviceImpl_GetMaterial,
7536 IWineD3DDeviceImpl_SetNPatchMode,
7537 IWineD3DDeviceImpl_GetNPatchMode,
7538 IWineD3DDeviceImpl_SetPaletteEntries,
7539 IWineD3DDeviceImpl_GetPaletteEntries,
7540 IWineD3DDeviceImpl_SetPixelShader,
7541 IWineD3DDeviceImpl_GetPixelShader,
7542 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7543 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7544 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7545 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7546 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7547 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7548 IWineD3DDeviceImpl_SetRenderState,
7549 IWineD3DDeviceImpl_GetRenderState,
7550 IWineD3DDeviceImpl_SetRenderTarget,
7551 IWineD3DDeviceImpl_GetRenderTarget,
7552 IWineD3DDeviceImpl_SetFrontBackBuffers,
7553 IWineD3DDeviceImpl_SetSamplerState,
7554 IWineD3DDeviceImpl_GetSamplerState,
7555 IWineD3DDeviceImpl_SetScissorRect,
7556 IWineD3DDeviceImpl_GetScissorRect,
7557 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7558 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7559 IWineD3DDeviceImpl_SetStreamSource,
7560 IWineD3DDeviceImpl_GetStreamSource,
7561 IWineD3DDeviceImpl_SetStreamSourceFreq,
7562 IWineD3DDeviceImpl_GetStreamSourceFreq,
7563 IWineD3DDeviceImpl_SetTexture,
7564 IWineD3DDeviceImpl_GetTexture,
7565 IWineD3DDeviceImpl_SetTextureStageState,
7566 IWineD3DDeviceImpl_GetTextureStageState,
7567 IWineD3DDeviceImpl_SetTransform,
7568 IWineD3DDeviceImpl_GetTransform,
7569 IWineD3DDeviceImpl_SetVertexDeclaration,
7570 IWineD3DDeviceImpl_GetVertexDeclaration,
7571 IWineD3DDeviceImpl_SetVertexShader,
7572 IWineD3DDeviceImpl_GetVertexShader,
7573 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7574 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7575 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7576 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7577 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7578 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7579 IWineD3DDeviceImpl_SetViewport,
7580 IWineD3DDeviceImpl_GetViewport,
7581 IWineD3DDeviceImpl_MultiplyTransform,
7582 IWineD3DDeviceImpl_ValidateDevice,
7583 IWineD3DDeviceImpl_ProcessVertices,
7584 /*** State block ***/
7585 IWineD3DDeviceImpl_BeginStateBlock,
7586 IWineD3DDeviceImpl_EndStateBlock,
7587 /*** Scene management ***/
7588 IWineD3DDeviceImpl_BeginScene,
7589 IWineD3DDeviceImpl_EndScene,
7590 IWineD3DDeviceImpl_Present,
7591 IWineD3DDeviceImpl_Clear,
7592 /*** Drawing ***/
7593 IWineD3DDeviceImpl_DrawPrimitive,
7594 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7595 IWineD3DDeviceImpl_DrawPrimitiveUP,
7596 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7597 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7598 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7599 IWineD3DDeviceImpl_DrawRectPatch,
7600 IWineD3DDeviceImpl_DrawTriPatch,
7601 IWineD3DDeviceImpl_DeletePatch,
7602 IWineD3DDeviceImpl_ColorFill,
7603 IWineD3DDeviceImpl_UpdateTexture,
7604 IWineD3DDeviceImpl_UpdateSurface,
7605 IWineD3DDeviceImpl_GetFrontBufferData,
7606 /*** object tracking ***/
7607 IWineD3DDeviceImpl_ResourceReleased,
7608 IWineD3DDeviceImpl_EnumResources
7611 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7613 /*** IUnknown methods ***/
7614 IWineD3DDeviceImpl_QueryInterface,
7615 IWineD3DDeviceImpl_AddRef,
7616 IWineD3DDeviceImpl_Release,
7617 /*** IWineD3DDevice methods ***/
7618 IWineD3DDeviceImpl_GetParent,
7619 /*** Creation methods**/
7620 IWineD3DDeviceImpl_CreateVertexBuffer,
7621 IWineD3DDeviceImpl_CreateIndexBuffer,
7622 IWineD3DDeviceImpl_CreateStateBlock,
7623 IWineD3DDeviceImpl_CreateSurface,
7624 IWineD3DDeviceImpl_CreateTexture,
7625 IWineD3DDeviceImpl_CreateVolumeTexture,
7626 IWineD3DDeviceImpl_CreateVolume,
7627 IWineD3DDeviceImpl_CreateCubeTexture,
7628 IWineD3DDeviceImpl_CreateQuery,
7629 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7630 IWineD3DDeviceImpl_CreateVertexDeclaration,
7631 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7632 IWineD3DDeviceImpl_CreateVertexShader,
7633 IWineD3DDeviceImpl_CreatePixelShader,
7634 IWineD3DDeviceImpl_CreatePalette,
7635 /*** Odd functions **/
7636 IWineD3DDeviceImpl_Init3D,
7637 IWineD3DDeviceImpl_InitGDI,
7638 IWineD3DDeviceImpl_Uninit3D,
7639 IWineD3DDeviceImpl_UninitGDI,
7640 IWineD3DDeviceImpl_SetMultithreaded,
7641 IWineD3DDeviceImpl_EvictManagedResources,
7642 IWineD3DDeviceImpl_GetAvailableTextureMem,
7643 IWineD3DDeviceImpl_GetBackBuffer,
7644 IWineD3DDeviceImpl_GetCreationParameters,
7645 IWineD3DDeviceImpl_GetDeviceCaps,
7646 IWineD3DDeviceImpl_GetDirect3D,
7647 IWineD3DDeviceImpl_GetDisplayMode,
7648 IWineD3DDeviceImpl_SetDisplayMode,
7649 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7650 IWineD3DDeviceImpl_GetRasterStatus,
7651 IWineD3DDeviceImpl_GetSwapChain,
7652 IWineD3DDeviceImpl_Reset,
7653 IWineD3DDeviceImpl_SetDialogBoxMode,
7654 IWineD3DDeviceImpl_SetCursorProperties,
7655 IWineD3DDeviceImpl_SetCursorPosition,
7656 IWineD3DDeviceImpl_ShowCursor,
7657 IWineD3DDeviceImpl_TestCooperativeLevel,
7658 /*** Getters and setters **/
7659 IWineD3DDeviceImpl_SetClipPlane,
7660 IWineD3DDeviceImpl_GetClipPlane,
7661 IWineD3DDeviceImpl_SetClipStatus,
7662 IWineD3DDeviceImpl_GetClipStatus,
7663 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7664 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7665 IWineD3DDeviceImpl_SetDepthStencilSurface,
7666 IWineD3DDeviceImpl_GetDepthStencilSurface,
7667 IWineD3DDeviceImpl_SetFVF,
7668 IWineD3DDeviceImpl_GetFVF,
7669 IWineD3DDeviceImpl_SetGammaRamp,
7670 IWineD3DDeviceImpl_GetGammaRamp,
7671 IWineD3DDeviceImpl_SetIndices,
7672 IWineD3DDeviceImpl_GetIndices,
7673 IWineD3DDeviceImpl_SetBaseVertexIndex,
7674 IWineD3DDeviceImpl_GetBaseVertexIndex,
7675 IWineD3DDeviceImpl_SetLight,
7676 IWineD3DDeviceImpl_GetLight,
7677 IWineD3DDeviceImpl_SetLightEnable,
7678 IWineD3DDeviceImpl_GetLightEnable,
7679 IWineD3DDeviceImpl_SetMaterial,
7680 IWineD3DDeviceImpl_GetMaterial,
7681 IWineD3DDeviceImpl_SetNPatchMode,
7682 IWineD3DDeviceImpl_GetNPatchMode,
7683 IWineD3DDeviceImpl_SetPaletteEntries,
7684 IWineD3DDeviceImpl_GetPaletteEntries,
7685 IWineD3DDeviceImpl_SetPixelShader,
7686 IWineD3DDeviceImpl_GetPixelShader,
7687 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7688 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7689 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7690 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7691 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7692 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7693 IWineD3DDeviceImpl_SetRenderState,
7694 IWineD3DDeviceImpl_GetRenderState,
7695 IWineD3DDeviceImpl_SetRenderTarget,
7696 IWineD3DDeviceImpl_GetRenderTarget,
7697 IWineD3DDeviceImpl_SetFrontBackBuffers,
7698 IWineD3DDeviceImpl_SetSamplerState,
7699 IWineD3DDeviceImpl_GetSamplerState,
7700 IWineD3DDeviceImpl_SetScissorRect,
7701 IWineD3DDeviceImpl_GetScissorRect,
7702 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7703 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7704 IWineD3DDeviceImpl_SetStreamSource,
7705 IWineD3DDeviceImpl_GetStreamSource,
7706 IWineD3DDeviceImpl_SetStreamSourceFreq,
7707 IWineD3DDeviceImpl_GetStreamSourceFreq,
7708 IWineD3DDeviceImpl_SetTexture,
7709 IWineD3DDeviceImpl_GetTexture,
7710 IWineD3DDeviceImpl_SetTextureStageState,
7711 IWineD3DDeviceImpl_GetTextureStageState,
7712 IWineD3DDeviceImpl_SetTransform,
7713 IWineD3DDeviceImpl_GetTransform,
7714 IWineD3DDeviceImpl_SetVertexDeclaration,
7715 IWineD3DDeviceImpl_GetVertexDeclaration,
7716 IWineD3DDeviceImpl_SetVertexShader,
7717 IWineD3DDeviceImpl_GetVertexShader,
7718 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7719 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7720 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7721 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7722 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7723 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7724 IWineD3DDeviceImpl_SetViewport,
7725 IWineD3DDeviceImpl_GetViewport,
7726 IWineD3DDeviceImpl_MultiplyTransform,
7727 IWineD3DDeviceImpl_ValidateDevice,
7728 IWineD3DDeviceImpl_ProcessVertices,
7729 /*** State block ***/
7730 IWineD3DDeviceImpl_BeginStateBlock,
7731 IWineD3DDeviceImpl_EndStateBlock,
7732 /*** Scene management ***/
7733 IWineD3DDeviceImpl_BeginScene,
7734 IWineD3DDeviceImpl_EndScene,
7735 IWineD3DDeviceImpl_Present,
7736 IWineD3DDeviceImpl_Clear,
7737 /*** Drawing ***/
7738 IWineD3DDeviceImpl_DrawPrimitive,
7739 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7740 IWineD3DDeviceImpl_DrawPrimitiveUP,
7741 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7742 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7743 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7744 IWineD3DDeviceImpl_DrawRectPatch,
7745 IWineD3DDeviceImpl_DrawTriPatch,
7746 IWineD3DDeviceImpl_DeletePatch,
7747 IWineD3DDeviceImpl_ColorFill,
7748 IWineD3DDeviceImpl_UpdateTexture,
7749 IWineD3DDeviceImpl_UpdateSurface,
7750 IWineD3DDeviceImpl_GetFrontBufferData,
7751 /*** object tracking ***/
7752 IWineD3DDeviceImpl_ResourceReleased,
7753 IWineD3DDeviceImpl_EnumResources
7756 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7757 WINED3DRS_ALPHABLENDENABLE ,
7758 WINED3DRS_ALPHAFUNC ,
7759 WINED3DRS_ALPHAREF ,
7760 WINED3DRS_ALPHATESTENABLE ,
7761 WINED3DRS_BLENDOP ,
7762 WINED3DRS_COLORWRITEENABLE ,
7763 WINED3DRS_DESTBLEND ,
7764 WINED3DRS_DITHERENABLE ,
7765 WINED3DRS_FILLMODE ,
7766 WINED3DRS_FOGDENSITY ,
7767 WINED3DRS_FOGEND ,
7768 WINED3DRS_FOGSTART ,
7769 WINED3DRS_LASTPIXEL ,
7770 WINED3DRS_SHADEMODE ,
7771 WINED3DRS_SRCBLEND ,
7772 WINED3DRS_STENCILENABLE ,
7773 WINED3DRS_STENCILFAIL ,
7774 WINED3DRS_STENCILFUNC ,
7775 WINED3DRS_STENCILMASK ,
7776 WINED3DRS_STENCILPASS ,
7777 WINED3DRS_STENCILREF ,
7778 WINED3DRS_STENCILWRITEMASK ,
7779 WINED3DRS_STENCILZFAIL ,
7780 WINED3DRS_TEXTUREFACTOR ,
7781 WINED3DRS_WRAP0 ,
7782 WINED3DRS_WRAP1 ,
7783 WINED3DRS_WRAP2 ,
7784 WINED3DRS_WRAP3 ,
7785 WINED3DRS_WRAP4 ,
7786 WINED3DRS_WRAP5 ,
7787 WINED3DRS_WRAP6 ,
7788 WINED3DRS_WRAP7 ,
7789 WINED3DRS_ZENABLE ,
7790 WINED3DRS_ZFUNC ,
7791 WINED3DRS_ZWRITEENABLE
7794 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7795 WINED3DTSS_ADDRESSW ,
7796 WINED3DTSS_ALPHAARG0 ,
7797 WINED3DTSS_ALPHAARG1 ,
7798 WINED3DTSS_ALPHAARG2 ,
7799 WINED3DTSS_ALPHAOP ,
7800 WINED3DTSS_BUMPENVLOFFSET ,
7801 WINED3DTSS_BUMPENVLSCALE ,
7802 WINED3DTSS_BUMPENVMAT00 ,
7803 WINED3DTSS_BUMPENVMAT01 ,
7804 WINED3DTSS_BUMPENVMAT10 ,
7805 WINED3DTSS_BUMPENVMAT11 ,
7806 WINED3DTSS_COLORARG0 ,
7807 WINED3DTSS_COLORARG1 ,
7808 WINED3DTSS_COLORARG2 ,
7809 WINED3DTSS_COLOROP ,
7810 WINED3DTSS_RESULTARG ,
7811 WINED3DTSS_TEXCOORDINDEX ,
7812 WINED3DTSS_TEXTURETRANSFORMFLAGS
7815 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7816 WINED3DSAMP_ADDRESSU ,
7817 WINED3DSAMP_ADDRESSV ,
7818 WINED3DSAMP_ADDRESSW ,
7819 WINED3DSAMP_BORDERCOLOR ,
7820 WINED3DSAMP_MAGFILTER ,
7821 WINED3DSAMP_MINFILTER ,
7822 WINED3DSAMP_MIPFILTER ,
7823 WINED3DSAMP_MIPMAPLODBIAS ,
7824 WINED3DSAMP_MAXMIPLEVEL ,
7825 WINED3DSAMP_MAXANISOTROPY ,
7826 WINED3DSAMP_SRGBTEXTURE ,
7827 WINED3DSAMP_ELEMENTINDEX
7830 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7831 WINED3DRS_AMBIENT ,
7832 WINED3DRS_AMBIENTMATERIALSOURCE ,
7833 WINED3DRS_CLIPPING ,
7834 WINED3DRS_CLIPPLANEENABLE ,
7835 WINED3DRS_COLORVERTEX ,
7836 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7837 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7838 WINED3DRS_FOGDENSITY ,
7839 WINED3DRS_FOGEND ,
7840 WINED3DRS_FOGSTART ,
7841 WINED3DRS_FOGTABLEMODE ,
7842 WINED3DRS_FOGVERTEXMODE ,
7843 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7844 WINED3DRS_LIGHTING ,
7845 WINED3DRS_LOCALVIEWER ,
7846 WINED3DRS_MULTISAMPLEANTIALIAS ,
7847 WINED3DRS_MULTISAMPLEMASK ,
7848 WINED3DRS_NORMALIZENORMALS ,
7849 WINED3DRS_PATCHEDGESTYLE ,
7850 WINED3DRS_POINTSCALE_A ,
7851 WINED3DRS_POINTSCALE_B ,
7852 WINED3DRS_POINTSCALE_C ,
7853 WINED3DRS_POINTSCALEENABLE ,
7854 WINED3DRS_POINTSIZE ,
7855 WINED3DRS_POINTSIZE_MAX ,
7856 WINED3DRS_POINTSIZE_MIN ,
7857 WINED3DRS_POINTSPRITEENABLE ,
7858 WINED3DRS_RANGEFOGENABLE ,
7859 WINED3DRS_SPECULARMATERIALSOURCE ,
7860 WINED3DRS_TWEENFACTOR ,
7861 WINED3DRS_VERTEXBLEND ,
7862 WINED3DRS_CULLMODE ,
7863 WINED3DRS_FOGCOLOR
7866 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7867 WINED3DTSS_TEXCOORDINDEX ,
7868 WINED3DTSS_TEXTURETRANSFORMFLAGS
7871 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7872 WINED3DSAMP_DMAPOFFSET
7875 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7876 DWORD rep = This->StateTable[state].representative;
7877 DWORD idx;
7878 BYTE shift;
7879 UINT i;
7880 WineD3DContext *context;
7882 if(!rep) return;
7883 for(i = 0; i < This->numContexts; i++) {
7884 context = This->contexts[i];
7885 if(isStateDirty(context, rep)) continue;
7887 context->dirtyArray[context->numDirtyEntries++] = rep;
7888 idx = rep >> 5;
7889 shift = rep & 0x1f;
7890 context->isStateDirty[idx] |= (1 << shift);
7894 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7895 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7896 /* The drawable size of a pbuffer render target is the current pbuffer size
7898 *width = dev->pbufferWidth;
7899 *height = dev->pbufferHeight;
7902 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7903 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7905 *width = This->pow2Width;
7906 *height = This->pow2Height;
7909 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7910 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7911 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7912 * current context's drawable, which is the size of the back buffer of the swapchain
7913 * the active context belongs to. The back buffer of the swapchain is stored as the
7914 * surface the context belongs to.
7916 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7917 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;