wined3d: Move texture -> drawable blits to LoadLocation.
[wine/multimedia.git] / dlls / wined3d / device.c
blob2f957ae75b0c844f39bb4f533025761fede4d7fd
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-2007 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
66 object->ref = 1; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->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.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
105 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
108 *pp##type = NULL; \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 *pp##type = (IWineD3D##type *) object; \
112 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
113 TRACE("(%p) : Created resource %p\n", This, object); \
116 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
117 _basetexture.levels = Levels; \
118 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
119 _basetexture.LOD = 0; \
120 _basetexture.dirty = TRUE; \
121 _basetexture.is_srgb = FALSE; \
122 _basetexture.srgb_mode_change_count = 0; \
125 /**********************************************************
126 * Global variable / Constants follow
127 **********************************************************/
128 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
130 /**********************************************************
131 * IUnknown parts follows
132 **********************************************************/
134 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
138 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
139 if (IsEqualGUID(riid, &IID_IUnknown)
140 || IsEqualGUID(riid, &IID_IWineD3DBase)
141 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
142 IUnknown_AddRef(iface);
143 *ppobj = This;
144 return S_OK;
146 *ppobj = NULL;
147 return E_NOINTERFACE;
150 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
152 ULONG refCount = InterlockedIncrement(&This->ref);
154 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
155 return refCount;
158 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
160 ULONG refCount = InterlockedDecrement(&This->ref);
162 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
164 if (!refCount) {
165 if (This->fbo) {
166 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
168 if (This->src_fbo) {
169 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
171 if (This->dst_fbo) {
172 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
175 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
177 /* TODO: Clean up all the surfaces and textures! */
178 /* NOTE: You must release the parent if the object was created via a callback
179 ** ***************************/
181 if (This->resources != NULL ) {
182 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
183 dumpResources(This->resources);
186 if(This->contexts) ERR("Context array not freed!\n");
187 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
188 This->haveHardwareCursor = FALSE;
190 IWineD3D_Release(This->wineD3D);
191 This->wineD3D = NULL;
192 HeapFree(GetProcessHeap(), 0, This);
193 TRACE("Freed device %p\n", This);
194 This = NULL;
196 return refCount;
199 /**********************************************************
200 * IWineD3DDevice implementation follows
201 **********************************************************/
202 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
204 *pParent = This->parent;
205 IUnknown_AddRef(This->parent);
206 return WINED3D_OK;
209 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
210 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
211 GLenum error, glUsage;
212 DWORD vboUsage = object->resource.usage;
213 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
214 WARN("Creating a vbo failed once, not trying again\n");
215 return;
218 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
220 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
221 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
222 ENTER_GL();
224 /* Make sure that the gl error is cleared. Do not use checkGLcall
225 * here because checkGLcall just prints a fixme and continues. However,
226 * if an error during VBO creation occurs we can fall back to non-vbo operation
227 * with full functionality(but performance loss)
229 while(glGetError() != GL_NO_ERROR);
231 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
232 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
233 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
234 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
235 * to check if the rhw and color values are in the correct format.
238 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
239 error = glGetError();
240 if(object->vbo == 0 || error != GL_NO_ERROR) {
241 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
242 goto error;
245 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
246 error = glGetError();
247 if(error != GL_NO_ERROR) {
248 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
249 goto error;
252 /* Don't use static, because dx apps tend to update the buffer
253 * quite often even if they specify 0 usage. Because we always keep the local copy
254 * we never read from the vbo and can create a write only opengl buffer.
256 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
257 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
258 case WINED3DUSAGE_DYNAMIC:
259 TRACE("Gl usage = GL_STREAM_DRAW\n");
260 glUsage = GL_STREAM_DRAW_ARB;
261 break;
262 case WINED3DUSAGE_WRITEONLY:
263 default:
264 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
265 glUsage = GL_DYNAMIC_DRAW_ARB;
266 break;
269 /* Reserve memory for the buffer. The amount of data won't change
270 * so we are safe with calling glBufferData once with a NULL ptr and
271 * calling glBufferSubData on updates
273 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
274 error = glGetError();
275 if(error != GL_NO_ERROR) {
276 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
277 goto error;
280 LEAVE_GL();
282 return;
283 error:
284 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
285 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
286 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
287 object->vbo = 0;
288 object->Flags |= VBFLAG_VBOCREATEFAIL;
289 LEAVE_GL();
290 return;
293 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
294 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
295 IUnknown *parent) {
296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
297 IWineD3DVertexBufferImpl *object;
298 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
299 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
300 BOOL conv;
302 if(Size == 0) {
303 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
304 *ppVertexBuffer = NULL;
305 return WINED3DERR_INVALIDCALL;
308 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
310 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
311 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
313 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
314 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
316 object->fvf = FVF;
318 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
319 * drawStridedFast (half-life 2).
321 * Basically converting the vertices in the buffer is quite expensive, and observations
322 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
323 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
325 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
326 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
327 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
328 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
329 * dx7 apps.
330 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
331 * more. In this call we can convert dx7 buffers too.
333 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
334 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
335 (dxVersion > 7 || !conv) ) {
336 CreateVBO(object);
338 return WINED3D_OK;
341 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
342 GLenum error, glUsage;
343 TRACE("Creating VBO for Index Buffer %p\n", object);
345 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
346 * restored on the next draw
348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
350 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
351 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
352 ENTER_GL();
354 while(glGetError());
356 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
357 error = glGetError();
358 if(error != GL_NO_ERROR || object->vbo == 0) {
359 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
360 goto out;
363 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
364 error = glGetError();
365 if(error != GL_NO_ERROR) {
366 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
367 goto out;
370 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
371 * copy no readback will be needed
373 glUsage = GL_STATIC_DRAW_ARB;
374 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
375 error = glGetError();
376 if(error != GL_NO_ERROR) {
377 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
378 goto out;
380 LEAVE_GL();
381 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
382 return;
384 out:
385 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
386 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
387 LEAVE_GL();
388 object->vbo = 0;
391 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
392 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
393 HANDLE *sharedHandle, IUnknown *parent) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 IWineD3DIndexBufferImpl *object;
396 TRACE("(%p) Creating index buffer\n", This);
398 /* Allocate the storage for the device */
399 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
401 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
402 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
405 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
406 CreateIndexBufferVBO(This, object);
409 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
410 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
411 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
413 return WINED3D_OK;
416 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
419 IWineD3DStateBlockImpl *object;
420 int i, j;
421 HRESULT temp_result;
423 D3DCREATEOBJECTINSTANCE(object, StateBlock)
424 object->blockType = Type;
426 for(i = 0; i < LIGHTMAP_SIZE; i++) {
427 list_init(&object->lightMap[i]);
430 /* Special case - Used during initialization to produce a placeholder stateblock
431 so other functions called can update a state block */
432 if (Type == WINED3DSBT_INIT) {
433 /* Don't bother increasing the reference count otherwise a device will never
434 be freed due to circular dependencies */
435 return WINED3D_OK;
438 temp_result = allocate_shader_constants(object);
439 if (WINED3D_OK != temp_result)
440 return temp_result;
442 /* Otherwise, might as well set the whole state block to the appropriate values */
443 if (This->stateBlock != NULL)
444 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
445 else
446 memset(object->streamFreq, 1, sizeof(object->streamFreq));
448 /* Reset the ref and type after kludging it */
449 object->wineD3DDevice = This;
450 object->ref = 1;
451 object->blockType = Type;
453 TRACE("Updating changed flags appropriate for type %d\n", Type);
455 if (Type == WINED3DSBT_ALL) {
457 TRACE("ALL => Pretend everything has changed\n");
458 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
460 /* Lights are not part of the changed / set structure */
461 for(j = 0; j < LIGHTMAP_SIZE; j++) {
462 struct list *e;
463 LIST_FOR_EACH(e, &object->lightMap[j]) {
464 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
465 light->changed = TRUE;
466 light->enabledChanged = TRUE;
469 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
470 object->contained_render_states[j - 1] = j;
472 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
473 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
474 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
475 object->contained_transform_states[j - 1] = j;
477 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
478 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
479 object->contained_vs_consts_f[j] = j;
481 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
482 for(j = 0; j < MAX_CONST_I; j++) {
483 object->contained_vs_consts_i[j] = j;
485 object->num_contained_vs_consts_i = MAX_CONST_I;
486 for(j = 0; j < MAX_CONST_B; j++) {
487 object->contained_vs_consts_b[j] = j;
489 object->num_contained_vs_consts_b = MAX_CONST_B;
490 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
491 object->contained_ps_consts_f[j] = j;
493 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
494 for(j = 0; j < MAX_CONST_I; j++) {
495 object->contained_ps_consts_i[j] = j;
497 object->num_contained_ps_consts_i = MAX_CONST_I;
498 for(j = 0; j < MAX_CONST_B; j++) {
499 object->contained_ps_consts_b[j] = j;
501 object->num_contained_ps_consts_b = MAX_CONST_B;
502 for(i = 0; i < MAX_TEXTURES; i++) {
503 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
504 object->contained_tss_states[object->num_contained_tss_states].stage = i;
505 object->contained_tss_states[object->num_contained_tss_states].state = j;
506 object->num_contained_tss_states++;
509 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
510 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
511 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
512 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
513 object->num_contained_sampler_states++;
517 for(i = 0; i < MAX_STREAMS; i++) {
518 if(object->streamSource[i]) {
519 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
522 if(object->pIndexData) {
523 IWineD3DIndexBuffer_AddRef(object->pIndexData);
525 if(object->vertexShader) {
526 IWineD3DVertexShader_AddRef(object->vertexShader);
528 if(object->pixelShader) {
529 IWineD3DPixelShader_AddRef(object->pixelShader);
532 } else if (Type == WINED3DSBT_PIXELSTATE) {
534 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
535 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
537 object->changed.pixelShader = TRUE;
539 /* Pixel Shader Constants */
540 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
541 object->contained_ps_consts_f[i] = i;
542 object->changed.pixelShaderConstantsF[i] = TRUE;
544 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
545 for (i = 0; i < MAX_CONST_B; ++i) {
546 object->contained_ps_consts_b[i] = i;
547 object->changed.pixelShaderConstantsB[i] = TRUE;
549 object->num_contained_ps_consts_b = MAX_CONST_B;
550 for (i = 0; i < MAX_CONST_I; ++i) {
551 object->contained_ps_consts_i[i] = i;
552 object->changed.pixelShaderConstantsI[i] = TRUE;
554 object->num_contained_ps_consts_i = MAX_CONST_I;
556 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
557 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
558 object->contained_render_states[i] = SavedPixelStates_R[i];
560 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
561 for (j = 0; j < MAX_TEXTURES; j++) {
562 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
563 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
564 object->contained_tss_states[object->num_contained_tss_states].stage = j;
565 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
566 object->num_contained_tss_states++;
569 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
570 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
571 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
572 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
573 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
574 object->num_contained_sampler_states++;
577 if(object->pixelShader) {
578 IWineD3DPixelShader_AddRef(object->pixelShader);
581 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
582 * on them. This makes releasing the buffer easier
584 for(i = 0; i < MAX_STREAMS; i++) {
585 object->streamSource[i] = NULL;
587 object->pIndexData = NULL;
588 object->vertexShader = NULL;
590 } else if (Type == WINED3DSBT_VERTEXSTATE) {
592 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
593 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
595 object->changed.vertexShader = TRUE;
597 /* Vertex Shader Constants */
598 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
599 object->changed.vertexShaderConstantsF[i] = TRUE;
600 object->contained_vs_consts_f[i] = i;
602 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
603 for (i = 0; i < MAX_CONST_B; ++i) {
604 object->changed.vertexShaderConstantsB[i] = TRUE;
605 object->contained_vs_consts_b[i] = i;
607 object->num_contained_vs_consts_b = MAX_CONST_B;
608 for (i = 0; i < MAX_CONST_I; ++i) {
609 object->changed.vertexShaderConstantsI[i] = TRUE;
610 object->contained_vs_consts_i[i] = i;
612 object->num_contained_vs_consts_i = MAX_CONST_I;
613 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
614 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
615 object->contained_render_states[i] = SavedVertexStates_R[i];
617 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
618 for (j = 0; j < MAX_TEXTURES; j++) {
619 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
620 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
621 object->contained_tss_states[object->num_contained_tss_states].stage = j;
622 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
623 object->num_contained_tss_states++;
626 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
627 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
628 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
629 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
630 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
631 object->num_contained_sampler_states++;
635 for(j = 0; j < LIGHTMAP_SIZE; j++) {
636 struct list *e;
637 LIST_FOR_EACH(e, &object->lightMap[j]) {
638 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
639 light->changed = TRUE;
640 light->enabledChanged = TRUE;
644 for(i = 0; i < MAX_STREAMS; i++) {
645 if(object->streamSource[i]) {
646 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
649 if(object->vertexShader) {
650 IWineD3DVertexShader_AddRef(object->vertexShader);
652 object->pIndexData = NULL;
653 object->pixelShader = NULL;
654 } else {
655 FIXME("Unrecognized state block type %d\n", Type);
658 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
659 return WINED3D_OK;
662 /* ************************************
663 MSDN:
664 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
666 Discard
667 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
669 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.
671 ******************************** */
673 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) {
674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
675 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
676 unsigned int Size = 1;
677 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
678 TRACE("(%p) Create surface\n",This);
680 /** FIXME: Check ranges on the inputs are valid
681 * MSDN
682 * MultisampleQuality
683 * [in] Quality level. The valid range is between zero and one less than the level
684 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
685 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
686 * values of paired render targets, depth stencil surfaces, and the MultiSample type
687 * must all match.
688 *******************************/
692 * TODO: Discard MSDN
693 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
695 * If this flag is set, the contents of the depth stencil buffer will be
696 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
697 * with a different depth surface.
699 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
700 ***************************/
702 if(MultisampleQuality < 0) {
703 FIXME("Invalid multisample level %d\n", MultisampleQuality);
704 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
707 if(MultisampleQuality > 0) {
708 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
709 MultisampleQuality=0;
712 /** FIXME: Check that the format is supported
713 * by the device.
714 *******************************/
716 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
717 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
718 * space!
719 *********************************/
720 if (WINED3DFMT_UNKNOWN == Format) {
721 Size = 0;
722 } else if (Format == WINED3DFMT_DXT1) {
723 /* DXT1 is half byte per pixel */
724 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
726 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
727 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
728 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
729 } else {
730 /* The pitch is a multiple of 4 bytes */
731 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
732 Size *= Height;
735 /** Create and initialise the surface resource **/
736 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
737 /* "Standalone" surface */
738 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
740 object->currentDesc.Width = Width;
741 object->currentDesc.Height = Height;
742 object->currentDesc.MultiSampleType = MultiSample;
743 object->currentDesc.MultiSampleQuality = MultisampleQuality;
744 object->glDescription.level = Level;
746 /* Flags */
747 object->Flags = 0;
748 object->Flags |= Discard ? SFLAG_DISCARD : 0;
749 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
750 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
753 if (WINED3DFMT_UNKNOWN != Format) {
754 object->bytesPerPixel = tableEntry->bpp;
755 } else {
756 object->bytesPerPixel = 0;
759 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
761 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
763 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
764 * this function is too deep to need to care about things like this.
765 * Levels need to be checked too, and possibly Type since they all affect what can be done.
766 * ****************************************/
767 switch(Pool) {
768 case WINED3DPOOL_SCRATCH:
769 if(!Lockable)
770 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
771 "which are mutually exclusive, setting lockable to TRUE\n");
772 Lockable = TRUE;
773 break;
774 case WINED3DPOOL_SYSTEMMEM:
775 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
776 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
777 case WINED3DPOOL_MANAGED:
778 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
779 "Usage of DYNAMIC which are mutually exclusive, not doing "
780 "anything just telling you.\n");
781 break;
782 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
783 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
784 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
785 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
786 break;
787 default:
788 FIXME("(%p) Unknown pool %d\n", This, Pool);
789 break;
792 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
793 FIXME("Trying to create a render target that isn't in the default pool\n");
796 /* mark the texture as dirty so that it gets loaded first time around*/
797 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
798 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
799 This, Width, Height, Format, debug_d3dformat(Format),
800 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
802 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
803 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
804 This->ddraw_primary = (IWineD3DSurface *) object;
806 /* Look at the implementation and set the correct Vtable */
807 switch(Impl) {
808 case SURFACE_OPENGL:
809 /* Check if a 3D adapter is available when creating gl surfaces */
810 if(!This->adapter) {
811 ERR("OpenGL surfaces are not available without opengl\n");
812 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
813 HeapFree(GetProcessHeap(), 0, object);
814 return WINED3DERR_NOTAVAILABLE;
816 break;
818 case SURFACE_GDI:
819 object->lpVtbl = &IWineGDISurface_Vtbl;
820 break;
822 default:
823 /* To be sure to catch this */
824 ERR("Unknown requested surface implementation %d!\n", Impl);
825 IWineD3DSurface_Release((IWineD3DSurface *) object);
826 return WINED3DERR_INVALIDCALL;
829 list_init(&object->renderbuffers);
831 /* Call the private setup routine */
832 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
836 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
837 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
838 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
839 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
842 IWineD3DTextureImpl *object;
843 unsigned int i;
844 UINT tmpW;
845 UINT tmpH;
846 HRESULT hr;
847 unsigned int pow2Width;
848 unsigned int pow2Height;
849 const GlPixelFormatDesc *glDesc;
850 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
853 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
854 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
855 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
857 /* TODO: It should only be possible to create textures for formats
858 that are reported as supported */
859 if (WINED3DFMT_UNKNOWN >= Format) {
860 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
861 return WINED3DERR_INVALIDCALL;
864 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
865 D3DINITIALIZEBASETEXTURE(object->baseTexture);
866 object->width = Width;
867 object->height = Height;
869 /** Non-power2 support **/
870 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
871 pow2Width = Width;
872 pow2Height = Height;
873 } else {
874 /* Find the nearest pow2 match */
875 pow2Width = pow2Height = 1;
876 while (pow2Width < Width) pow2Width <<= 1;
877 while (pow2Height < Height) pow2Height <<= 1;
880 /** FIXME: add support for real non-power-two if it's provided by the video card **/
881 /* Precalculated scaling for 'faked' non power of two texture coords */
882 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
883 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
884 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
886 /* Calculate levels for mip mapping */
887 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
888 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
889 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
890 return WINED3DERR_INVALIDCALL;
892 if(Levels > 1) {
893 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
894 return WINED3DERR_INVALIDCALL;
896 object->baseTexture.levels = 1;
897 } else if (Levels == 0) {
898 TRACE("calculating levels %d\n", object->baseTexture.levels);
899 object->baseTexture.levels++;
900 tmpW = Width;
901 tmpH = Height;
902 while (tmpW > 1 || tmpH > 1) {
903 tmpW = max(1, tmpW >> 1);
904 tmpH = max(1, tmpH >> 1);
905 object->baseTexture.levels++;
907 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
910 /* Generate all the surfaces */
911 tmpW = Width;
912 tmpH = Height;
913 for (i = 0; i < object->baseTexture.levels; i++)
915 /* use the callback to create the texture surface */
916 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
917 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
918 FIXME("Failed to create surface %p\n", object);
919 /* clean up */
920 object->surfaces[i] = NULL;
921 IWineD3DTexture_Release((IWineD3DTexture *)object);
923 *ppTexture = NULL;
924 return hr;
927 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
928 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
929 /* calculate the next mipmap level */
930 tmpW = max(1, tmpW >> 1);
931 tmpH = max(1, tmpH >> 1);
933 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
935 TRACE("(%p) : Created texture %p\n", This, object);
936 return WINED3D_OK;
939 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
940 UINT Width, UINT Height, UINT Depth,
941 UINT Levels, DWORD Usage,
942 WINED3DFORMAT Format, WINED3DPOOL Pool,
943 IWineD3DVolumeTexture **ppVolumeTexture,
944 HANDLE *pSharedHandle, IUnknown *parent,
945 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
948 IWineD3DVolumeTextureImpl *object;
949 unsigned int i;
950 UINT tmpW;
951 UINT tmpH;
952 UINT tmpD;
953 const GlPixelFormatDesc *glDesc;
954 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
956 /* TODO: It should only be possible to create textures for formats
957 that are reported as supported */
958 if (WINED3DFMT_UNKNOWN >= Format) {
959 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
960 return WINED3DERR_INVALIDCALL;
963 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
964 D3DINITIALIZEBASETEXTURE(object->baseTexture);
966 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
967 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
969 object->width = Width;
970 object->height = Height;
971 object->depth = Depth;
973 /* Calculate levels for mip mapping */
974 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
975 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
976 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
977 return WINED3DERR_INVALIDCALL;
979 if(Levels > 1) {
980 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
981 return WINED3DERR_INVALIDCALL;
983 Levels = 1;
984 } else if (Levels == 0) {
985 object->baseTexture.levels++;
986 tmpW = Width;
987 tmpH = Height;
988 tmpD = Depth;
989 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
990 tmpW = max(1, tmpW >> 1);
991 tmpH = max(1, tmpH >> 1);
992 tmpD = max(1, tmpD >> 1);
993 object->baseTexture.levels++;
995 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
998 /* Generate all the surfaces */
999 tmpW = Width;
1000 tmpH = Height;
1001 tmpD = Depth;
1003 for (i = 0; i < object->baseTexture.levels; i++)
1005 HRESULT hr;
1006 /* Create the volume */
1007 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
1008 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1010 if(FAILED(hr)) {
1011 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1012 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1013 *ppVolumeTexture = NULL;
1014 return hr;
1017 /* Set its container to this object */
1018 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1020 /* calcualte the next mipmap level */
1021 tmpW = max(1, tmpW >> 1);
1022 tmpH = max(1, tmpH >> 1);
1023 tmpD = max(1, tmpD >> 1);
1025 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1027 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1028 TRACE("(%p) : Created volume texture %p\n", This, object);
1029 return WINED3D_OK;
1032 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1033 UINT Width, UINT Height, UINT Depth,
1034 DWORD Usage,
1035 WINED3DFORMAT Format, WINED3DPOOL Pool,
1036 IWineD3DVolume** ppVolume,
1037 HANDLE* pSharedHandle, IUnknown *parent) {
1039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1040 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1041 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1043 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1045 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1046 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1048 object->currentDesc.Width = Width;
1049 object->currentDesc.Height = Height;
1050 object->currentDesc.Depth = Depth;
1051 object->bytesPerPixel = formatDesc->bpp;
1053 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1054 object->lockable = TRUE;
1055 object->locked = FALSE;
1056 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1057 object->dirty = TRUE;
1059 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1062 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1063 UINT Levels, DWORD Usage,
1064 WINED3DFORMAT Format, WINED3DPOOL Pool,
1065 IWineD3DCubeTexture **ppCubeTexture,
1066 HANDLE *pSharedHandle, IUnknown *parent,
1067 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1070 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1071 unsigned int i, j;
1072 UINT tmpW;
1073 HRESULT hr;
1074 unsigned int pow2EdgeLength = EdgeLength;
1075 const GlPixelFormatDesc *glDesc;
1076 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1078 /* TODO: It should only be possible to create textures for formats
1079 that are reported as supported */
1080 if (WINED3DFMT_UNKNOWN >= Format) {
1081 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1082 return WINED3DERR_INVALIDCALL;
1085 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1086 WARN("(%p) : Tried to create not supported cube texture\n", This);
1087 return WINED3DERR_INVALIDCALL;
1090 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1091 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1093 TRACE("(%p) Create Cube Texture\n", This);
1095 /** Non-power2 support **/
1097 /* Find the nearest pow2 match */
1098 pow2EdgeLength = 1;
1099 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1101 object->edgeLength = EdgeLength;
1102 /* TODO: support for native non-power 2 */
1103 /* Precalculated scaling for 'faked' non power of two texture coords */
1104 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1106 /* Calculate levels for mip mapping */
1107 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1108 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1109 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1110 HeapFree(GetProcessHeap(), 0, object);
1111 *ppCubeTexture = NULL;
1113 return WINED3DERR_INVALIDCALL;
1115 if(Levels > 1) {
1116 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1117 HeapFree(GetProcessHeap(), 0, object);
1118 *ppCubeTexture = NULL;
1120 return WINED3DERR_INVALIDCALL;
1122 Levels = 1;
1123 } else if (Levels == 0) {
1124 object->baseTexture.levels++;
1125 tmpW = EdgeLength;
1126 while (tmpW > 1) {
1127 tmpW = max(1, tmpW >> 1);
1128 object->baseTexture.levels++;
1130 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1133 /* Generate all the surfaces */
1134 tmpW = EdgeLength;
1135 for (i = 0; i < object->baseTexture.levels; i++) {
1137 /* Create the 6 faces */
1138 for (j = 0; j < 6; j++) {
1140 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1141 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1143 if(hr!= WINED3D_OK) {
1144 /* clean up */
1145 int k;
1146 int l;
1147 for (l = 0; l < j; l++) {
1148 IWineD3DSurface_Release(object->surfaces[l][i]);
1150 for (k = 0; k < i; k++) {
1151 for (l = 0; l < 6; l++) {
1152 IWineD3DSurface_Release(object->surfaces[l][k]);
1156 FIXME("(%p) Failed to create surface\n",object);
1157 HeapFree(GetProcessHeap(),0,object);
1158 *ppCubeTexture = NULL;
1159 return hr;
1161 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1162 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1164 tmpW = max(1, tmpW >> 1);
1166 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1168 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1169 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1170 return WINED3D_OK;
1173 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1175 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1176 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1178 /* Just a check to see if we support this type of query */
1179 switch(Type) {
1180 case WINED3DQUERYTYPE_OCCLUSION:
1181 TRACE("(%p) occlusion query\n", This);
1182 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1183 hr = WINED3D_OK;
1184 else
1185 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1186 break;
1188 case WINED3DQUERYTYPE_EVENT:
1189 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1190 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1191 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1193 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1195 hr = WINED3D_OK;
1196 break;
1198 case WINED3DQUERYTYPE_VCACHE:
1199 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1200 case WINED3DQUERYTYPE_VERTEXSTATS:
1201 case WINED3DQUERYTYPE_TIMESTAMP:
1202 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1203 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1204 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1205 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1206 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1207 case WINED3DQUERYTYPE_PIXELTIMINGS:
1208 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1209 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1210 default:
1211 FIXME("(%p) Unhandled query type %d\n", This, Type);
1213 if(NULL == ppQuery || hr != WINED3D_OK) {
1214 return hr;
1217 D3DCREATEOBJECTINSTANCE(object, Query)
1218 object->type = Type;
1219 /* allocated the 'extended' data based on the type of query requested */
1220 switch(Type){
1221 case WINED3DQUERYTYPE_OCCLUSION:
1222 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1223 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1225 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1226 TRACE("(%p) Allocating data for an occlusion query\n", This);
1227 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1228 break;
1230 case WINED3DQUERYTYPE_EVENT:
1231 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1232 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1234 if(GL_SUPPORT(APPLE_FENCE)) {
1235 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1236 checkGLcall("glGenFencesAPPLE");
1237 } else if(GL_SUPPORT(NV_FENCE)) {
1238 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1239 checkGLcall("glGenFencesNV");
1241 break;
1243 case WINED3DQUERYTYPE_VCACHE:
1244 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1245 case WINED3DQUERYTYPE_VERTEXSTATS:
1246 case WINED3DQUERYTYPE_TIMESTAMP:
1247 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1248 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1249 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1250 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1251 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1252 case WINED3DQUERYTYPE_PIXELTIMINGS:
1253 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1254 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1255 default:
1256 object->extendedData = 0;
1257 FIXME("(%p) Unhandled query type %d\n",This , Type);
1259 TRACE("(%p) : Created Query %p\n", This, object);
1260 return WINED3D_OK;
1263 /*****************************************************************************
1264 * IWineD3DDeviceImpl_SetupFullscreenWindow
1266 * Helper function that modifies a HWND's Style and ExStyle for proper
1267 * fullscreen use.
1269 * Params:
1270 * iface: Pointer to the IWineD3DDevice interface
1271 * window: Window to setup
1273 *****************************************************************************/
1274 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1277 LONG style, exStyle;
1278 /* Don't do anything if an original style is stored.
1279 * That shouldn't happen
1281 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1282 if (This->style || This->exStyle) {
1283 ERR("(%p): Want to change the window parameters of HWND %p, but "
1284 "another style is stored for restoration afterwards\n", This, window);
1287 /* Get the parameters and save them */
1288 style = GetWindowLongW(window, GWL_STYLE);
1289 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1290 This->style = style;
1291 This->exStyle = exStyle;
1293 /* Filter out window decorations */
1294 style &= ~WS_CAPTION;
1295 style &= ~WS_THICKFRAME;
1296 exStyle &= ~WS_EX_WINDOWEDGE;
1297 exStyle &= ~WS_EX_CLIENTEDGE;
1299 /* Make sure the window is managed, otherwise we won't get keyboard input */
1300 style |= WS_POPUP | WS_SYSMENU;
1302 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1303 This->style, This->exStyle, style, exStyle);
1305 SetWindowLongW(window, GWL_STYLE, style);
1306 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1308 /* Inform the window about the update. */
1309 SetWindowPos(window, HWND_TOP, 0, 0,
1310 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1311 ShowWindow(window, SW_NORMAL);
1314 /*****************************************************************************
1315 * IWineD3DDeviceImpl_RestoreWindow
1317 * Helper function that restores a windows' properties when taking it out
1318 * of fullscreen mode
1320 * Params:
1321 * iface: Pointer to the IWineD3DDevice interface
1322 * window: Window to setup
1324 *****************************************************************************/
1325 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1328 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1329 * switch, do nothing
1331 if (!This->style && !This->exStyle) return;
1333 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1334 This, window, This->style, This->exStyle);
1336 SetWindowLongW(window, GWL_STYLE, This->style);
1337 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1339 /* Delete the old values */
1340 This->style = 0;
1341 This->exStyle = 0;
1343 /* Inform the window about the update */
1344 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1345 0, 0, 0, 0, /* Pos, Size, ignored */
1346 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1349 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1350 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1351 IUnknown* parent,
1352 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1353 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1356 HDC hDc;
1357 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1358 HRESULT hr = WINED3D_OK;
1359 IUnknown *bufferParent;
1361 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1363 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1364 * does a device hold a reference to a swap chain giving them a lifetime of the device
1365 * or does the swap chain notify the device of its destruction.
1366 *******************************/
1368 /* Check the params */
1369 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1370 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1371 return WINED3DERR_INVALIDCALL;
1372 } else if (pPresentationParameters->BackBufferCount > 1) {
1373 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");
1376 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1378 /*********************
1379 * Lookup the window Handle and the relating X window handle
1380 ********************/
1382 /* Setup hwnd we are using, plus which display this equates to */
1383 object->win_handle = pPresentationParameters->hDeviceWindow;
1384 if (!object->win_handle) {
1385 object->win_handle = This->createParms.hFocusWindow;
1388 hDc = GetDC(object->win_handle);
1389 TRACE("Using hDc %p\n", hDc);
1391 if (NULL == hDc) {
1392 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1393 return WINED3DERR_NOTAVAILABLE;
1396 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1397 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1398 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1399 ReleaseDC(object->win_handle, hDc);
1401 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1402 * then the corresponding dimension of the client area of the hDeviceWindow
1403 * (or the focus window, if hDeviceWindow is NULL) is taken.
1404 **********************/
1406 if (pPresentationParameters->Windowed &&
1407 ((pPresentationParameters->BackBufferWidth == 0) ||
1408 (pPresentationParameters->BackBufferHeight == 0) ||
1409 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1411 RECT Rect;
1412 GetClientRect(object->win_handle, &Rect);
1414 if (pPresentationParameters->BackBufferWidth == 0) {
1415 pPresentationParameters->BackBufferWidth = Rect.right;
1416 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1418 if (pPresentationParameters->BackBufferHeight == 0) {
1419 pPresentationParameters->BackBufferHeight = Rect.bottom;
1420 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1422 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1423 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1424 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1428 /* Put the correct figures in the presentation parameters */
1429 TRACE("Copying across presentation parameters\n");
1430 object->presentParms = *pPresentationParameters;
1432 TRACE("calling rendertarget CB\n");
1433 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1434 parent,
1435 object->presentParms.BackBufferWidth,
1436 object->presentParms.BackBufferHeight,
1437 object->presentParms.BackBufferFormat,
1438 object->presentParms.MultiSampleType,
1439 object->presentParms.MultiSampleQuality,
1440 TRUE /* Lockable */,
1441 &object->frontBuffer,
1442 NULL /* pShared (always null)*/);
1443 if (object->frontBuffer != NULL) {
1444 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1445 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1446 } else {
1447 ERR("Failed to create the front buffer\n");
1448 goto error;
1452 * Create an opengl context for the display visual
1453 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1454 * use different properties after that point in time. FIXME: How to handle when requested format
1455 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1456 * it chooses is identical to the one already being used!
1457 **********************************/
1458 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1460 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1461 if(!object->context)
1462 return E_OUTOFMEMORY;
1463 object->num_contexts = 1;
1465 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1466 if (!object->context[0]) {
1467 ERR("Failed to create a new context\n");
1468 hr = WINED3DERR_NOTAVAILABLE;
1469 goto error;
1470 } else {
1471 TRACE("Context created (HWND=%p, glContext=%p)\n",
1472 object->win_handle, object->context[0]->glCtx);
1475 /*********************
1476 * Windowed / Fullscreen
1477 *******************/
1480 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1481 * so we should really check to see if there is a fullscreen swapchain already
1482 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1483 **************************************/
1485 if (!pPresentationParameters->Windowed) {
1487 DEVMODEW devmode;
1488 HDC hdc;
1489 int bpp = 0;
1490 RECT clip_rc;
1492 /* Get info on the current display setup */
1493 hdc = GetDC(0);
1494 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1495 ReleaseDC(0, hdc);
1497 /* Change the display settings */
1498 memset(&devmode, 0, sizeof(devmode));
1499 devmode.dmSize = sizeof(devmode);
1500 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1501 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1502 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1503 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1504 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1506 /* For GetDisplayMode */
1507 This->ddraw_width = devmode.dmPelsWidth;
1508 This->ddraw_height = devmode.dmPelsHeight;
1509 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1511 IWineD3DDevice_SetFullscreen(iface, TRUE);
1513 /* And finally clip mouse to our screen */
1514 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1515 ClipCursor(&clip_rc);
1518 /*********************
1519 * Create the back, front and stencil buffers
1520 *******************/
1521 if(object->presentParms.BackBufferCount > 0) {
1522 int i;
1524 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1525 if(!object->backBuffer) {
1526 ERR("Out of memory\n");
1527 hr = E_OUTOFMEMORY;
1528 goto error;
1531 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1532 TRACE("calling rendertarget CB\n");
1533 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1534 parent,
1535 object->presentParms.BackBufferWidth,
1536 object->presentParms.BackBufferHeight,
1537 object->presentParms.BackBufferFormat,
1538 object->presentParms.MultiSampleType,
1539 object->presentParms.MultiSampleQuality,
1540 TRUE /* Lockable */,
1541 &object->backBuffer[i],
1542 NULL /* pShared (always null)*/);
1543 if(hr == WINED3D_OK && object->backBuffer[i]) {
1544 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1545 } else {
1546 ERR("Cannot create new back buffer\n");
1547 goto error;
1549 ENTER_GL();
1550 glDrawBuffer(GL_BACK);
1551 checkGLcall("glDrawBuffer(GL_BACK)");
1552 LEAVE_GL();
1554 } else {
1555 object->backBuffer = NULL;
1557 /* Single buffering - draw to front buffer */
1558 ENTER_GL();
1559 glDrawBuffer(GL_FRONT);
1560 checkGLcall("glDrawBuffer(GL_FRONT)");
1561 LEAVE_GL();
1564 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1565 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1566 TRACE("Creating depth stencil buffer\n");
1567 if (This->depthStencilBuffer == NULL ) {
1568 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1569 parent,
1570 object->presentParms.BackBufferWidth,
1571 object->presentParms.BackBufferHeight,
1572 object->presentParms.AutoDepthStencilFormat,
1573 object->presentParms.MultiSampleType,
1574 object->presentParms.MultiSampleQuality,
1575 FALSE /* FIXME: Discard */,
1576 &This->depthStencilBuffer,
1577 NULL /* pShared (always null)*/ );
1578 if (This->depthStencilBuffer != NULL)
1579 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1582 /** TODO: A check on width, height and multisample types
1583 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1584 ****************************/
1585 object->wantsDepthStencilBuffer = TRUE;
1586 } else {
1587 object->wantsDepthStencilBuffer = FALSE;
1590 TRACE("Created swapchain %p\n", object);
1591 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1592 return WINED3D_OK;
1594 error:
1595 if (object->backBuffer) {
1596 int i;
1597 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1598 if(object->backBuffer[i]) {
1599 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1600 IUnknown_Release(bufferParent); /* once for the get parent */
1601 if (IUnknown_Release(bufferParent) > 0) {
1602 FIXME("(%p) Something's still holding the back buffer\n",This);
1606 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1607 object->backBuffer = NULL;
1609 if(object->context[0])
1610 DestroyContext(This, object->context[0]);
1611 if(object->frontBuffer) {
1612 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1613 IUnknown_Release(bufferParent); /* once for the get parent */
1614 if (IUnknown_Release(bufferParent) > 0) {
1615 FIXME("(%p) Something's still holding the front buffer\n",This);
1618 HeapFree(GetProcessHeap(), 0, object);
1619 return hr;
1622 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1623 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1625 TRACE("(%p)\n", This);
1627 return This->NumberOfSwapChains;
1630 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1632 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1634 if(iSwapChain < This->NumberOfSwapChains) {
1635 *pSwapChain = This->swapchains[iSwapChain];
1636 IWineD3DSwapChain_AddRef(*pSwapChain);
1637 TRACE("(%p) returning %p\n", This, *pSwapChain);
1638 return WINED3D_OK;
1639 } else {
1640 TRACE("Swapchain out of range\n");
1641 *pSwapChain = NULL;
1642 return WINED3DERR_INVALIDCALL;
1646 /*****
1647 * Vertex Declaration
1648 *****/
1649 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1650 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1652 IWineD3DVertexDeclarationImpl *object = NULL;
1653 HRESULT hr = WINED3D_OK;
1655 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1656 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1658 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1660 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1662 return hr;
1665 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1667 unsigned int idx, idx2;
1668 unsigned int offset;
1669 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1670 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1671 BOOL has_blend_idx = has_blend &&
1672 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1673 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1674 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1675 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1676 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1677 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1678 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1680 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1681 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1683 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1684 WINED3DVERTEXELEMENT *elements = NULL;
1686 unsigned int size;
1687 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1688 if (has_blend_idx) num_blends--;
1690 /* Compute declaration size */
1691 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1692 has_psize + has_diffuse + has_specular + num_textures + 1;
1694 /* convert the declaration */
1695 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1696 if (!elements)
1697 return 0;
1699 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1700 idx = 0;
1701 if (has_pos) {
1702 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1703 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1704 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1706 else {
1707 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1708 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1710 elements[idx].UsageIndex = 0;
1711 idx++;
1713 if (has_blend && (num_blends > 0)) {
1714 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1715 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1716 else
1717 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1718 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1719 elements[idx].UsageIndex = 0;
1720 idx++;
1722 if (has_blend_idx) {
1723 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1724 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1725 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1726 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1727 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1728 else
1729 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1730 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1731 elements[idx].UsageIndex = 0;
1732 idx++;
1734 if (has_normal) {
1735 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1736 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1737 elements[idx].UsageIndex = 0;
1738 idx++;
1740 if (has_psize) {
1741 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1742 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1743 elements[idx].UsageIndex = 0;
1744 idx++;
1746 if (has_diffuse) {
1747 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1748 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1749 elements[idx].UsageIndex = 0;
1750 idx++;
1752 if (has_specular) {
1753 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1754 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1755 elements[idx].UsageIndex = 1;
1756 idx++;
1758 for (idx2 = 0; idx2 < num_textures; idx2++) {
1759 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1760 switch (numcoords) {
1761 case WINED3DFVF_TEXTUREFORMAT1:
1762 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1763 break;
1764 case WINED3DFVF_TEXTUREFORMAT2:
1765 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1766 break;
1767 case WINED3DFVF_TEXTUREFORMAT3:
1768 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1769 break;
1770 case WINED3DFVF_TEXTUREFORMAT4:
1771 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1772 break;
1774 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1775 elements[idx].UsageIndex = idx2;
1776 idx++;
1779 /* Now compute offsets, and initialize the rest of the fields */
1780 for (idx = 0, offset = 0; idx < size-1; idx++) {
1781 elements[idx].Stream = 0;
1782 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1783 elements[idx].Offset = offset;
1784 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1787 *ppVertexElements = elements;
1788 return size;
1791 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1792 WINED3DVERTEXELEMENT* elements = NULL;
1793 size_t size;
1794 DWORD hr;
1796 size = ConvertFvfToDeclaration(Fvf, &elements);
1797 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1799 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1800 HeapFree(GetProcessHeap(), 0, elements);
1801 if (hr != S_OK) return hr;
1803 return WINED3D_OK;
1806 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1807 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1809 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1810 HRESULT hr = WINED3D_OK;
1811 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1812 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1814 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1816 if (vertex_declaration) {
1817 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1820 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1822 if (WINED3D_OK != hr) {
1823 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1824 IWineD3DVertexShader_Release(*ppVertexShader);
1825 return WINED3DERR_INVALIDCALL;
1828 return WINED3D_OK;
1831 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1833 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1834 HRESULT hr = WINED3D_OK;
1836 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1837 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1838 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1839 if (WINED3D_OK == hr) {
1840 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1841 } else {
1842 WARN("(%p) : Failed to create pixel shader\n", This);
1845 return hr;
1848 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1850 IWineD3DPaletteImpl *object;
1851 HRESULT hr;
1852 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1854 /* Create the new object */
1855 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1856 if(!object) {
1857 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1858 return E_OUTOFMEMORY;
1861 object->lpVtbl = &IWineD3DPalette_Vtbl;
1862 object->ref = 1;
1863 object->Flags = Flags;
1864 object->parent = Parent;
1865 object->wineD3DDevice = This;
1866 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1868 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1870 if(!object->hpal) {
1871 HeapFree( GetProcessHeap(), 0, object);
1872 return E_OUTOFMEMORY;
1875 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1876 if(FAILED(hr)) {
1877 IWineD3DPalette_Release((IWineD3DPalette *) object);
1878 return hr;
1881 *Palette = (IWineD3DPalette *) object;
1883 return WINED3D_OK;
1886 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1887 HBITMAP hbm;
1888 BITMAP bm;
1889 HRESULT hr;
1890 HDC dcb = NULL, dcs = NULL;
1891 WINEDDCOLORKEY colorkey;
1893 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1894 if(hbm)
1896 GetObjectA(hbm, sizeof(BITMAP), &bm);
1897 dcb = CreateCompatibleDC(NULL);
1898 if(!dcb) goto out;
1899 SelectObject(dcb, hbm);
1901 else
1903 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1904 * couldn't be loaded
1906 memset(&bm, 0, sizeof(bm));
1907 bm.bmWidth = 32;
1908 bm.bmHeight = 32;
1911 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1912 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1913 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1914 if(FAILED(hr)) {
1915 ERR("Wine logo requested, but failed to create surface\n");
1916 goto out;
1919 if(dcb) {
1920 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1921 if(FAILED(hr)) goto out;
1922 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1923 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1925 colorkey.dwColorSpaceLowValue = 0;
1926 colorkey.dwColorSpaceHighValue = 0;
1927 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1928 } else {
1929 /* Fill the surface with a white color to show that wined3d is there */
1930 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1933 out:
1934 if(dcb) {
1935 DeleteDC(dcb);
1937 if(hbm) {
1938 DeleteObject(hbm);
1940 return;
1943 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1945 IWineD3DSwapChainImpl *swapchain;
1946 HRESULT hr;
1947 DWORD state;
1949 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1950 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1952 /* TODO: Test if OpenGL is compiled in and loaded */
1954 TRACE("(%p) : Creating stateblock\n", This);
1955 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1956 hr = IWineD3DDevice_CreateStateBlock(iface,
1957 WINED3DSBT_INIT,
1958 (IWineD3DStateBlock **)&This->stateBlock,
1959 NULL);
1960 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1961 WARN("Failed to create stateblock\n");
1962 goto err_out;
1964 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1965 This->updateStateBlock = This->stateBlock;
1966 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1968 hr = allocate_shader_constants(This->updateStateBlock);
1969 if (WINED3D_OK != hr) {
1970 goto err_out;
1973 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1974 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1975 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1977 /* Initialize the texture unit mapping to a 1:1 mapping */
1978 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1979 if (state < GL_LIMITS(fragment_samplers)) {
1980 This->texUnitMap[state] = state;
1981 This->rev_tex_unit_map[state] = state;
1982 } else {
1983 This->texUnitMap[state] = -1;
1984 This->rev_tex_unit_map[state] = -1;
1988 /* Setup the implicit swapchain */
1989 TRACE("Creating implicit swapchain\n");
1990 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1991 if (FAILED(hr) || !swapchain) {
1992 WARN("Failed to create implicit swapchain\n");
1993 goto err_out;
1996 This->NumberOfSwapChains = 1;
1997 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1998 if(!This->swapchains) {
1999 ERR("Out of memory!\n");
2000 goto err_out;
2002 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2004 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
2006 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2007 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2008 This->render_targets[0] = swapchain->backBuffer[0];
2009 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2011 else {
2012 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2013 This->render_targets[0] = swapchain->frontBuffer;
2014 This->lastActiveRenderTarget = swapchain->frontBuffer;
2016 IWineD3DSurface_AddRef(This->render_targets[0]);
2017 This->activeContext = swapchain->context[0];
2018 This->lastThread = GetCurrentThreadId();
2020 /* Depth Stencil support */
2021 This->stencilBufferTarget = This->depthStencilBuffer;
2022 if (NULL != This->stencilBufferTarget) {
2023 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2026 /* Set up some starting GL setup */
2027 ENTER_GL();
2029 /* Setup all the devices defaults */
2030 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2031 #if 0
2032 IWineD3DImpl_CheckGraphicsMemory();
2033 #endif
2035 { /* Set a default viewport */
2036 WINED3DVIEWPORT vp;
2037 vp.X = 0;
2038 vp.Y = 0;
2039 vp.Width = pPresentationParameters->BackBufferWidth;
2040 vp.Height = pPresentationParameters->BackBufferHeight;
2041 vp.MinZ = 0.0f;
2042 vp.MaxZ = 1.0f;
2043 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2046 /* Initialize the current view state */
2047 This->view_ident = 1;
2048 This->contexts[0]->last_was_rhw = 0;
2049 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2050 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2052 switch(wined3d_settings.offscreen_rendering_mode) {
2053 case ORM_FBO:
2054 case ORM_PBUFFER:
2055 This->offscreenBuffer = GL_BACK;
2056 break;
2058 case ORM_BACKBUFFER:
2060 if(GL_LIMITS(aux_buffers) > 0) {
2061 TRACE("Using auxilliary buffer for offscreen rendering\n");
2062 This->offscreenBuffer = GL_AUX0;
2063 } else {
2064 TRACE("Using back buffer for offscreen rendering\n");
2065 This->offscreenBuffer = GL_BACK;
2070 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2071 LEAVE_GL();
2073 /* Clear the screen */
2074 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2075 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2076 0x00, 1.0, 0);
2078 This->d3d_initialized = TRUE;
2080 if(wined3d_settings.logo) {
2081 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2083 return WINED3D_OK;
2085 err_out:
2086 HeapFree(GetProcessHeap(), 0, This->render_targets);
2087 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2088 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2089 HeapFree(GetProcessHeap(), 0, This->swapchains);
2090 This->NumberOfSwapChains = 0;
2091 if(swapchain) {
2092 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2094 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2095 if(This->stateBlock) {
2096 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2097 This->stateBlock = NULL;
2099 return hr;
2102 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2104 int sampler;
2105 UINT i;
2106 TRACE("(%p)\n", This);
2108 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2110 /* I don't think that the interface guarants that the device is destroyed from the same thread
2111 * it was created. Thus make sure a context is active for the glDelete* calls
2113 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2115 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2117 TRACE("Deleting high order patches\n");
2118 for(i = 0; i < PATCHMAP_SIZE; i++) {
2119 struct list *e1, *e2;
2120 struct WineD3DRectPatch *patch;
2121 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2122 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2123 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2127 /* Delete the palette conversion shader if it is around */
2128 if(This->paletteConversionShader) {
2129 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2132 /* Delete the pbuffer context if there is any */
2133 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2135 /* Delete the mouse cursor texture */
2136 if(This->cursorTexture) {
2137 ENTER_GL();
2138 glDeleteTextures(1, &This->cursorTexture);
2139 LEAVE_GL();
2140 This->cursorTexture = 0;
2143 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2144 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2146 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2147 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2150 /* Release the update stateblock */
2151 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2152 if(This->updateStateBlock != This->stateBlock)
2153 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2155 This->updateStateBlock = NULL;
2157 { /* because were not doing proper internal refcounts releasing the primary state block
2158 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2159 to set this->stateBlock = NULL; first */
2160 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2161 This->stateBlock = NULL;
2163 /* Release the stateblock */
2164 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2165 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2169 /* Release the buffers (with sanity checks)*/
2170 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2171 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2172 if(This->depthStencilBuffer != This->stencilBufferTarget)
2173 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2175 This->stencilBufferTarget = NULL;
2177 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2178 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2179 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2181 TRACE("Setting rendertarget to NULL\n");
2182 This->render_targets[0] = NULL;
2184 if (This->depthStencilBuffer) {
2185 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2186 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2188 This->depthStencilBuffer = NULL;
2191 for(i=0; i < This->NumberOfSwapChains; i++) {
2192 TRACE("Releasing the implicit swapchain %d\n", i);
2193 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2194 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2198 HeapFree(GetProcessHeap(), 0, This->swapchains);
2199 This->swapchains = NULL;
2200 This->NumberOfSwapChains = 0;
2202 HeapFree(GetProcessHeap(), 0, This->render_targets);
2203 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2204 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2205 This->render_targets = NULL;
2206 This->fbo_color_attachments = NULL;
2207 This->draw_buffers = NULL;
2210 This->d3d_initialized = FALSE;
2211 return WINED3D_OK;
2214 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2216 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2218 /* Setup the window for fullscreen mode */
2219 if(fullscreen && !This->ddraw_fullscreen) {
2220 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2221 } else if(!fullscreen && This->ddraw_fullscreen) {
2222 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2225 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2226 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2227 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2228 * separately.
2230 This->ddraw_fullscreen = fullscreen;
2233 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2234 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2235 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2237 * There is no way to deactivate thread safety once it is enabled.
2239 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2242 /*For now just store the flag(needed in case of ddraw) */
2243 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2245 return;
2248 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2249 DEVMODEW devmode;
2250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2251 LONG ret;
2252 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2253 RECT clip_rc;
2255 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2257 /* Resize the screen even without a window:
2258 * The app could have unset it with SetCooperativeLevel, but not called
2259 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2260 * but we don't have any hwnd
2263 memset(&devmode, 0, sizeof(devmode));
2264 devmode.dmSize = sizeof(devmode);
2265 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2266 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2267 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2268 devmode.dmPelsWidth = pMode->Width;
2269 devmode.dmPelsHeight = pMode->Height;
2271 devmode.dmDisplayFrequency = pMode->RefreshRate;
2272 if (pMode->RefreshRate != 0) {
2273 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2276 /* Only change the mode if necessary */
2277 if( (This->ddraw_width == pMode->Width) &&
2278 (This->ddraw_height == pMode->Height) &&
2279 (This->ddraw_format == pMode->Format) &&
2280 (pMode->RefreshRate == 0) ) {
2281 return WINED3D_OK;
2284 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2285 if (ret != DISP_CHANGE_SUCCESSFUL) {
2286 if(devmode.dmDisplayFrequency != 0) {
2287 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2288 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2289 devmode.dmDisplayFrequency = 0;
2290 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2292 if(ret != DISP_CHANGE_SUCCESSFUL) {
2293 return WINED3DERR_NOTAVAILABLE;
2297 /* Store the new values */
2298 This->ddraw_width = pMode->Width;
2299 This->ddraw_height = pMode->Height;
2300 This->ddraw_format = pMode->Format;
2302 /* Only do this with a window of course */
2303 if(This->ddraw_window)
2304 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2306 /* And finally clip mouse to our screen */
2307 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2308 ClipCursor(&clip_rc);
2310 return WINED3D_OK;
2313 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2315 *ppD3D= This->wineD3D;
2316 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2317 IWineD3D_AddRef(*ppD3D);
2318 return WINED3D_OK;
2321 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2324 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2325 (This->adapter->TextureRam/(1024*1024)),
2326 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2327 /* return simulated texture memory left */
2328 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2333 /*****
2334 * Get / Set FVF
2335 *****/
2336 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2339 /* Update the current state block */
2340 This->updateStateBlock->changed.fvf = TRUE;
2342 if(This->updateStateBlock->fvf == fvf) {
2343 TRACE("Application is setting the old fvf over, nothing to do\n");
2344 return WINED3D_OK;
2347 This->updateStateBlock->fvf = fvf;
2348 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2349 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2350 return WINED3D_OK;
2354 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2356 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2357 *pfvf = This->stateBlock->fvf;
2358 return WINED3D_OK;
2361 /*****
2362 * Get / Set Stream Source
2363 *****/
2364 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2366 IWineD3DVertexBuffer *oldSrc;
2368 if (StreamNumber >= MAX_STREAMS) {
2369 WARN("Stream out of range %d\n", StreamNumber);
2370 return WINED3DERR_INVALIDCALL;
2373 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2374 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2376 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2378 if(oldSrc == pStreamData &&
2379 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2380 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2381 TRACE("Application is setting the old values over, nothing to do\n");
2382 return WINED3D_OK;
2385 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2386 if (pStreamData) {
2387 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2388 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2391 /* Handle recording of state blocks */
2392 if (This->isRecordingState) {
2393 TRACE("Recording... not performing anything\n");
2394 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2395 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2396 return WINED3D_OK;
2399 /* Need to do a getParent and pass the reffs up */
2400 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2401 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2402 so for now, just count internally */
2403 if (pStreamData != NULL) {
2404 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2405 InterlockedIncrement(&vbImpl->bindCount);
2406 IWineD3DVertexBuffer_AddRef(pStreamData);
2408 if (oldSrc != NULL) {
2409 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2410 IWineD3DVertexBuffer_Release(oldSrc);
2413 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2415 return WINED3D_OK;
2418 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2421 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2422 This->stateBlock->streamSource[StreamNumber],
2423 This->stateBlock->streamOffset[StreamNumber],
2424 This->stateBlock->streamStride[StreamNumber]);
2426 if (StreamNumber >= MAX_STREAMS) {
2427 WARN("Stream out of range %d\n", StreamNumber);
2428 return WINED3DERR_INVALIDCALL;
2430 *pStream = This->stateBlock->streamSource[StreamNumber];
2431 *pStride = This->stateBlock->streamStride[StreamNumber];
2432 if (pOffset) {
2433 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2436 if (*pStream != NULL) {
2437 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2439 return WINED3D_OK;
2442 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2444 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2445 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2447 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2448 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2450 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2451 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2453 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2454 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2455 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2458 return WINED3D_OK;
2461 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2464 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2465 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2467 TRACE("(%p) : returning %d\n", This, *Divider);
2469 return WINED3D_OK;
2472 /*****
2473 * Get / Set & Multiply Transform
2474 *****/
2475 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2478 /* Most of this routine, comments included copied from ddraw tree initially: */
2479 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2481 /* Handle recording of state blocks */
2482 if (This->isRecordingState) {
2483 TRACE("Recording... not performing anything\n");
2484 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2485 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2486 return WINED3D_OK;
2490 * If the new matrix is the same as the current one,
2491 * we cut off any further processing. this seems to be a reasonable
2492 * optimization because as was noticed, some apps (warcraft3 for example)
2493 * tend towards setting the same matrix repeatedly for some reason.
2495 * From here on we assume that the new matrix is different, wherever it matters.
2497 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2498 TRACE("The app is setting the same matrix over again\n");
2499 return WINED3D_OK;
2500 } else {
2501 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2505 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2506 where ViewMat = Camera space, WorldMat = world space.
2508 In OpenGL, camera and world space is combined into GL_MODELVIEW
2509 matrix. The Projection matrix stay projection matrix.
2512 /* Capture the times we can just ignore the change for now */
2513 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2514 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2515 /* Handled by the state manager */
2518 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2519 return WINED3D_OK;
2522 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2524 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2525 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2526 return WINED3D_OK;
2529 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2530 WINED3DMATRIX *mat = NULL;
2531 WINED3DMATRIX temp;
2533 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2534 * below means it will be recorded in a state block change, but it
2535 * works regardless where it is recorded.
2536 * If this is found to be wrong, change to StateBlock.
2538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2539 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2541 if (State < HIGHEST_TRANSFORMSTATE)
2543 mat = &This->updateStateBlock->transforms[State];
2544 } else {
2545 FIXME("Unhandled transform state!!\n");
2548 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2550 /* Apply change via set transform - will reapply to eg. lights this way */
2551 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2554 /*****
2555 * Get / Set Light
2556 *****/
2557 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2558 you can reference any indexes you want as long as that number max are enabled at any
2559 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2560 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2561 but when recording, just build a chain pretty much of commands to be replayed. */
2563 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2564 float rho;
2565 PLIGHTINFOEL *object = NULL;
2566 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2567 struct list *e;
2569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2570 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2572 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2573 * the gl driver.
2575 if(!pLight) {
2576 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2577 return WINED3DERR_INVALIDCALL;
2580 switch(pLight->Type) {
2581 case WINED3DLIGHT_POINT:
2582 case WINED3DLIGHT_SPOT:
2583 case WINED3DLIGHT_PARALLELPOINT:
2584 case WINED3DLIGHT_GLSPOT:
2585 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2586 * most wanted
2588 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2589 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2590 return WINED3DERR_INVALIDCALL;
2592 break;
2594 case WINED3DLIGHT_DIRECTIONAL:
2595 /* Ignores attenuation */
2596 break;
2598 default:
2599 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2600 return WINED3DERR_INVALIDCALL;
2603 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2604 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2605 if(object->OriginalIndex == Index) break;
2606 object = NULL;
2609 if(!object) {
2610 TRACE("Adding new light\n");
2611 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2612 if(!object) {
2613 ERR("Out of memory error when allocating a light\n");
2614 return E_OUTOFMEMORY;
2616 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2617 object->glIndex = -1;
2618 object->OriginalIndex = Index;
2619 object->changed = TRUE;
2622 /* Initialize the object */
2623 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,
2624 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2625 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2626 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2627 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2628 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2629 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2631 /* Save away the information */
2632 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2634 switch (pLight->Type) {
2635 case WINED3DLIGHT_POINT:
2636 /* Position */
2637 object->lightPosn[0] = pLight->Position.x;
2638 object->lightPosn[1] = pLight->Position.y;
2639 object->lightPosn[2] = pLight->Position.z;
2640 object->lightPosn[3] = 1.0f;
2641 object->cutoff = 180.0f;
2642 /* FIXME: Range */
2643 break;
2645 case WINED3DLIGHT_DIRECTIONAL:
2646 /* Direction */
2647 object->lightPosn[0] = -pLight->Direction.x;
2648 object->lightPosn[1] = -pLight->Direction.y;
2649 object->lightPosn[2] = -pLight->Direction.z;
2650 object->lightPosn[3] = 0.0;
2651 object->exponent = 0.0f;
2652 object->cutoff = 180.0f;
2653 break;
2655 case WINED3DLIGHT_SPOT:
2656 /* Position */
2657 object->lightPosn[0] = pLight->Position.x;
2658 object->lightPosn[1] = pLight->Position.y;
2659 object->lightPosn[2] = pLight->Position.z;
2660 object->lightPosn[3] = 1.0;
2662 /* Direction */
2663 object->lightDirn[0] = pLight->Direction.x;
2664 object->lightDirn[1] = pLight->Direction.y;
2665 object->lightDirn[2] = pLight->Direction.z;
2666 object->lightDirn[3] = 1.0;
2669 * opengl-ish and d3d-ish spot lights use too different models for the
2670 * light "intensity" as a function of the angle towards the main light direction,
2671 * so we only can approximate very roughly.
2672 * however spot lights are rather rarely used in games (if ever used at all).
2673 * furthermore if still used, probably nobody pays attention to such details.
2675 if (pLight->Falloff == 0) {
2676 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2677 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2678 * will always be 1.0 for both of them, and we don't have to care for the
2679 * rest of the rather complex calculation
2681 object->exponent = 0;
2682 } else {
2683 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2684 if (rho < 0.0001) rho = 0.0001f;
2685 object->exponent = -0.3/log(cos(rho/2));
2687 if (object->exponent > 128.0) {
2688 object->exponent = 128.0;
2690 object->cutoff = pLight->Phi*90/M_PI;
2692 /* FIXME: Range */
2693 break;
2695 default:
2696 FIXME("Unrecognized light type %d\n", pLight->Type);
2699 /* Update the live definitions if the light is currently assigned a glIndex */
2700 if (object->glIndex != -1 && !This->isRecordingState) {
2701 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2703 return WINED3D_OK;
2706 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2707 PLIGHTINFOEL *lightInfo = NULL;
2708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2709 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2710 struct list *e;
2711 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2713 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2714 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2715 if(lightInfo->OriginalIndex == Index) break;
2716 lightInfo = NULL;
2719 if (lightInfo == NULL) {
2720 TRACE("Light information requested but light not defined\n");
2721 return WINED3DERR_INVALIDCALL;
2724 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2725 return WINED3D_OK;
2728 /*****
2729 * Get / Set Light Enable
2730 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2731 *****/
2732 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2733 PLIGHTINFOEL *lightInfo = NULL;
2734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2735 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2736 struct list *e;
2737 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2739 /* Tests show true = 128...not clear why */
2740 Enable = Enable? 128: 0;
2742 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2743 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2744 if(lightInfo->OriginalIndex == Index) break;
2745 lightInfo = NULL;
2747 TRACE("Found light: %p\n", lightInfo);
2749 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2750 if (lightInfo == NULL) {
2752 TRACE("Light enabled requested but light not defined, so defining one!\n");
2753 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2755 /* Search for it again! Should be fairly quick as near head of list */
2756 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2757 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2758 if(lightInfo->OriginalIndex == Index) break;
2759 lightInfo = NULL;
2761 if (lightInfo == NULL) {
2762 FIXME("Adding default lights has failed dismally\n");
2763 return WINED3DERR_INVALIDCALL;
2767 lightInfo->enabledChanged = TRUE;
2768 if(!Enable) {
2769 if(lightInfo->glIndex != -1) {
2770 if(!This->isRecordingState) {
2771 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2774 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2775 lightInfo->glIndex = -1;
2776 } else {
2777 TRACE("Light already disabled, nothing to do\n");
2779 } else {
2780 if (lightInfo->glIndex != -1) {
2781 /* nop */
2782 TRACE("Nothing to do as light was enabled\n");
2783 } else {
2784 int i;
2785 /* Find a free gl light */
2786 for(i = 0; i < This->maxConcurrentLights; i++) {
2787 if(This->stateBlock->activeLights[i] == NULL) {
2788 This->stateBlock->activeLights[i] = lightInfo;
2789 lightInfo->glIndex = i;
2790 break;
2793 if(lightInfo->glIndex == -1) {
2794 ERR("Too many concurrently active lights\n");
2795 return WINED3DERR_INVALIDCALL;
2798 /* i == lightInfo->glIndex */
2799 if(!This->isRecordingState) {
2800 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2805 return WINED3D_OK;
2808 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2810 PLIGHTINFOEL *lightInfo = NULL;
2811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2812 struct list *e;
2813 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2814 TRACE("(%p) : for idx(%d)\n", This, Index);
2816 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2817 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2818 if(lightInfo->OriginalIndex == Index) break;
2819 lightInfo = NULL;
2822 if (lightInfo == NULL) {
2823 TRACE("Light enabled state requested but light not defined\n");
2824 return WINED3DERR_INVALIDCALL;
2826 /* true is 128 according to SetLightEnable */
2827 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2828 return WINED3D_OK;
2831 /*****
2832 * Get / Set Clip Planes
2833 *****/
2834 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2836 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2838 /* Validate Index */
2839 if (Index >= GL_LIMITS(clipplanes)) {
2840 TRACE("Application has requested clipplane this device doesn't support\n");
2841 return WINED3DERR_INVALIDCALL;
2844 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2846 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2847 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2848 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2849 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2850 TRACE("Application is setting old values over, nothing to do\n");
2851 return WINED3D_OK;
2854 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2855 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2856 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2857 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2859 /* Handle recording of state blocks */
2860 if (This->isRecordingState) {
2861 TRACE("Recording... not performing anything\n");
2862 return WINED3D_OK;
2865 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2867 return WINED3D_OK;
2870 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2872 TRACE("(%p) : for idx %d\n", This, Index);
2874 /* Validate Index */
2875 if (Index >= GL_LIMITS(clipplanes)) {
2876 TRACE("Application has requested clipplane this device doesn't support\n");
2877 return WINED3DERR_INVALIDCALL;
2880 pPlane[0] = This->stateBlock->clipplane[Index][0];
2881 pPlane[1] = This->stateBlock->clipplane[Index][1];
2882 pPlane[2] = This->stateBlock->clipplane[Index][2];
2883 pPlane[3] = This->stateBlock->clipplane[Index][3];
2884 return WINED3D_OK;
2887 /*****
2888 * Get / Set Clip Plane Status
2889 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2890 *****/
2891 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2893 FIXME("(%p) : stub\n", This);
2894 if (NULL == pClipStatus) {
2895 return WINED3DERR_INVALIDCALL;
2897 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2898 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2899 return WINED3D_OK;
2902 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2904 FIXME("(%p) : stub\n", This);
2905 if (NULL == pClipStatus) {
2906 return WINED3DERR_INVALIDCALL;
2908 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2909 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2910 return WINED3D_OK;
2913 /*****
2914 * Get / Set Material
2915 *****/
2916 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2919 This->updateStateBlock->changed.material = TRUE;
2920 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2922 /* Handle recording of state blocks */
2923 if (This->isRecordingState) {
2924 TRACE("Recording... not performing anything\n");
2925 return WINED3D_OK;
2928 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2929 return WINED3D_OK;
2932 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2934 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2935 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2936 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2937 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2938 pMaterial->Ambient.b, pMaterial->Ambient.a);
2939 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2940 pMaterial->Specular.b, pMaterial->Specular.a);
2941 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2942 pMaterial->Emissive.b, pMaterial->Emissive.a);
2943 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2945 return WINED3D_OK;
2948 /*****
2949 * Get / Set Indices
2950 *****/
2951 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2953 IWineD3DIndexBuffer *oldIdxs;
2955 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2956 oldIdxs = This->updateStateBlock->pIndexData;
2958 This->updateStateBlock->changed.indices = TRUE;
2959 This->updateStateBlock->pIndexData = pIndexData;
2961 /* Handle recording of state blocks */
2962 if (This->isRecordingState) {
2963 TRACE("Recording... not performing anything\n");
2964 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2965 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2966 return WINED3D_OK;
2969 if(oldIdxs != pIndexData) {
2970 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2971 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2972 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2974 return WINED3D_OK;
2977 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2980 *ppIndexData = This->stateBlock->pIndexData;
2982 /* up ref count on ppindexdata */
2983 if (*ppIndexData) {
2984 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2985 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2986 }else{
2987 TRACE("(%p) No index data set\n", This);
2989 TRACE("Returning %p\n", *ppIndexData);
2991 return WINED3D_OK;
2994 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2995 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2997 TRACE("(%p)->(%d)\n", This, BaseIndex);
2999 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3000 TRACE("Application is setting the old value over, nothing to do\n");
3001 return WINED3D_OK;
3004 This->updateStateBlock->baseVertexIndex = BaseIndex;
3006 if (This->isRecordingState) {
3007 TRACE("Recording... not performing anything\n");
3008 return WINED3D_OK;
3010 /* The base vertex index affects the stream sources */
3011 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3012 return WINED3D_OK;
3015 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3017 TRACE("(%p) : base_index %p\n", This, base_index);
3019 *base_index = This->stateBlock->baseVertexIndex;
3021 TRACE("Returning %u\n", *base_index);
3023 return WINED3D_OK;
3026 /*****
3027 * Get / Set Viewports
3028 *****/
3029 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3032 TRACE("(%p)\n", This);
3033 This->updateStateBlock->changed.viewport = TRUE;
3034 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3036 /* Handle recording of state blocks */
3037 if (This->isRecordingState) {
3038 TRACE("Recording... not performing anything\n");
3039 return WINED3D_OK;
3042 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3043 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3045 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3046 return WINED3D_OK;
3050 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3052 TRACE("(%p)\n", This);
3053 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3054 return WINED3D_OK;
3057 /*****
3058 * Get / Set Render States
3059 * TODO: Verify against dx9 definitions
3060 *****/
3061 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3064 DWORD oldValue = This->stateBlock->renderState[State];
3066 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3068 This->updateStateBlock->changed.renderState[State] = TRUE;
3069 This->updateStateBlock->renderState[State] = Value;
3071 /* Handle recording of state blocks */
3072 if (This->isRecordingState) {
3073 TRACE("Recording... not performing anything\n");
3074 return WINED3D_OK;
3077 /* Compared here and not before the assignment to allow proper stateblock recording */
3078 if(Value == oldValue) {
3079 TRACE("Application is setting the old value over, nothing to do\n");
3080 } else {
3081 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3084 return WINED3D_OK;
3087 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3089 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3090 *pValue = This->stateBlock->renderState[State];
3091 return WINED3D_OK;
3094 /*****
3095 * Get / Set Sampler States
3096 * TODO: Verify against dx9 definitions
3097 *****/
3099 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3101 DWORD oldValue;
3103 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3104 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3106 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3107 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3111 * SetSampler is designed to allow for more than the standard up to 8 textures
3112 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3113 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3115 * http://developer.nvidia.com/object/General_FAQ.html#t6
3117 * There are two new settings for GForce
3118 * the sampler one:
3119 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3120 * and the texture one:
3121 * GL_MAX_TEXTURE_COORDS_ARB.
3122 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3123 ******************/
3125 oldValue = This->stateBlock->samplerState[Sampler][Type];
3126 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3127 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3129 /* Handle recording of state blocks */
3130 if (This->isRecordingState) {
3131 TRACE("Recording... not performing anything\n");
3132 return WINED3D_OK;
3135 if(oldValue == Value) {
3136 TRACE("Application is setting the old value over, nothing to do\n");
3137 return WINED3D_OK;
3140 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3142 return WINED3D_OK;
3145 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3148 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3149 This, Sampler, debug_d3dsamplerstate(Type), Type);
3151 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3152 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3155 *Value = This->stateBlock->samplerState[Sampler][Type];
3156 TRACE("(%p) : Returning %#x\n", This, *Value);
3158 return WINED3D_OK;
3161 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3164 This->updateStateBlock->changed.scissorRect = TRUE;
3165 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3166 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3167 return WINED3D_OK;
3169 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3171 if(This->isRecordingState) {
3172 TRACE("Recording... not performing anything\n");
3173 return WINED3D_OK;
3176 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3178 return WINED3D_OK;
3181 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3184 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3185 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3186 return WINED3D_OK;
3189 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3191 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3193 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3195 This->updateStateBlock->vertexDecl = pDecl;
3196 This->updateStateBlock->changed.vertexDecl = TRUE;
3198 if (This->isRecordingState) {
3199 TRACE("Recording... not performing anything\n");
3200 return WINED3D_OK;
3201 } else if(pDecl == oldDecl) {
3202 /* Checked after the assignment to allow proper stateblock recording */
3203 TRACE("Application is setting the old declaration over, nothing to do\n");
3204 return WINED3D_OK;
3207 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3208 return WINED3D_OK;
3211 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3214 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3216 *ppDecl = This->stateBlock->vertexDecl;
3217 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3218 return WINED3D_OK;
3221 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3223 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3225 This->updateStateBlock->vertexShader = pShader;
3226 This->updateStateBlock->changed.vertexShader = TRUE;
3228 if (This->isRecordingState) {
3229 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3230 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3231 TRACE("Recording... not performing anything\n");
3232 return WINED3D_OK;
3233 } else if(oldShader == pShader) {
3234 /* Checked here to allow proper stateblock recording */
3235 TRACE("App is setting the old shader over, nothing to do\n");
3236 return WINED3D_OK;
3239 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3240 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3241 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3243 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3245 return WINED3D_OK;
3248 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3251 if (NULL == ppShader) {
3252 return WINED3DERR_INVALIDCALL;
3254 *ppShader = This->stateBlock->vertexShader;
3255 if( NULL != *ppShader)
3256 IWineD3DVertexShader_AddRef(*ppShader);
3258 TRACE("(%p) : returning %p\n", This, *ppShader);
3259 return WINED3D_OK;
3262 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3263 IWineD3DDevice *iface,
3264 UINT start,
3265 CONST BOOL *srcData,
3266 UINT count) {
3268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3269 int i, cnt = min(count, MAX_CONST_B - start);
3271 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3272 iface, srcData, start, count);
3274 if (srcData == NULL || cnt < 0)
3275 return WINED3DERR_INVALIDCALL;
3277 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3278 for (i = 0; i < cnt; i++)
3279 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3281 for (i = start; i < cnt + start; ++i) {
3282 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3285 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3287 return WINED3D_OK;
3290 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3291 IWineD3DDevice *iface,
3292 UINT start,
3293 BOOL *dstData,
3294 UINT count) {
3296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3297 int cnt = min(count, MAX_CONST_B - start);
3299 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3300 iface, dstData, start, count);
3302 if (dstData == NULL || cnt < 0)
3303 return WINED3DERR_INVALIDCALL;
3305 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3306 return WINED3D_OK;
3309 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3310 IWineD3DDevice *iface,
3311 UINT start,
3312 CONST int *srcData,
3313 UINT count) {
3315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3316 int i, cnt = min(count, MAX_CONST_I - start);
3318 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3319 iface, srcData, start, count);
3321 if (srcData == NULL || cnt < 0)
3322 return WINED3DERR_INVALIDCALL;
3324 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3325 for (i = 0; i < cnt; i++)
3326 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3327 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3329 for (i = start; i < cnt + start; ++i) {
3330 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3333 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3335 return WINED3D_OK;
3338 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3339 IWineD3DDevice *iface,
3340 UINT start,
3341 int *dstData,
3342 UINT count) {
3344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3345 int cnt = min(count, MAX_CONST_I - start);
3347 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3348 iface, dstData, start, count);
3350 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3351 return WINED3DERR_INVALIDCALL;
3353 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3354 return WINED3D_OK;
3357 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3358 IWineD3DDevice *iface,
3359 UINT start,
3360 CONST float *srcData,
3361 UINT count) {
3363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3364 int i;
3366 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3367 iface, srcData, start, count);
3369 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3370 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3371 return WINED3DERR_INVALIDCALL;
3373 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3374 if(TRACE_ON(d3d)) {
3375 for (i = 0; i < count; i++)
3376 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3377 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3380 for (i = start; i < count + start; ++i) {
3381 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3382 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3383 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3384 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3385 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3387 ptr->idx[ptr->count++] = i;
3388 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3392 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3394 return WINED3D_OK;
3397 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3398 IWineD3DDevice *iface,
3399 UINT start,
3400 float *dstData,
3401 UINT count) {
3403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3404 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3406 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3407 iface, dstData, start, count);
3409 if (dstData == NULL || cnt < 0)
3410 return WINED3DERR_INVALIDCALL;
3412 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3413 return WINED3D_OK;
3416 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3417 DWORD i;
3418 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3419 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3423 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3424 int i = This->rev_tex_unit_map[unit];
3425 int j = This->texUnitMap[stage];
3427 This->texUnitMap[stage] = unit;
3428 if (i != -1 && i != stage) {
3429 This->texUnitMap[i] = -1;
3432 This->rev_tex_unit_map[unit] = stage;
3433 if (j != -1 && j != unit) {
3434 This->rev_tex_unit_map[j] = -1;
3438 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3439 int i;
3441 for (i = 0; i < MAX_TEXTURES; ++i) {
3442 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3443 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3444 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3445 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3446 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3447 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3448 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3449 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3451 if (color_op == WINED3DTOP_DISABLE) {
3452 /* Not used, and disable higher stages */
3453 while (i < MAX_TEXTURES) {
3454 This->fixed_function_usage_map[i] = FALSE;
3455 ++i;
3457 break;
3460 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3461 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3462 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3463 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3464 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3465 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3466 This->fixed_function_usage_map[i] = TRUE;
3467 } else {
3468 This->fixed_function_usage_map[i] = FALSE;
3471 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3472 This->fixed_function_usage_map[i+1] = TRUE;
3477 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3478 int i, tex;
3480 device_update_fixed_function_usage_map(This);
3482 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3483 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3484 if (!This->fixed_function_usage_map[i]) continue;
3486 if (This->texUnitMap[i] != i) {
3487 device_map_stage(This, i, i);
3488 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3489 markTextureStagesDirty(This, i);
3492 return;
3495 /* Now work out the mapping */
3496 tex = 0;
3497 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3498 if (!This->fixed_function_usage_map[i]) continue;
3500 if (This->texUnitMap[i] != tex) {
3501 device_map_stage(This, i, tex);
3502 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3503 markTextureStagesDirty(This, i);
3506 ++tex;
3510 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3511 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3512 int i;
3514 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3515 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3516 device_map_stage(This, i, i);
3517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3518 if (i < MAX_TEXTURES) {
3519 markTextureStagesDirty(This, i);
3525 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3526 int current_mapping = This->rev_tex_unit_map[unit];
3528 if (current_mapping == -1) {
3529 /* Not currently used */
3530 return TRUE;
3533 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3534 /* Used by a fragment sampler */
3536 if (!pshader_sampler_tokens) {
3537 /* No pixel shader, check fixed function */
3538 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3541 /* Pixel shader, check the shader's sampler map */
3542 return !pshader_sampler_tokens[current_mapping];
3545 /* Used by a vertex sampler */
3546 return !vshader_sampler_tokens[current_mapping];
3549 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3550 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3551 DWORD *pshader_sampler_tokens = NULL;
3552 int start = GL_LIMITS(combined_samplers) - 1;
3553 int i;
3555 if (ps) {
3556 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3558 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3559 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3560 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3563 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3564 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3565 if (vshader_sampler_tokens[i]) {
3566 if (This->texUnitMap[vsampler_idx] != -1) {
3567 /* Already mapped somewhere */
3568 continue;
3571 while (start >= 0) {
3572 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3573 device_map_stage(This, vsampler_idx, start);
3574 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3576 --start;
3577 break;
3580 --start;
3586 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3587 BOOL vs = use_vs(This);
3588 BOOL ps = use_ps(This);
3590 * Rules are:
3591 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3592 * that would be really messy and require shader recompilation
3593 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3594 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3596 if (ps) {
3597 device_map_psamplers(This);
3598 } else {
3599 device_map_fixed_function_samplers(This);
3602 if (vs) {
3603 device_map_vsamplers(This, ps);
3607 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3609 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3610 This->updateStateBlock->pixelShader = pShader;
3611 This->updateStateBlock->changed.pixelShader = TRUE;
3613 /* Handle recording of state blocks */
3614 if (This->isRecordingState) {
3615 TRACE("Recording... not performing anything\n");
3618 if (This->isRecordingState) {
3619 TRACE("Recording... not performing anything\n");
3620 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3621 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3622 return WINED3D_OK;
3625 if(pShader == oldShader) {
3626 TRACE("App is setting the old pixel shader over, nothing to do\n");
3627 return WINED3D_OK;
3630 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3631 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3633 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3634 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3636 return WINED3D_OK;
3639 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3642 if (NULL == ppShader) {
3643 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3644 return WINED3DERR_INVALIDCALL;
3647 *ppShader = This->stateBlock->pixelShader;
3648 if (NULL != *ppShader) {
3649 IWineD3DPixelShader_AddRef(*ppShader);
3651 TRACE("(%p) : returning %p\n", This, *ppShader);
3652 return WINED3D_OK;
3655 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3656 IWineD3DDevice *iface,
3657 UINT start,
3658 CONST BOOL *srcData,
3659 UINT count) {
3661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3662 int i, cnt = min(count, MAX_CONST_B - start);
3664 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3665 iface, srcData, start, count);
3667 if (srcData == NULL || cnt < 0)
3668 return WINED3DERR_INVALIDCALL;
3670 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3671 for (i = 0; i < cnt; i++)
3672 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3674 for (i = start; i < cnt + start; ++i) {
3675 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3678 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3680 return WINED3D_OK;
3683 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3684 IWineD3DDevice *iface,
3685 UINT start,
3686 BOOL *dstData,
3687 UINT count) {
3689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3690 int cnt = min(count, MAX_CONST_B - start);
3692 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3693 iface, dstData, start, count);
3695 if (dstData == NULL || cnt < 0)
3696 return WINED3DERR_INVALIDCALL;
3698 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3699 return WINED3D_OK;
3702 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3703 IWineD3DDevice *iface,
3704 UINT start,
3705 CONST int *srcData,
3706 UINT count) {
3708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3709 int i, cnt = min(count, MAX_CONST_I - start);
3711 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3712 iface, srcData, start, count);
3714 if (srcData == NULL || cnt < 0)
3715 return WINED3DERR_INVALIDCALL;
3717 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3718 for (i = 0; i < cnt; i++)
3719 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3720 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3722 for (i = start; i < cnt + start; ++i) {
3723 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3726 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3728 return WINED3D_OK;
3731 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3732 IWineD3DDevice *iface,
3733 UINT start,
3734 int *dstData,
3735 UINT count) {
3737 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3738 int cnt = min(count, MAX_CONST_I - start);
3740 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3741 iface, dstData, start, count);
3743 if (dstData == NULL || cnt < 0)
3744 return WINED3DERR_INVALIDCALL;
3746 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3747 return WINED3D_OK;
3750 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3751 IWineD3DDevice *iface,
3752 UINT start,
3753 CONST float *srcData,
3754 UINT count) {
3756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3757 int i;
3759 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3760 iface, srcData, start, count);
3762 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3763 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3764 return WINED3DERR_INVALIDCALL;
3766 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3767 if(TRACE_ON(d3d)) {
3768 for (i = 0; i < count; i++)
3769 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3770 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3773 for (i = start; i < count + start; ++i) {
3774 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3775 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3776 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3777 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3778 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3780 ptr->idx[ptr->count++] = i;
3781 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3785 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3787 return WINED3D_OK;
3790 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3791 IWineD3DDevice *iface,
3792 UINT start,
3793 float *dstData,
3794 UINT count) {
3796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3797 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3799 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3800 iface, dstData, start, count);
3802 if (dstData == NULL || cnt < 0)
3803 return WINED3DERR_INVALIDCALL;
3805 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3806 return WINED3D_OK;
3809 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3810 static HRESULT
3811 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3812 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3813 unsigned int i;
3814 DWORD DestFVF = dest->fvf;
3815 WINED3DVIEWPORT vp;
3816 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3817 BOOL doClip;
3818 int numTextures;
3820 if (lpStrideData->u.s.normal.lpData) {
3821 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3824 if (lpStrideData->u.s.position.lpData == NULL) {
3825 ERR("Source has no position mask\n");
3826 return WINED3DERR_INVALIDCALL;
3829 /* We might access VBOs from this code, so hold the lock */
3830 ENTER_GL();
3832 if (dest->resource.allocatedMemory == NULL) {
3833 /* This may happen if we do direct locking into a vbo. Unlikely,
3834 * but theoretically possible(ddraw processvertices test)
3836 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3837 if(!dest->resource.allocatedMemory) {
3838 LEAVE_GL();
3839 ERR("Out of memory\n");
3840 return E_OUTOFMEMORY;
3842 if(dest->vbo) {
3843 void *src;
3844 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3845 checkGLcall("glBindBufferARB");
3846 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3847 if(src) {
3848 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3850 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3851 checkGLcall("glUnmapBufferARB");
3855 /* Get a pointer into the destination vbo(create one if none exists) and
3856 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3858 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3859 CreateVBO(dest);
3862 if(dest->vbo) {
3863 unsigned char extrabytes = 0;
3864 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3865 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3866 * this may write 4 extra bytes beyond the area that should be written
3868 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3869 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3870 if(!dest_conv_addr) {
3871 ERR("Out of memory\n");
3872 /* Continue without storing converted vertices */
3874 dest_conv = dest_conv_addr;
3877 /* Should I clip?
3878 * a) WINED3DRS_CLIPPING is enabled
3879 * b) WINED3DVOP_CLIP is passed
3881 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3882 static BOOL warned = FALSE;
3884 * The clipping code is not quite correct. Some things need
3885 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3886 * so disable clipping for now.
3887 * (The graphics in Half-Life are broken, and my processvertices
3888 * test crashes with IDirect3DDevice3)
3889 doClip = TRUE;
3891 doClip = FALSE;
3892 if(!warned) {
3893 warned = TRUE;
3894 FIXME("Clipping is broken and disabled for now\n");
3896 } else doClip = FALSE;
3897 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3899 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3900 WINED3DTS_VIEW,
3901 &view_mat);
3902 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3903 WINED3DTS_PROJECTION,
3904 &proj_mat);
3905 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3906 WINED3DTS_WORLDMATRIX(0),
3907 &world_mat);
3909 TRACE("View mat:\n");
3910 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);
3911 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);
3912 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);
3913 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);
3915 TRACE("Proj mat:\n");
3916 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);
3917 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);
3918 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);
3919 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);
3921 TRACE("World mat:\n");
3922 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);
3923 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);
3924 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);
3925 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);
3927 /* Get the viewport */
3928 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3929 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3930 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3932 multiply_matrix(&mat,&view_mat,&world_mat);
3933 multiply_matrix(&mat,&proj_mat,&mat);
3935 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3937 for (i = 0; i < dwCount; i+= 1) {
3938 unsigned int tex_index;
3940 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3941 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3942 /* The position first */
3943 float *p =
3944 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3945 float x, y, z, rhw;
3946 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3948 /* Multiplication with world, view and projection matrix */
3949 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);
3950 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);
3951 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);
3952 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);
3954 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3956 /* WARNING: The following things are taken from d3d7 and were not yet checked
3957 * against d3d8 or d3d9!
3960 /* Clipping conditions: From
3961 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3963 * A vertex is clipped if it does not match the following requirements
3964 * -rhw < x <= rhw
3965 * -rhw < y <= rhw
3966 * 0 < z <= rhw
3967 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3969 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3970 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3974 if( !doClip ||
3975 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3976 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3977 ( rhw > eps ) ) ) {
3979 /* "Normal" viewport transformation (not clipped)
3980 * 1) The values are divided by rhw
3981 * 2) The y axis is negative, so multiply it with -1
3982 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3983 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3984 * 4) Multiply x with Width/2 and add Width/2
3985 * 5) The same for the height
3986 * 6) Add the viewpoint X and Y to the 2D coordinates and
3987 * The minimum Z value to z
3988 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3990 * Well, basically it's simply a linear transformation into viewport
3991 * coordinates
3994 x /= rhw;
3995 y /= rhw;
3996 z /= rhw;
3998 y *= -1;
4000 x *= vp.Width / 2;
4001 y *= vp.Height / 2;
4002 z *= vp.MaxZ - vp.MinZ;
4004 x += vp.Width / 2 + vp.X;
4005 y += vp.Height / 2 + vp.Y;
4006 z += vp.MinZ;
4008 rhw = 1 / rhw;
4009 } else {
4010 /* That vertex got clipped
4011 * Contrary to OpenGL it is not dropped completely, it just
4012 * undergoes a different calculation.
4014 TRACE("Vertex got clipped\n");
4015 x += rhw;
4016 y += rhw;
4018 x /= 2;
4019 y /= 2;
4021 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4022 * outside of the main vertex buffer memory. That needs some more
4023 * investigation...
4027 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4030 ( (float *) dest_ptr)[0] = x;
4031 ( (float *) dest_ptr)[1] = y;
4032 ( (float *) dest_ptr)[2] = z;
4033 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4035 dest_ptr += 3 * sizeof(float);
4037 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4038 dest_ptr += sizeof(float);
4041 if(dest_conv) {
4042 float w = 1 / rhw;
4043 ( (float *) dest_conv)[0] = x * w;
4044 ( (float *) dest_conv)[1] = y * w;
4045 ( (float *) dest_conv)[2] = z * w;
4046 ( (float *) dest_conv)[3] = w;
4048 dest_conv += 3 * sizeof(float);
4050 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4051 dest_conv += sizeof(float);
4055 if (DestFVF & WINED3DFVF_PSIZE) {
4056 dest_ptr += sizeof(DWORD);
4057 if(dest_conv) dest_conv += sizeof(DWORD);
4059 if (DestFVF & WINED3DFVF_NORMAL) {
4060 float *normal =
4061 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4062 /* AFAIK this should go into the lighting information */
4063 FIXME("Didn't expect the destination to have a normal\n");
4064 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4065 if(dest_conv) {
4066 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4070 if (DestFVF & WINED3DFVF_DIFFUSE) {
4071 DWORD *color_d =
4072 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4073 if(!color_d) {
4074 static BOOL warned = FALSE;
4076 if(!warned) {
4077 ERR("No diffuse color in source, but destination has one\n");
4078 warned = TRUE;
4081 *( (DWORD *) dest_ptr) = 0xffffffff;
4082 dest_ptr += sizeof(DWORD);
4084 if(dest_conv) {
4085 *( (DWORD *) dest_conv) = 0xffffffff;
4086 dest_conv += sizeof(DWORD);
4089 else {
4090 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4091 if(dest_conv) {
4092 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4093 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4094 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4095 dest_conv += sizeof(DWORD);
4100 if (DestFVF & WINED3DFVF_SPECULAR) {
4101 /* What's the color value in the feedback buffer? */
4102 DWORD *color_s =
4103 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4104 if(!color_s) {
4105 static BOOL warned = FALSE;
4107 if(!warned) {
4108 ERR("No specular color in source, but destination has one\n");
4109 warned = TRUE;
4112 *( (DWORD *) dest_ptr) = 0xFF000000;
4113 dest_ptr += sizeof(DWORD);
4115 if(dest_conv) {
4116 *( (DWORD *) dest_conv) = 0xFF000000;
4117 dest_conv += sizeof(DWORD);
4120 else {
4121 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4122 if(dest_conv) {
4123 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4124 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4125 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4126 dest_conv += sizeof(DWORD);
4131 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4132 float *tex_coord =
4133 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4134 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4135 if(!tex_coord) {
4136 ERR("No source texture, but destination requests one\n");
4137 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4138 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4140 else {
4141 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4142 if(dest_conv) {
4143 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4149 if(dest_conv) {
4150 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4151 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4152 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4153 dwCount * get_flexible_vertex_size(DestFVF),
4154 dest_conv_addr));
4155 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4156 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4159 LEAVE_GL();
4161 return WINED3D_OK;
4163 #undef copy_and_next
4165 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4167 WineDirect3DVertexStridedData strided;
4168 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4169 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4171 if(pVertexDecl) {
4172 ERR("Output vertex declaration not implemented yet\n");
4175 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
4176 * and this call is quite performance critical, so don't call needlessly
4178 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4179 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4182 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4183 * control the streamIsUP flag, thus restore it afterwards.
4185 This->stateBlock->streamIsUP = FALSE;
4186 memset(&strided, 0, sizeof(strided));
4187 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4188 This->stateBlock->streamIsUP = streamWasUP;
4190 if(vbo || SrcStartIndex) {
4191 unsigned int i;
4192 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4193 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4195 * Also get the start index in, but only loop over all elements if there's something to add at all.
4197 #define FIXSRC(type) \
4198 if(strided.u.s.type.VBO) { \
4199 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4200 strided.u.s.type.VBO = 0; \
4201 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4202 ENTER_GL(); \
4203 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4204 vb->vbo = 0; \
4205 LEAVE_GL(); \
4207 if(strided.u.s.type.lpData) { \
4208 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4210 FIXSRC(position);
4211 FIXSRC(blendWeights);
4212 FIXSRC(blendMatrixIndices);
4213 FIXSRC(normal);
4214 FIXSRC(pSize);
4215 FIXSRC(diffuse);
4216 FIXSRC(specular);
4217 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4218 FIXSRC(texCoords[i]);
4220 FIXSRC(position2);
4221 FIXSRC(normal2);
4222 FIXSRC(tangent);
4223 FIXSRC(binormal);
4224 FIXSRC(tessFactor);
4225 FIXSRC(fog);
4226 FIXSRC(depth);
4227 FIXSRC(sample);
4228 #undef FIXSRC
4231 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4234 /*****
4235 * Get / Set Texture Stage States
4236 * TODO: Verify against dx9 definitions
4237 *****/
4238 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4240 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4242 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4244 if (Stage >= MAX_TEXTURES) {
4245 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4246 return WINED3D_OK;
4249 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4250 This->updateStateBlock->textureState[Stage][Type] = Value;
4252 if (This->isRecordingState) {
4253 TRACE("Recording... not performing anything\n");
4254 return WINED3D_OK;
4257 /* Checked after the assignments to allow proper stateblock recording */
4258 if(oldValue == Value) {
4259 TRACE("App is setting the old value over, nothing to do\n");
4260 return WINED3D_OK;
4263 if(Stage > This->stateBlock->lowest_disabled_stage &&
4264 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4265 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4266 * Changes in other states are important on disabled stages too
4268 return WINED3D_OK;
4271 if(Type == WINED3DTSS_COLOROP) {
4272 int i;
4274 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4275 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4276 * they have to be disabled
4278 * The current stage is dirtified below.
4280 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4281 TRACE("Additionally dirtifying stage %d\n", i);
4282 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4284 This->stateBlock->lowest_disabled_stage = Stage;
4285 TRACE("New lowest disabled: %d\n", Stage);
4286 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4287 /* Previously disabled stage enabled. Stages above it may need enabling
4288 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4289 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4291 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4294 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4295 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4296 break;
4298 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4299 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4301 This->stateBlock->lowest_disabled_stage = i;
4302 TRACE("New lowest disabled: %d\n", i);
4304 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4305 /* TODO: Built a stage -> texture unit mapping for register combiners */
4309 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4311 return WINED3D_OK;
4314 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4316 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4317 *pValue = This->updateStateBlock->textureState[Stage][Type];
4318 return WINED3D_OK;
4321 /*****
4322 * Get / Set Texture
4323 *****/
4324 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4326 IWineD3DBaseTexture *oldTexture;
4328 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4330 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4331 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4334 oldTexture = This->updateStateBlock->textures[Stage];
4336 if(pTexture != NULL) {
4337 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4339 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4340 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4341 return WINED3DERR_INVALIDCALL;
4343 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4346 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4347 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4349 This->updateStateBlock->changed.textures[Stage] = TRUE;
4350 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4351 This->updateStateBlock->textures[Stage] = pTexture;
4353 /* Handle recording of state blocks */
4354 if (This->isRecordingState) {
4355 TRACE("Recording... not performing anything\n");
4356 return WINED3D_OK;
4359 if(oldTexture == pTexture) {
4360 TRACE("App is setting the same texture again, nothing to do\n");
4361 return WINED3D_OK;
4364 /** NOTE: MSDN says that setTexture increases the reference count,
4365 * and that the application must set the texture back to null (or have a leaky application),
4366 * This means we should pass the refcount up to the parent
4367 *******************************/
4368 if (NULL != This->updateStateBlock->textures[Stage]) {
4369 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4370 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4372 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4373 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4374 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4375 * so the COLOROP and ALPHAOP have to be dirtified.
4377 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4380 if(bindCount == 1) {
4381 new->baseTexture.sampler = Stage;
4383 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4387 if (NULL != oldTexture) {
4388 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4389 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4391 IWineD3DBaseTexture_Release(oldTexture);
4392 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4393 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4394 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4397 if(bindCount && old->baseTexture.sampler == Stage) {
4398 int i;
4399 /* Have to do a search for the other sampler(s) where the texture is bound to
4400 * Shouldn't happen as long as apps bind a texture only to one stage
4402 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4403 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4404 if(This->updateStateBlock->textures[i] == oldTexture) {
4405 old->baseTexture.sampler = i;
4406 break;
4412 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4414 return WINED3D_OK;
4417 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4420 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4422 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4423 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4426 *ppTexture=This->stateBlock->textures[Stage];
4427 if (*ppTexture)
4428 IWineD3DBaseTexture_AddRef(*ppTexture);
4430 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4432 return WINED3D_OK;
4435 /*****
4436 * Get Back Buffer
4437 *****/
4438 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4439 IWineD3DSurface **ppBackBuffer) {
4440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4441 IWineD3DSwapChain *swapChain;
4442 HRESULT hr;
4444 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4446 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4447 if (hr == WINED3D_OK) {
4448 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4449 IWineD3DSwapChain_Release(swapChain);
4450 } else {
4451 *ppBackBuffer = NULL;
4453 return hr;
4456 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4458 WARN("(%p) : stub, calling idirect3d for now\n", This);
4459 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4462 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4464 IWineD3DSwapChain *swapChain;
4465 HRESULT hr;
4467 if(iSwapChain > 0) {
4468 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4469 if (hr == WINED3D_OK) {
4470 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4471 IWineD3DSwapChain_Release(swapChain);
4472 } else {
4473 FIXME("(%p) Error getting display mode\n", This);
4475 } else {
4476 /* Don't read the real display mode,
4477 but return the stored mode instead. X11 can't change the color
4478 depth, and some apps are pretty angry if they SetDisplayMode from
4479 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4481 Also don't relay to the swapchain because with ddraw it's possible
4482 that there isn't a swapchain at all */
4483 pMode->Width = This->ddraw_width;
4484 pMode->Height = This->ddraw_height;
4485 pMode->Format = This->ddraw_format;
4486 pMode->RefreshRate = 0;
4487 hr = WINED3D_OK;
4490 return hr;
4493 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4495 TRACE("(%p)->(%p)\n", This, hWnd);
4497 if(This->ddraw_fullscreen) {
4498 if(This->ddraw_window && This->ddraw_window != hWnd) {
4499 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4501 if(hWnd && This->ddraw_window != hWnd) {
4502 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4506 This->ddraw_window = hWnd;
4507 return WINED3D_OK;
4510 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4511 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4512 TRACE("(%p)->(%p)\n", This, hWnd);
4514 *hWnd = This->ddraw_window;
4515 return WINED3D_OK;
4518 /*****
4519 * Stateblock related functions
4520 *****/
4522 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4524 IWineD3DStateBlockImpl *object;
4525 HRESULT temp_result;
4526 int i;
4528 TRACE("(%p)\n", This);
4530 if (This->isRecordingState) {
4531 return WINED3DERR_INVALIDCALL;
4534 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4535 if (NULL == object ) {
4536 FIXME("(%p)Error allocating memory for stateblock\n", This);
4537 return E_OUTOFMEMORY;
4539 TRACE("(%p) created object %p\n", This, object);
4540 object->wineD3DDevice= This;
4541 /** FIXME: object->parent = parent; **/
4542 object->parent = NULL;
4543 object->blockType = WINED3DSBT_RECORDED;
4544 object->ref = 1;
4545 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4547 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4548 list_init(&object->lightMap[i]);
4551 temp_result = allocate_shader_constants(object);
4552 if (WINED3D_OK != temp_result)
4553 return temp_result;
4555 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4556 This->updateStateBlock = object;
4557 This->isRecordingState = TRUE;
4559 TRACE("(%p) recording stateblock %p\n",This , object);
4560 return WINED3D_OK;
4563 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4565 unsigned int i, j;
4566 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4568 if (!This->isRecordingState) {
4569 FIXME("(%p) not recording! returning error\n", This);
4570 *ppStateBlock = NULL;
4571 return WINED3DERR_INVALIDCALL;
4574 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4575 if(object->changed.renderState[i]) {
4576 object->contained_render_states[object->num_contained_render_states] = i;
4577 object->num_contained_render_states++;
4580 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4581 if(object->changed.transform[i]) {
4582 object->contained_transform_states[object->num_contained_transform_states] = i;
4583 object->num_contained_transform_states++;
4586 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4587 if(object->changed.vertexShaderConstantsF[i]) {
4588 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4589 object->num_contained_vs_consts_f++;
4592 for(i = 0; i < MAX_CONST_I; i++) {
4593 if(object->changed.vertexShaderConstantsI[i]) {
4594 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4595 object->num_contained_vs_consts_i++;
4598 for(i = 0; i < MAX_CONST_B; i++) {
4599 if(object->changed.vertexShaderConstantsB[i]) {
4600 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4601 object->num_contained_vs_consts_b++;
4604 for(i = 0; i < MAX_CONST_I; i++) {
4605 if(object->changed.pixelShaderConstantsI[i]) {
4606 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4607 object->num_contained_ps_consts_i++;
4610 for(i = 0; i < MAX_CONST_B; i++) {
4611 if(object->changed.pixelShaderConstantsB[i]) {
4612 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4613 object->num_contained_ps_consts_b++;
4616 for(i = 0; i < MAX_TEXTURES; i++) {
4617 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4618 if(object->changed.textureState[i][j]) {
4619 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4620 object->contained_tss_states[object->num_contained_tss_states].state = j;
4621 object->num_contained_tss_states++;
4625 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4626 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4627 if(object->changed.samplerState[i][j]) {
4628 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4629 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4630 object->num_contained_sampler_states++;
4635 *ppStateBlock = (IWineD3DStateBlock*) object;
4636 This->isRecordingState = FALSE;
4637 This->updateStateBlock = This->stateBlock;
4638 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4639 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4640 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4641 return WINED3D_OK;
4644 /*****
4645 * Scene related functions
4646 *****/
4647 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4648 /* At the moment we have no need for any functionality at the beginning
4649 of a scene */
4650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4651 TRACE("(%p)\n", This);
4653 if(This->inScene) {
4654 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4655 return WINED3DERR_INVALIDCALL;
4657 This->inScene = TRUE;
4658 return WINED3D_OK;
4661 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4663 TRACE("(%p)\n", This);
4665 if(!This->inScene) {
4666 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4667 return WINED3DERR_INVALIDCALL;
4670 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4671 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4673 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4674 ENTER_GL();
4675 glFlush();
4676 checkGLcall("glFlush");
4677 LEAVE_GL();
4679 This->inScene = FALSE;
4680 return WINED3D_OK;
4683 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4684 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4685 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4687 IWineD3DSwapChain *swapChain = NULL;
4688 int i;
4689 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4691 TRACE("(%p) Presenting the frame\n", This);
4693 for(i = 0 ; i < swapchains ; i ++) {
4695 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4696 TRACE("presentinng chain %d, %p\n", i, swapChain);
4697 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4698 IWineD3DSwapChain_Release(swapChain);
4701 return WINED3D_OK;
4704 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4705 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4707 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4709 GLbitfield glMask = 0;
4710 unsigned int i;
4711 CONST WINED3DRECT* curRect;
4713 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4714 Count, pRects, Flags, Color, Z, Stencil);
4716 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4717 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4718 /* TODO: What about depth stencil buffers without stencil bits? */
4719 return WINED3DERR_INVALIDCALL;
4722 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4723 * and not the last active one.
4725 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4726 ENTER_GL();
4728 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4729 apply_fbo_state(iface);
4732 if (Count > 0 && pRects) {
4733 curRect = pRects;
4734 } else {
4735 curRect = NULL;
4738 /* Only set the values up once, as they are not changing */
4739 if (Flags & WINED3DCLEAR_STENCIL) {
4740 glClearStencil(Stencil);
4741 checkGLcall("glClearStencil");
4742 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4743 glStencilMask(0xFFFFFFFF);
4746 if (Flags & WINED3DCLEAR_ZBUFFER) {
4747 glDepthMask(GL_TRUE);
4748 glClearDepth(Z);
4749 checkGLcall("glClearDepth");
4750 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4751 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4754 if (Flags & WINED3DCLEAR_TARGET) {
4755 TRACE("Clearing screen with glClear to color %x\n", Color);
4756 glClearColor(D3DCOLOR_R(Color),
4757 D3DCOLOR_G(Color),
4758 D3DCOLOR_B(Color),
4759 D3DCOLOR_A(Color));
4760 checkGLcall("glClearColor");
4762 /* Clear ALL colors! */
4763 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4764 glMask = glMask | GL_COLOR_BUFFER_BIT;
4767 if (!curRect) {
4768 /* In drawable flag is set below */
4770 if (This->render_offscreen) {
4771 glScissor(This->stateBlock->viewport.X,
4772 This->stateBlock->viewport.Y,
4773 This->stateBlock->viewport.Width,
4774 This->stateBlock->viewport.Height);
4775 } else {
4776 glScissor(This->stateBlock->viewport.X,
4777 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4778 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4779 This->stateBlock->viewport.Width,
4780 This->stateBlock->viewport.Height);
4782 checkGLcall("glScissor");
4783 glClear(glMask);
4784 checkGLcall("glClear");
4785 } else {
4786 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4787 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4789 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4790 curRect[0].x2 < target->currentDesc.Width ||
4791 curRect[0].y2 < target->currentDesc.Height) {
4792 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4793 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4797 /* Now process each rect in turn */
4798 for (i = 0; i < Count; i++) {
4799 /* Note gl uses lower left, width/height */
4800 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4801 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4802 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4803 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4805 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4806 * The rectangle is not cleared, no error is returned, but further rectanlges are
4807 * still cleared if they are valid
4809 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4810 TRACE("Rectangle with negative dimensions, ignoring\n");
4811 continue;
4814 if(This->render_offscreen) {
4815 glScissor(curRect[i].x1, curRect[i].y1,
4816 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4817 } else {
4818 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4819 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4821 checkGLcall("glScissor");
4823 glClear(glMask);
4824 checkGLcall("glClear");
4828 /* Restore the old values (why..?) */
4829 if (Flags & WINED3DCLEAR_STENCIL) {
4830 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4832 if (Flags & WINED3DCLEAR_TARGET) {
4833 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4834 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4835 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4836 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4837 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4840 LEAVE_GL();
4842 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4843 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4845 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
4846 /* TODO: Move the fbo logic into ModifyLocation() */
4847 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4848 target->Flags |= SFLAG_INTEXTURE;
4850 return WINED3D_OK;
4853 /*****
4854 * Drawing functions
4855 *****/
4856 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4857 UINT PrimitiveCount) {
4859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4861 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4862 debug_d3dprimitivetype(PrimitiveType),
4863 StartVertex, PrimitiveCount);
4865 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4866 if(This->stateBlock->streamIsUP) {
4867 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4868 This->stateBlock->streamIsUP = FALSE;
4871 if(This->stateBlock->loadBaseVertexIndex != 0) {
4872 This->stateBlock->loadBaseVertexIndex = 0;
4873 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4875 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4876 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4877 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4878 return WINED3D_OK;
4881 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4882 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4883 WINED3DPRIMITIVETYPE PrimitiveType,
4884 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4887 UINT idxStride = 2;
4888 IWineD3DIndexBuffer *pIB;
4889 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4890 GLuint vbo;
4892 pIB = This->stateBlock->pIndexData;
4893 if (!pIB) {
4894 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4895 * without an index buffer set. (The first time at least...)
4896 * D3D8 simply dies, but I doubt it can do much harm to return
4897 * D3DERR_INVALIDCALL there as well. */
4898 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4899 return WINED3DERR_INVALIDCALL;
4902 if(This->stateBlock->streamIsUP) {
4903 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4904 This->stateBlock->streamIsUP = FALSE;
4906 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4908 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4909 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4910 minIndex, NumVertices, startIndex, primCount);
4912 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4913 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4914 idxStride = 2;
4915 } else {
4916 idxStride = 4;
4919 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4920 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4921 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4924 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4925 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4927 return WINED3D_OK;
4930 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4931 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4932 UINT VertexStreamZeroStride) {
4933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4934 IWineD3DVertexBuffer *vb;
4936 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4937 debug_d3dprimitivetype(PrimitiveType),
4938 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4940 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4941 vb = This->stateBlock->streamSource[0];
4942 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4943 if(vb) IWineD3DVertexBuffer_Release(vb);
4944 This->stateBlock->streamOffset[0] = 0;
4945 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4946 This->stateBlock->streamIsUP = TRUE;
4947 This->stateBlock->loadBaseVertexIndex = 0;
4949 /* TODO: Only mark dirty if drawing from a different UP address */
4950 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4952 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4953 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4955 /* MSDN specifies stream zero settings must be set to NULL */
4956 This->stateBlock->streamStride[0] = 0;
4957 This->stateBlock->streamSource[0] = NULL;
4959 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4960 * the new stream sources or use UP drawing again
4962 return WINED3D_OK;
4965 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4966 UINT MinVertexIndex, UINT NumVertices,
4967 UINT PrimitiveCount, CONST void* pIndexData,
4968 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4969 UINT VertexStreamZeroStride) {
4970 int idxStride;
4971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4972 IWineD3DVertexBuffer *vb;
4973 IWineD3DIndexBuffer *ib;
4975 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4976 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4977 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4978 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4980 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4981 idxStride = 2;
4982 } else {
4983 idxStride = 4;
4986 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4987 vb = This->stateBlock->streamSource[0];
4988 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4989 if(vb) IWineD3DVertexBuffer_Release(vb);
4990 This->stateBlock->streamIsUP = TRUE;
4991 This->stateBlock->streamOffset[0] = 0;
4992 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4994 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4995 This->stateBlock->baseVertexIndex = 0;
4996 This->stateBlock->loadBaseVertexIndex = 0;
4997 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4998 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4999 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5001 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5003 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5004 This->stateBlock->streamSource[0] = NULL;
5005 This->stateBlock->streamStride[0] = 0;
5006 ib = This->stateBlock->pIndexData;
5007 if(ib) {
5008 IWineD3DIndexBuffer_Release(ib);
5009 This->stateBlock->pIndexData = NULL;
5011 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5012 * SetStreamSource to specify a vertex buffer
5015 return WINED3D_OK;
5018 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5021 /* Mark the state dirty until we have nicer tracking
5022 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5023 * that value.
5025 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5026 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5027 This->stateBlock->baseVertexIndex = 0;
5028 This->up_strided = DrawPrimStrideData;
5029 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5030 This->up_strided = NULL;
5031 return WINED3D_OK;
5034 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5036 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5038 /* Mark the state dirty until we have nicer tracking
5039 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5040 * that value.
5042 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5043 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5044 This->stateBlock->streamIsUP = TRUE;
5045 This->stateBlock->baseVertexIndex = 0;
5046 This->up_strided = DrawPrimStrideData;
5047 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5048 This->up_strided = NULL;
5049 return WINED3D_OK;
5052 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5053 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5054 * not callable by the app directly no parameter validation checks are needed here.
5056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5057 WINED3DLOCKED_BOX src;
5058 WINED3DLOCKED_BOX dst;
5059 HRESULT hr;
5060 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5062 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5063 * dirtification to improve loading performance.
5065 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5066 if(FAILED(hr)) return hr;
5067 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5068 if(FAILED(hr)) {
5069 IWineD3DVolume_UnlockBox(pSourceVolume);
5070 return hr;
5073 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5075 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5076 if(FAILED(hr)) {
5077 IWineD3DVolume_UnlockBox(pSourceVolume);
5078 } else {
5079 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5081 return hr;
5084 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5085 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5086 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5087 HRESULT hr = WINED3D_OK;
5088 WINED3DRESOURCETYPE sourceType;
5089 WINED3DRESOURCETYPE destinationType;
5090 int i ,levels;
5092 /* TODO: think about moving the code into IWineD3DBaseTexture */
5094 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5096 /* verify that the source and destination textures aren't NULL */
5097 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5098 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5099 This, pSourceTexture, pDestinationTexture);
5100 hr = WINED3DERR_INVALIDCALL;
5103 if (pSourceTexture == pDestinationTexture) {
5104 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5105 This, pSourceTexture, pDestinationTexture);
5106 hr = WINED3DERR_INVALIDCALL;
5108 /* Verify that the source and destination textures are the same type */
5109 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5110 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5112 if (sourceType != destinationType) {
5113 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5114 This);
5115 hr = WINED3DERR_INVALIDCALL;
5118 /* check that both textures have the identical numbers of levels */
5119 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5120 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5121 hr = WINED3DERR_INVALIDCALL;
5124 if (WINED3D_OK == hr) {
5126 /* Make sure that the destination texture is loaded */
5127 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5129 /* Update every surface level of the texture */
5130 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5132 switch (sourceType) {
5133 case WINED3DRTYPE_TEXTURE:
5135 IWineD3DSurface *srcSurface;
5136 IWineD3DSurface *destSurface;
5138 for (i = 0 ; i < levels ; ++i) {
5139 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5140 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5141 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5142 IWineD3DSurface_Release(srcSurface);
5143 IWineD3DSurface_Release(destSurface);
5144 if (WINED3D_OK != hr) {
5145 WARN("(%p) : Call to update surface failed\n", This);
5146 return hr;
5150 break;
5151 case WINED3DRTYPE_CUBETEXTURE:
5153 IWineD3DSurface *srcSurface;
5154 IWineD3DSurface *destSurface;
5155 WINED3DCUBEMAP_FACES faceType;
5157 for (i = 0 ; i < levels ; ++i) {
5158 /* Update each cube face */
5159 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5160 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5161 if (WINED3D_OK != hr) {
5162 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5163 } else {
5164 TRACE("Got srcSurface %p\n", srcSurface);
5166 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5167 if (WINED3D_OK != hr) {
5168 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5169 } else {
5170 TRACE("Got desrSurface %p\n", destSurface);
5172 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5173 IWineD3DSurface_Release(srcSurface);
5174 IWineD3DSurface_Release(destSurface);
5175 if (WINED3D_OK != hr) {
5176 WARN("(%p) : Call to update surface failed\n", This);
5177 return hr;
5182 break;
5184 case WINED3DRTYPE_VOLUMETEXTURE:
5186 IWineD3DVolume *srcVolume = NULL;
5187 IWineD3DVolume *destVolume = NULL;
5189 for (i = 0 ; i < levels ; ++i) {
5190 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5191 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5192 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5193 IWineD3DVolume_Release(srcVolume);
5194 IWineD3DVolume_Release(destVolume);
5195 if (WINED3D_OK != hr) {
5196 WARN("(%p) : Call to update volume failed\n", This);
5197 return hr;
5201 break;
5203 default:
5204 FIXME("(%p) : Unsupported source and destination type\n", This);
5205 hr = WINED3DERR_INVALIDCALL;
5209 return hr;
5212 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5213 IWineD3DSwapChain *swapChain;
5214 HRESULT hr;
5215 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5216 if(hr == WINED3D_OK) {
5217 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5218 IWineD3DSwapChain_Release(swapChain);
5220 return hr;
5223 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5225 /* return a sensible default */
5226 *pNumPasses = 1;
5227 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5228 FIXME("(%p) : stub\n", This);
5229 return WINED3D_OK;
5232 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5234 int j;
5235 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5236 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5237 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5238 return WINED3DERR_INVALIDCALL;
5240 for (j = 0; j < 256; ++j) {
5241 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5242 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5243 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5244 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5246 TRACE("(%p) : returning\n", This);
5247 return WINED3D_OK;
5250 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5252 int j;
5253 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5254 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5255 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5256 return WINED3DERR_INVALIDCALL;
5258 for (j = 0; j < 256; ++j) {
5259 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5260 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5261 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5262 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5264 TRACE("(%p) : returning\n", This);
5265 return WINED3D_OK;
5268 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5270 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5271 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5272 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5273 return WINED3DERR_INVALIDCALL;
5275 /*TODO: stateblocks */
5276 This->currentPalette = PaletteNumber;
5277 TRACE("(%p) : returning\n", This);
5278 return WINED3D_OK;
5281 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5283 if (PaletteNumber == NULL) {
5284 WARN("(%p) : returning Invalid Call\n", This);
5285 return WINED3DERR_INVALIDCALL;
5287 /*TODO: stateblocks */
5288 *PaletteNumber = This->currentPalette;
5289 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5290 return WINED3D_OK;
5293 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5295 static BOOL showFixmes = TRUE;
5296 if (showFixmes) {
5297 FIXME("(%p) : stub\n", This);
5298 showFixmes = FALSE;
5301 This->softwareVertexProcessing = bSoftware;
5302 return WINED3D_OK;
5306 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5308 static BOOL showFixmes = TRUE;
5309 if (showFixmes) {
5310 FIXME("(%p) : stub\n", This);
5311 showFixmes = FALSE;
5313 return This->softwareVertexProcessing;
5317 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5319 IWineD3DSwapChain *swapChain;
5320 HRESULT hr;
5322 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5324 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5325 if(hr == WINED3D_OK){
5326 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5327 IWineD3DSwapChain_Release(swapChain);
5328 }else{
5329 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5331 return hr;
5335 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5337 static BOOL showfixmes = TRUE;
5338 if(nSegments != 0.0f) {
5339 if( showfixmes) {
5340 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5341 showfixmes = FALSE;
5344 return WINED3D_OK;
5347 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5349 static BOOL showfixmes = TRUE;
5350 if( showfixmes) {
5351 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5352 showfixmes = FALSE;
5354 return 0.0f;
5357 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5359 /** TODO: remove casts to IWineD3DSurfaceImpl
5360 * NOTE: move code to surface to accomplish this
5361 ****************************************/
5362 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5363 int srcWidth, srcHeight;
5364 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5365 WINED3DFORMAT destFormat, srcFormat;
5366 UINT destSize;
5367 int srcLeft, destLeft, destTop;
5368 WINED3DPOOL srcPool, destPool;
5369 int offset = 0;
5370 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5371 glDescriptor *glDescription = NULL;
5372 GLenum dummy;
5373 int bpp;
5374 CONVERT_TYPES convert = NO_CONVERSION;
5376 WINED3DSURFACE_DESC winedesc;
5378 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5379 memset(&winedesc, 0, sizeof(winedesc));
5380 winedesc.Width = &srcSurfaceWidth;
5381 winedesc.Height = &srcSurfaceHeight;
5382 winedesc.Pool = &srcPool;
5383 winedesc.Format = &srcFormat;
5385 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5387 winedesc.Width = &destSurfaceWidth;
5388 winedesc.Height = &destSurfaceHeight;
5389 winedesc.Pool = &destPool;
5390 winedesc.Format = &destFormat;
5391 winedesc.Size = &destSize;
5393 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5395 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5396 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5397 return WINED3DERR_INVALIDCALL;
5400 /* This call loads the opengl surface directly, instead of copying the surface to the
5401 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5402 * copy in sysmem and use regular surface loading.
5404 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5405 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5406 if(convert != NO_CONVERSION) {
5407 return IWineD3DSurface_BltFast(pDestinationSurface,
5408 pDestPoint ? pDestPoint->x : 0,
5409 pDestPoint ? pDestPoint->y : 0,
5410 pSourceSurface, (RECT *) pSourceRect, 0);
5413 if (destFormat == WINED3DFMT_UNKNOWN) {
5414 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5415 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5417 /* Get the update surface description */
5418 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5421 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5423 ENTER_GL();
5425 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5426 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5427 checkGLcall("glActiveTextureARB");
5430 /* Make sure the surface is loaded and up to date */
5431 IWineD3DSurface_PreLoad(pDestinationSurface);
5433 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5435 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5436 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5437 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5438 srcLeft = pSourceRect ? pSourceRect->left : 0;
5439 destLeft = pDestPoint ? pDestPoint->x : 0;
5440 destTop = pDestPoint ? pDestPoint->y : 0;
5443 /* This function doesn't support compressed textures
5444 the pitch is just bytesPerPixel * width */
5445 if(srcWidth != srcSurfaceWidth || srcLeft ){
5446 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5447 offset += srcLeft * pSrcSurface->bytesPerPixel;
5448 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5450 /* TODO DXT formats */
5452 if(pSourceRect != NULL && pSourceRect->top != 0){
5453 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5455 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5456 ,This
5457 ,glDescription->level
5458 ,destLeft
5459 ,destTop
5460 ,srcWidth
5461 ,srcHeight
5462 ,glDescription->glFormat
5463 ,glDescription->glType
5464 ,IWineD3DSurface_GetData(pSourceSurface)
5467 /* Sanity check */
5468 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5470 /* need to lock the surface to get the data */
5471 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5474 /* TODO: Cube and volume support */
5475 if(rowoffset != 0){
5476 /* not a whole row so we have to do it a line at a time */
5477 int j;
5479 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5480 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5482 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5484 glTexSubImage2D(glDescription->target
5485 ,glDescription->level
5486 ,destLeft
5488 ,srcWidth
5490 ,glDescription->glFormat
5491 ,glDescription->glType
5492 ,data /* could be quicker using */
5494 data += rowoffset;
5497 } else { /* Full width, so just write out the whole texture */
5499 if (WINED3DFMT_DXT1 == destFormat ||
5500 WINED3DFMT_DXT2 == destFormat ||
5501 WINED3DFMT_DXT3 == destFormat ||
5502 WINED3DFMT_DXT4 == destFormat ||
5503 WINED3DFMT_DXT5 == destFormat) {
5504 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5505 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5506 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5507 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5508 } if (destFormat != srcFormat) {
5509 FIXME("Updating mixed format compressed texture is not curretly support\n");
5510 } else {
5511 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5512 glDescription->level,
5513 glDescription->glFormatInternal,
5514 srcWidth,
5515 srcHeight,
5517 destSize,
5518 IWineD3DSurface_GetData(pSourceSurface));
5520 } else {
5521 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5525 } else {
5526 glTexSubImage2D(glDescription->target
5527 ,glDescription->level
5528 ,destLeft
5529 ,destTop
5530 ,srcWidth
5531 ,srcHeight
5532 ,glDescription->glFormat
5533 ,glDescription->glType
5534 ,IWineD3DSurface_GetData(pSourceSurface)
5538 checkGLcall("glTexSubImage2D");
5540 LEAVE_GL();
5542 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5543 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5545 return WINED3D_OK;
5548 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5550 struct WineD3DRectPatch *patch;
5551 unsigned int i;
5552 struct list *e;
5553 BOOL found;
5554 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5556 if(!(Handle || pRectPatchInfo)) {
5557 /* TODO: Write a test for the return value, thus the FIXME */
5558 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5559 return WINED3DERR_INVALIDCALL;
5562 if(Handle) {
5563 i = PATCHMAP_HASHFUNC(Handle);
5564 found = FALSE;
5565 LIST_FOR_EACH(e, &This->patches[i]) {
5566 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5567 if(patch->Handle == Handle) {
5568 found = TRUE;
5569 break;
5573 if(!found) {
5574 TRACE("Patch does not exist. Creating a new one\n");
5575 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5576 patch->Handle = Handle;
5577 list_add_head(&This->patches[i], &patch->entry);
5578 } else {
5579 TRACE("Found existing patch %p\n", patch);
5581 } else {
5582 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5583 * attributes we have to tesselate, read back, and draw. This needs a patch
5584 * management structure instance. Create one.
5586 * A possible improvement is to check if a vertex shader is used, and if not directly
5587 * draw the patch.
5589 FIXME("Drawing an uncached patch. This is slow\n");
5590 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5593 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5594 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5595 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5596 HRESULT hr;
5597 TRACE("Tesselation density or patch info changed, retesselating\n");
5599 if(pRectPatchInfo) {
5600 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5602 patch->numSegs[0] = pNumSegs[0];
5603 patch->numSegs[1] = pNumSegs[1];
5604 patch->numSegs[2] = pNumSegs[2];
5605 patch->numSegs[3] = pNumSegs[3];
5607 hr = tesselate_rectpatch(This, patch);
5608 if(FAILED(hr)) {
5609 WARN("Patch tesselation failed\n");
5611 /* Do not release the handle to store the params of the patch */
5612 if(!Handle) {
5613 HeapFree(GetProcessHeap(), 0, patch);
5615 return hr;
5619 This->currentPatch = patch;
5620 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5621 This->currentPatch = NULL;
5623 /* Destroy uncached patches */
5624 if(!Handle) {
5625 HeapFree(GetProcessHeap(), 0, patch->mem);
5626 HeapFree(GetProcessHeap(), 0, patch);
5628 return WINED3D_OK;
5631 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5632 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5634 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5635 FIXME("(%p) : Stub\n", This);
5636 return WINED3D_OK;
5639 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5641 int i;
5642 struct WineD3DRectPatch *patch;
5643 struct list *e;
5644 TRACE("(%p) Handle(%d)\n", This, Handle);
5646 i = PATCHMAP_HASHFUNC(Handle);
5647 LIST_FOR_EACH(e, &This->patches[i]) {
5648 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5649 if(patch->Handle == Handle) {
5650 TRACE("Deleting patch %p\n", patch);
5651 list_remove(&patch->entry);
5652 HeapFree(GetProcessHeap(), 0, patch->mem);
5653 HeapFree(GetProcessHeap(), 0, patch);
5654 return WINED3D_OK;
5658 /* TODO: Write a test for the return value */
5659 FIXME("Attempt to destroy nonexistant patch\n");
5660 return WINED3DERR_INVALIDCALL;
5663 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5664 HRESULT hr;
5665 IWineD3DSwapChain *swapchain;
5667 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5668 if (SUCCEEDED(hr)) {
5669 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5670 return swapchain;
5673 return NULL;
5676 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5679 if (!*fbo) {
5680 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5681 checkGLcall("glGenFramebuffersEXT()");
5683 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5684 checkGLcall("glBindFramebuffer()");
5687 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5688 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5689 IWineD3DBaseTextureImpl *texture_impl;
5690 GLenum texttarget, target;
5691 GLint old_binding;
5693 texttarget = surface_impl->glDescription.target;
5694 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5695 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5697 IWineD3DSurface_PreLoad(surface);
5699 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5700 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5701 glBindTexture(target, old_binding);
5703 /* Update base texture states array */
5704 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5705 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5706 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5707 if (texture_impl->baseTexture.bindCount) {
5708 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5711 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5714 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5715 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5717 checkGLcall("attach_surface_fbo");
5720 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5722 IWineD3DSwapChain *swapchain;
5724 swapchain = get_swapchain(surface);
5725 if (swapchain) {
5726 GLenum buffer;
5728 TRACE("Surface %p is onscreen\n", surface);
5730 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5731 buffer = surface_get_gl_buffer(surface, swapchain);
5732 glDrawBuffer(buffer);
5733 checkGLcall("glDrawBuffer()");
5734 } else {
5735 TRACE("Surface %p is offscreen\n", surface);
5736 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5737 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5740 if (rect) {
5741 glEnable(GL_SCISSOR_TEST);
5742 if(!swapchain) {
5743 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5744 } else {
5745 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5746 rect->x2 - rect->x1, rect->y2 - rect->y1);
5748 checkGLcall("glScissor");
5749 } else {
5750 glDisable(GL_SCISSOR_TEST);
5752 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5754 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5755 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5757 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5758 glClear(GL_COLOR_BUFFER_BIT);
5759 checkGLcall("glClear");
5761 if (This->render_offscreen) {
5762 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5763 } else {
5764 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5765 checkGLcall("glBindFramebuffer()");
5768 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5769 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5770 glDrawBuffer(GL_BACK);
5771 checkGLcall("glDrawBuffer()");
5775 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5776 unsigned int r, g, b, a;
5777 DWORD ret;
5779 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
5780 destfmt == WINED3DFMT_R8G8B8)
5781 return color;
5783 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5785 a = (color & 0xff000000) >> 24;
5786 r = (color & 0x00ff0000) >> 16;
5787 g = (color & 0x0000ff00) >> 8;
5788 b = (color & 0x000000ff) >> 0;
5790 switch(destfmt)
5792 case WINED3DFMT_R5G6B5:
5793 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5794 r = (r * 32) / 256;
5795 g = (g * 64) / 256;
5796 b = (b * 32) / 256;
5797 ret = r << 11;
5798 ret |= g << 5;
5799 ret |= b;
5800 TRACE("Returning %08x\n", ret);
5801 return ret;
5803 case WINED3DFMT_X1R5G5B5:
5804 case WINED3DFMT_A1R5G5B5:
5805 a = (a * 2) / 256;
5806 r = (r * 32) / 256;
5807 g = (g * 32) / 256;
5808 b = (b * 32) / 256;
5809 ret = a << 15;
5810 ret |= r << 10;
5811 ret |= g << 5;
5812 ret |= b << 0;
5813 TRACE("Returning %08x\n", ret);
5814 return ret;
5816 case WINED3DFMT_A8:
5817 TRACE("Returning %08x\n", a);
5818 return a;
5820 case WINED3DFMT_X4R4G4B4:
5821 case WINED3DFMT_A4R4G4B4:
5822 a = (a * 16) / 256;
5823 r = (r * 16) / 256;
5824 g = (g * 16) / 256;
5825 b = (b * 16) / 256;
5826 ret = a << 12;
5827 ret |= r << 8;
5828 ret |= g << 4;
5829 ret |= b << 0;
5830 TRACE("Returning %08x\n", ret);
5831 return ret;
5833 case WINED3DFMT_R3G3B2:
5834 r = (r * 8) / 256;
5835 g = (g * 8) / 256;
5836 b = (b * 4) / 256;
5837 ret = r << 5;
5838 ret |= g << 2;
5839 ret |= b << 0;
5840 TRACE("Returning %08x\n", ret);
5841 return ret;
5843 case WINED3DFMT_X8B8G8R8:
5844 case WINED3DFMT_A8B8G8R8:
5845 ret = a << 24;
5846 ret |= b << 16;
5847 ret |= g << 8;
5848 ret |= r << 0;
5849 TRACE("Returning %08x\n", ret);
5850 return ret;
5852 case WINED3DFMT_A2R10G10B10:
5853 a = (a * 4) / 256;
5854 r = (r * 1024) / 256;
5855 g = (g * 1024) / 256;
5856 b = (b * 1024) / 256;
5857 ret = a << 30;
5858 ret |= r << 20;
5859 ret |= g << 10;
5860 ret |= b << 0;
5861 TRACE("Returning %08x\n", ret);
5862 return ret;
5864 case WINED3DFMT_A2B10G10R10:
5865 a = (a * 4) / 256;
5866 r = (r * 1024) / 256;
5867 g = (g * 1024) / 256;
5868 b = (b * 1024) / 256;
5869 ret = a << 30;
5870 ret |= b << 20;
5871 ret |= g << 10;
5872 ret |= r << 0;
5873 TRACE("Returning %08x\n", ret);
5874 return ret;
5876 default:
5877 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5878 return 0;
5882 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5884 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5885 WINEDDBLTFX BltFx;
5886 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5888 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5889 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5890 return WINED3DERR_INVALIDCALL;
5893 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5894 color_fill_fbo(iface, pSurface, pRect, color);
5895 return WINED3D_OK;
5896 } else {
5897 /* Just forward this to the DirectDraw blitting engine */
5898 memset(&BltFx, 0, sizeof(BltFx));
5899 BltFx.dwSize = sizeof(BltFx);
5900 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
5901 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5905 /* rendertarget and deptth stencil functions */
5906 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5907 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5909 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5910 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5911 return WINED3DERR_INVALIDCALL;
5914 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5915 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5916 /* Note inc ref on returned surface */
5917 if(*ppRenderTarget != NULL)
5918 IWineD3DSurface_AddRef(*ppRenderTarget);
5919 return WINED3D_OK;
5922 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5924 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5925 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5926 IWineD3DSwapChainImpl *Swapchain;
5927 HRESULT hr;
5929 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5931 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5932 if(hr != WINED3D_OK) {
5933 ERR("Can't get the swapchain\n");
5934 return hr;
5937 /* Make sure to release the swapchain */
5938 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5940 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5941 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5942 return WINED3DERR_INVALIDCALL;
5944 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5945 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5946 return WINED3DERR_INVALIDCALL;
5949 if(Swapchain->frontBuffer != Front) {
5950 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5952 if(Swapchain->frontBuffer)
5953 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5954 Swapchain->frontBuffer = Front;
5956 if(Swapchain->frontBuffer) {
5957 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5961 if(Back && !Swapchain->backBuffer) {
5962 /* We need memory for the back buffer array - only one back buffer this way */
5963 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5964 if(!Swapchain->backBuffer) {
5965 ERR("Out of memory\n");
5966 return E_OUTOFMEMORY;
5970 if(Swapchain->backBuffer[0] != Back) {
5971 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5973 /* What to do about the context here in the case of multithreading? Not sure.
5974 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5976 ENTER_GL();
5977 if(!Swapchain->backBuffer[0]) {
5978 /* GL was told to draw to the front buffer at creation,
5979 * undo that
5981 glDrawBuffer(GL_BACK);
5982 checkGLcall("glDrawBuffer(GL_BACK)");
5983 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5984 Swapchain->presentParms.BackBufferCount = 1;
5985 } else if (!Back) {
5986 /* That makes problems - disable for now */
5987 /* glDrawBuffer(GL_FRONT); */
5988 checkGLcall("glDrawBuffer(GL_FRONT)");
5989 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5990 Swapchain->presentParms.BackBufferCount = 0;
5992 LEAVE_GL();
5994 if(Swapchain->backBuffer[0])
5995 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5996 Swapchain->backBuffer[0] = Back;
5998 if(Swapchain->backBuffer[0]) {
5999 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6000 } else {
6001 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6006 return WINED3D_OK;
6009 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6011 *ppZStencilSurface = This->depthStencilBuffer;
6012 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6014 if(*ppZStencilSurface != NULL) {
6015 /* Note inc ref on returned surface */
6016 IWineD3DSurface_AddRef(*ppZStencilSurface);
6017 return WINED3D_OK;
6018 } else {
6019 return WINED3DERR_NOTFOUND;
6023 /* TODO: Handle stencil attachments */
6024 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6026 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6028 TRACE("Set depth stencil to %p\n", depth_stencil);
6030 if (depth_stencil_impl) {
6031 if (depth_stencil_impl->current_renderbuffer) {
6032 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6033 checkGLcall("glFramebufferRenderbufferEXT()");
6034 } else {
6035 IWineD3DBaseTextureImpl *texture_impl;
6036 GLenum texttarget, target;
6037 GLint old_binding = 0;
6039 texttarget = depth_stencil_impl->glDescription.target;
6040 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
6041 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6043 IWineD3DSurface_PreLoad(depth_stencil);
6045 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6046 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6047 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6048 glBindTexture(target, old_binding);
6050 /* Update base texture states array */
6051 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6052 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6053 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6054 if (texture_impl->baseTexture.bindCount) {
6055 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6058 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6061 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6062 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6063 checkGLcall("glFramebufferTexture2DEXT()");
6065 } else {
6066 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6067 checkGLcall("glFramebufferTexture2DEXT()");
6071 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6072 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6073 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6075 TRACE("Set render target %u to %p\n", idx, render_target);
6077 if (rtimpl) {
6078 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6079 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6080 } else {
6081 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6082 checkGLcall("glFramebufferTexture2DEXT()");
6084 This->draw_buffers[idx] = GL_NONE;
6088 static void check_fbo_status(IWineD3DDevice *iface) {
6089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6090 GLenum status;
6092 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6093 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6094 TRACE("FBO complete\n");
6095 } else {
6096 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6098 /* Dump the FBO attachments */
6099 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
6100 IWineD3DSurfaceImpl *attachment;
6101 int i;
6103 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6104 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6105 if (attachment) {
6106 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6107 attachment->pow2Width, attachment->pow2Height);
6110 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6111 if (attachment) {
6112 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6113 attachment->pow2Width, attachment->pow2Height);
6119 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6121 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6122 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6124 if (!ds_impl) return FALSE;
6126 if (ds_impl->current_renderbuffer) {
6127 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6128 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6131 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6132 rt_impl->pow2Height != ds_impl->pow2Height);
6135 void apply_fbo_state(IWineD3DDevice *iface) {
6136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6137 unsigned int i;
6139 if (This->render_offscreen) {
6140 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6142 /* Apply render targets */
6143 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6144 IWineD3DSurface *render_target = This->render_targets[i];
6145 if (This->fbo_color_attachments[i] != render_target) {
6146 set_render_target_fbo(iface, i, render_target);
6147 This->fbo_color_attachments[i] = render_target;
6151 /* Apply depth targets */
6152 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6153 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6154 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6156 if (This->stencilBufferTarget) {
6157 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6159 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6160 This->fbo_depth_attachment = This->stencilBufferTarget;
6163 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6164 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6165 checkGLcall("glDrawBuffers()");
6166 } else {
6167 glDrawBuffer(This->draw_buffers[0]);
6168 checkGLcall("glDrawBuffer()");
6170 } else {
6171 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6174 check_fbo_status(iface);
6177 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6178 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6180 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6181 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6182 GLenum gl_filter;
6184 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6185 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6186 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6187 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6189 switch (filter) {
6190 case WINED3DTEXF_LINEAR:
6191 gl_filter = GL_LINEAR;
6192 break;
6194 default:
6195 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6196 case WINED3DTEXF_NONE:
6197 case WINED3DTEXF_POINT:
6198 gl_filter = GL_NEAREST;
6199 break;
6202 /* Attach src surface to src fbo */
6203 src_swapchain = get_swapchain(src_surface);
6204 if (src_swapchain) {
6205 GLenum buffer;
6207 TRACE("Source surface %p is onscreen\n", src_surface);
6208 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6210 ENTER_GL();
6211 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6212 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6213 glReadBuffer(buffer);
6214 checkGLcall("glReadBuffer()");
6216 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6217 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6218 } else {
6219 TRACE("Source surface %p is offscreen\n", src_surface);
6220 ENTER_GL();
6221 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6222 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6223 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6224 checkGLcall("glReadBuffer()");
6226 LEAVE_GL();
6228 /* Attach dst surface to dst fbo */
6229 dst_swapchain = get_swapchain(dst_surface);
6230 if (dst_swapchain) {
6231 GLenum buffer;
6233 TRACE("Destination surface %p is onscreen\n", dst_surface);
6234 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6236 ENTER_GL();
6237 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6238 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6239 glDrawBuffer(buffer);
6240 checkGLcall("glDrawBuffer()");
6242 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6243 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6244 } else {
6245 TRACE("Destination surface %p is offscreen\n", dst_surface);
6247 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6248 if(!src_swapchain) {
6249 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6252 ENTER_GL();
6253 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6254 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6255 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6256 checkGLcall("glDrawBuffer()");
6258 glDisable(GL_SCISSOR_TEST);
6259 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6261 if (flip) {
6262 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6263 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6264 checkGLcall("glBlitFramebuffer()");
6265 } else {
6266 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6267 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6268 checkGLcall("glBlitFramebuffer()");
6271 if (This->render_offscreen) {
6272 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6273 } else {
6274 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6275 checkGLcall("glBindFramebuffer()");
6278 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6279 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6280 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6281 glDrawBuffer(GL_BACK);
6282 checkGLcall("glDrawBuffer()");
6284 LEAVE_GL();
6287 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6289 WINED3DVIEWPORT viewport;
6291 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6293 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6294 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6295 return WINED3DERR_INVALIDCALL;
6298 /* MSDN says that null disables the render target
6299 but a device must always be associated with a render target
6300 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6302 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6303 for more details
6305 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6306 FIXME("Trying to set render target 0 to NULL\n");
6307 return WINED3DERR_INVALIDCALL;
6309 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
6310 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);
6311 return WINED3DERR_INVALIDCALL;
6314 /* If we are trying to set what we already have, don't bother */
6315 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6316 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6317 return WINED3D_OK;
6319 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6320 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6321 This->render_targets[RenderTargetIndex] = pRenderTarget;
6323 /* Render target 0 is special */
6324 if(RenderTargetIndex == 0) {
6325 /* Finally, reset the viewport as the MSDN states. */
6326 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6327 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6328 viewport.X = 0;
6329 viewport.Y = 0;
6330 viewport.MaxZ = 1.0f;
6331 viewport.MinZ = 0.0f;
6332 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6333 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6334 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6336 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6338 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6339 * ctx properly.
6340 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6341 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6343 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6345 return WINED3D_OK;
6348 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6350 HRESULT hr = WINED3D_OK;
6351 IWineD3DSurface *tmp;
6353 TRACE("(%p) Swapping z-buffer\n",This);
6355 if (pNewZStencil == This->stencilBufferTarget) {
6356 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6357 } else {
6358 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6359 * depending on the renter target implementation being used.
6360 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6361 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6362 * stencil buffer and incure an extra memory overhead
6363 ******************************************************/
6365 tmp = This->stencilBufferTarget;
6366 This->stencilBufferTarget = pNewZStencil;
6367 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6368 /* should we be calling the parent or the wined3d surface? */
6369 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6370 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6371 hr = WINED3D_OK;
6373 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6374 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6376 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6377 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6381 return hr;
6384 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6385 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6387 /* TODO: the use of Impl is deprecated. */
6388 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6389 WINED3DLOCKED_RECT lockedRect;
6391 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6393 /* some basic validation checks */
6394 if(This->cursorTexture) {
6395 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6396 ENTER_GL();
6397 glDeleteTextures(1, &This->cursorTexture);
6398 LEAVE_GL();
6399 This->cursorTexture = 0;
6402 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6403 This->haveHardwareCursor = TRUE;
6404 else
6405 This->haveHardwareCursor = FALSE;
6407 if(pCursorBitmap) {
6408 WINED3DLOCKED_RECT rect;
6410 /* MSDN: Cursor must be A8R8G8B8 */
6411 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6412 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6413 return WINED3DERR_INVALIDCALL;
6416 /* MSDN: Cursor must be smaller than the display mode */
6417 if(pSur->currentDesc.Width > This->ddraw_width ||
6418 pSur->currentDesc.Height > This->ddraw_height) {
6419 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);
6420 return WINED3DERR_INVALIDCALL;
6423 if (!This->haveHardwareCursor) {
6424 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6426 /* Do not store the surface's pointer because the application may
6427 * release it after setting the cursor image. Windows doesn't
6428 * addref the set surface, so we can't do this either without
6429 * creating circular refcount dependencies. Copy out the gl texture
6430 * instead.
6432 This->cursorWidth = pSur->currentDesc.Width;
6433 This->cursorHeight = pSur->currentDesc.Height;
6434 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6436 const GlPixelFormatDesc *glDesc;
6437 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6438 char *mem, *bits = (char *)rect.pBits;
6439 GLint intfmt = glDesc->glInternal;
6440 GLint format = glDesc->glFormat;
6441 GLint type = glDesc->glType;
6442 INT height = This->cursorHeight;
6443 INT width = This->cursorWidth;
6444 INT bpp = tableEntry->bpp;
6445 INT i;
6447 /* Reformat the texture memory (pitch and width can be
6448 * different) */
6449 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6450 for(i = 0; i < height; i++)
6451 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6452 IWineD3DSurface_UnlockRect(pCursorBitmap);
6453 ENTER_GL();
6455 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6456 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6457 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6460 /* Make sure that a proper texture unit is selected */
6461 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6462 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6463 checkGLcall("glActiveTextureARB");
6465 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6466 /* Create a new cursor texture */
6467 glGenTextures(1, &This->cursorTexture);
6468 checkGLcall("glGenTextures");
6469 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6470 checkGLcall("glBindTexture");
6471 /* Copy the bitmap memory into the cursor texture */
6472 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6473 HeapFree(GetProcessHeap(), 0, mem);
6474 checkGLcall("glTexImage2D");
6476 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6477 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6478 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6481 LEAVE_GL();
6483 else
6485 FIXME("A cursor texture was not returned.\n");
6486 This->cursorTexture = 0;
6489 else
6491 /* Draw a hardware cursor */
6492 ICONINFO cursorInfo;
6493 HCURSOR cursor;
6494 /* Create and clear maskBits because it is not needed for
6495 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6496 * chunks. */
6497 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6498 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6499 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6500 WINED3DLOCK_NO_DIRTY_UPDATE |
6501 WINED3DLOCK_READONLY
6503 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6504 pSur->currentDesc.Height);
6506 cursorInfo.fIcon = FALSE;
6507 cursorInfo.xHotspot = XHotSpot;
6508 cursorInfo.yHotspot = YHotSpot;
6509 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6510 pSur->currentDesc.Height, 1,
6511 1, &maskBits);
6512 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6513 pSur->currentDesc.Height, 1,
6514 32, lockedRect.pBits);
6515 IWineD3DSurface_UnlockRect(pCursorBitmap);
6516 /* Create our cursor and clean up. */
6517 cursor = CreateIconIndirect(&cursorInfo);
6518 SetCursor(cursor);
6519 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6520 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6521 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6522 This->hardwareCursor = cursor;
6523 HeapFree(GetProcessHeap(), 0, maskBits);
6527 This->xHotSpot = XHotSpot;
6528 This->yHotSpot = YHotSpot;
6529 return WINED3D_OK;
6532 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6534 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6536 This->xScreenSpace = XScreenSpace;
6537 This->yScreenSpace = YScreenSpace;
6539 return;
6543 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6545 BOOL oldVisible = This->bCursorVisible;
6546 POINT pt;
6548 TRACE("(%p) : visible(%d)\n", This, bShow);
6551 * When ShowCursor is first called it should make the cursor appear at the OS's last
6552 * known cursor position. Because of this, some applications just repetitively call
6553 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6555 GetCursorPos(&pt);
6556 This->xScreenSpace = pt.x;
6557 This->yScreenSpace = pt.y;
6559 if (This->haveHardwareCursor) {
6560 This->bCursorVisible = bShow;
6561 if (bShow)
6562 SetCursor(This->hardwareCursor);
6563 else
6564 SetCursor(NULL);
6566 else
6568 if (This->cursorTexture)
6569 This->bCursorVisible = bShow;
6572 return oldVisible;
6575 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6577 TRACE("(%p) : state (%u)\n", This, This->state);
6578 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6579 switch (This->state) {
6580 case WINED3D_OK:
6581 return WINED3D_OK;
6582 case WINED3DERR_DEVICELOST:
6584 ResourceList *resourceList = This->resources;
6585 while (NULL != resourceList) {
6586 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6587 return WINED3DERR_DEVICENOTRESET;
6588 resourceList = resourceList->next;
6590 return WINED3DERR_DEVICELOST;
6592 case WINED3DERR_DRIVERINTERNALERROR:
6593 return WINED3DERR_DRIVERINTERNALERROR;
6596 /* Unknown state */
6597 return WINED3DERR_DRIVERINTERNALERROR;
6601 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6603 /** FIXME: Resource tracking needs to be done,
6604 * The closes we can do to this is set the priorities of all managed textures low
6605 * and then reset them.
6606 ***********************************************************/
6607 FIXME("(%p) : stub\n", This);
6608 return WINED3D_OK;
6611 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6612 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6614 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6615 if(surface->Flags & SFLAG_DIBSECTION) {
6616 /* Release the DC */
6617 SelectObject(surface->hDC, surface->dib.holdbitmap);
6618 DeleteDC(surface->hDC);
6619 /* Release the DIB section */
6620 DeleteObject(surface->dib.DIBsection);
6621 surface->dib.bitmap_data = NULL;
6622 surface->resource.allocatedMemory = NULL;
6623 surface->Flags &= ~SFLAG_DIBSECTION;
6625 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6626 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6627 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6628 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6629 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6630 } else {
6631 surface->pow2Width = surface->pow2Height = 1;
6632 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6633 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6635 if(surface->glDescription.textureName) {
6636 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6637 ENTER_GL();
6638 glDeleteTextures(1, &surface->glDescription.textureName);
6639 LEAVE_GL();
6640 surface->glDescription.textureName = 0;
6641 surface->Flags &= ~SFLAG_CLIENT;
6643 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6644 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6645 surface->Flags |= SFLAG_NONPOW2;
6646 } else {
6647 surface->Flags &= ~SFLAG_NONPOW2;
6649 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6650 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6653 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6655 IWineD3DSwapChainImpl *swapchain;
6656 HRESULT hr;
6657 BOOL DisplayModeChanged = FALSE;
6658 WINED3DDISPLAYMODE mode;
6659 TRACE("(%p)\n", This);
6661 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6662 if(FAILED(hr)) {
6663 ERR("Failed to get the first implicit swapchain\n");
6664 return hr;
6667 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6668 * on an existing gl context, so there's no real need for recreation.
6670 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6672 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6674 TRACE("New params:\n");
6675 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6676 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6677 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6678 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6679 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6680 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6681 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6682 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6683 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6684 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6685 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6686 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6687 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6689 /* No special treatment of these parameters. Just store them */
6690 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6691 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6692 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6693 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6695 /* What to do about these? */
6696 if(pPresentationParameters->BackBufferCount != 0 &&
6697 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6698 ERR("Cannot change the back buffer count yet\n");
6700 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6701 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6702 ERR("Cannot change the back buffer format yet\n");
6704 if(pPresentationParameters->hDeviceWindow != NULL &&
6705 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6706 ERR("Cannot change the device window yet\n");
6708 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6709 ERR("What do do about a changed auto depth stencil parameter?\n");
6712 if(pPresentationParameters->Windowed) {
6713 mode.Width = swapchain->orig_width;
6714 mode.Height = swapchain->orig_height;
6715 mode.RefreshRate = 0;
6716 mode.Format = swapchain->presentParms.BackBufferFormat;
6717 } else {
6718 mode.Width = pPresentationParameters->BackBufferWidth;
6719 mode.Height = pPresentationParameters->BackBufferHeight;
6720 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6721 mode.Format = swapchain->presentParms.BackBufferFormat;
6724 /* Should Width == 800 && Height == 0 set 800x600? */
6725 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6726 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6727 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6729 WINED3DVIEWPORT vp;
6730 int i;
6732 vp.X = 0;
6733 vp.Y = 0;
6734 vp.Width = pPresentationParameters->BackBufferWidth;
6735 vp.Height = pPresentationParameters->BackBufferHeight;
6736 vp.MinZ = 0;
6737 vp.MaxZ = 1;
6739 if(!pPresentationParameters->Windowed) {
6740 DisplayModeChanged = TRUE;
6742 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6743 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6745 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6746 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6747 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6750 /* Now set the new viewport */
6751 IWineD3DDevice_SetViewport(iface, &vp);
6754 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6755 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6756 DisplayModeChanged) {
6758 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6759 if(!pPresentationParameters->Windowed) {
6760 IWineD3DDevice_SetFullscreen(iface, TRUE);
6763 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6765 /* Switching out of fullscreen mode? First set the original res, then change the window */
6766 if(pPresentationParameters->Windowed) {
6767 IWineD3DDevice_SetFullscreen(iface, FALSE);
6769 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6772 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6773 return WINED3D_OK;
6776 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6778 /** FIXME: always true at the moment **/
6779 if(!bEnableDialogs) {
6780 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6782 return WINED3D_OK;
6786 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6788 TRACE("(%p) : pParameters %p\n", This, pParameters);
6790 *pParameters = This->createParms;
6791 return WINED3D_OK;
6794 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6795 IWineD3DSwapChain *swapchain;
6796 HRESULT hrc = WINED3D_OK;
6798 TRACE("Relaying to swapchain\n");
6800 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6801 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6802 IWineD3DSwapChain_Release(swapchain);
6804 return;
6807 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6808 IWineD3DSwapChain *swapchain;
6809 HRESULT hrc = WINED3D_OK;
6811 TRACE("Relaying to swapchain\n");
6813 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6814 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6815 IWineD3DSwapChain_Release(swapchain);
6817 return;
6821 /** ********************************************************
6822 * Notification functions
6823 ** ********************************************************/
6824 /** This function must be called in the release of a resource when ref == 0,
6825 * the contents of resource must still be correct,
6826 * any handels to other resource held by the caller must be closed
6827 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6828 *****************************************************/
6829 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6831 ResourceList* resourceList;
6833 TRACE("(%p) : resource %p\n", This, resource);
6834 /* add a new texture to the frot of the linked list */
6835 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6836 resourceList->resource = resource;
6838 /* Get the old head */
6839 resourceList->next = This->resources;
6841 This->resources = resourceList;
6842 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6844 return;
6847 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6849 ResourceList* resourceList = NULL;
6850 ResourceList* previousResourceList = NULL;
6852 TRACE("(%p) : resource %p\n", This, resource);
6854 resourceList = This->resources;
6856 while (resourceList != NULL) {
6857 if(resourceList->resource == resource) break;
6858 previousResourceList = resourceList;
6859 resourceList = resourceList->next;
6862 if (resourceList == NULL) {
6863 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6864 return;
6865 } else {
6866 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6868 /* make sure we don't leave a hole in the list */
6869 if (previousResourceList != NULL) {
6870 previousResourceList->next = resourceList->next;
6871 } else {
6872 This->resources = resourceList->next;
6875 return;
6879 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6881 int counter;
6883 TRACE("(%p) : resource %p\n", This, resource);
6884 switch(IWineD3DResource_GetType(resource)){
6885 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6886 case WINED3DRTYPE_SURFACE: {
6887 unsigned int i;
6889 /* Cleanup any FBO attachments if d3d is enabled */
6890 if(This->d3d_initialized) {
6891 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
6892 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
6894 TRACE("Last active render target destroyed\n");
6895 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
6896 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
6897 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
6898 * and the lastActiveRenderTarget member shouldn't matter
6900 if(swapchain) {
6901 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
6902 TRACE("Activating primary back buffer\n");
6903 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
6904 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
6905 /* Single buffering environment */
6906 TRACE("Activating primary front buffer\n");
6907 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
6908 } else {
6909 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
6910 /* Implicit render target destroyed, that means the device is being destroyed
6911 * whatever we set here, it shouldn't matter
6913 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
6915 } else {
6916 /* May happen during ddraw uninitialization */
6917 TRACE("Render target set, but swapchain does not exist!\n");
6918 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
6922 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6923 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6924 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6925 set_render_target_fbo(iface, i, NULL);
6926 This->fbo_color_attachments[i] = NULL;
6929 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6930 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6931 set_depth_stencil_fbo(iface, NULL);
6932 This->fbo_depth_attachment = NULL;
6936 break;
6938 case WINED3DRTYPE_TEXTURE:
6939 case WINED3DRTYPE_CUBETEXTURE:
6940 case WINED3DRTYPE_VOLUMETEXTURE:
6941 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6942 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6943 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6944 This->stateBlock->textures[counter] = NULL;
6946 if (This->updateStateBlock != This->stateBlock ){
6947 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6948 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6949 This->updateStateBlock->textures[counter] = NULL;
6953 break;
6954 case WINED3DRTYPE_VOLUME:
6955 /* TODO: nothing really? */
6956 break;
6957 case WINED3DRTYPE_VERTEXBUFFER:
6958 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6960 int streamNumber;
6961 TRACE("Cleaning up stream pointers\n");
6963 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6964 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6965 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6967 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6968 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6969 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6970 This->updateStateBlock->streamSource[streamNumber] = 0;
6971 /* Set changed flag? */
6974 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) */
6975 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6976 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6977 This->stateBlock->streamSource[streamNumber] = 0;
6980 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6981 else { /* This shouldn't happen */
6982 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6984 #endif
6988 break;
6989 case WINED3DRTYPE_INDEXBUFFER:
6990 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6991 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6992 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6993 This->updateStateBlock->pIndexData = NULL;
6996 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6997 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6998 This->stateBlock->pIndexData = NULL;
7002 break;
7003 default:
7004 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7005 break;
7009 /* Remove the resoruce from the resourceStore */
7010 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7012 TRACE("Resource released\n");
7016 /**********************************************************
7017 * IWineD3DDevice VTbl follows
7018 **********************************************************/
7020 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7022 /*** IUnknown methods ***/
7023 IWineD3DDeviceImpl_QueryInterface,
7024 IWineD3DDeviceImpl_AddRef,
7025 IWineD3DDeviceImpl_Release,
7026 /*** IWineD3DDevice methods ***/
7027 IWineD3DDeviceImpl_GetParent,
7028 /*** Creation methods**/
7029 IWineD3DDeviceImpl_CreateVertexBuffer,
7030 IWineD3DDeviceImpl_CreateIndexBuffer,
7031 IWineD3DDeviceImpl_CreateStateBlock,
7032 IWineD3DDeviceImpl_CreateSurface,
7033 IWineD3DDeviceImpl_CreateTexture,
7034 IWineD3DDeviceImpl_CreateVolumeTexture,
7035 IWineD3DDeviceImpl_CreateVolume,
7036 IWineD3DDeviceImpl_CreateCubeTexture,
7037 IWineD3DDeviceImpl_CreateQuery,
7038 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7039 IWineD3DDeviceImpl_CreateVertexDeclaration,
7040 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7041 IWineD3DDeviceImpl_CreateVertexShader,
7042 IWineD3DDeviceImpl_CreatePixelShader,
7043 IWineD3DDeviceImpl_CreatePalette,
7044 /*** Odd functions **/
7045 IWineD3DDeviceImpl_Init3D,
7046 IWineD3DDeviceImpl_Uninit3D,
7047 IWineD3DDeviceImpl_SetFullscreen,
7048 IWineD3DDeviceImpl_SetMultithreaded,
7049 IWineD3DDeviceImpl_EvictManagedResources,
7050 IWineD3DDeviceImpl_GetAvailableTextureMem,
7051 IWineD3DDeviceImpl_GetBackBuffer,
7052 IWineD3DDeviceImpl_GetCreationParameters,
7053 IWineD3DDeviceImpl_GetDeviceCaps,
7054 IWineD3DDeviceImpl_GetDirect3D,
7055 IWineD3DDeviceImpl_GetDisplayMode,
7056 IWineD3DDeviceImpl_SetDisplayMode,
7057 IWineD3DDeviceImpl_GetHWND,
7058 IWineD3DDeviceImpl_SetHWND,
7059 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7060 IWineD3DDeviceImpl_GetRasterStatus,
7061 IWineD3DDeviceImpl_GetSwapChain,
7062 IWineD3DDeviceImpl_Reset,
7063 IWineD3DDeviceImpl_SetDialogBoxMode,
7064 IWineD3DDeviceImpl_SetCursorProperties,
7065 IWineD3DDeviceImpl_SetCursorPosition,
7066 IWineD3DDeviceImpl_ShowCursor,
7067 IWineD3DDeviceImpl_TestCooperativeLevel,
7068 /*** Getters and setters **/
7069 IWineD3DDeviceImpl_SetClipPlane,
7070 IWineD3DDeviceImpl_GetClipPlane,
7071 IWineD3DDeviceImpl_SetClipStatus,
7072 IWineD3DDeviceImpl_GetClipStatus,
7073 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7074 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7075 IWineD3DDeviceImpl_SetDepthStencilSurface,
7076 IWineD3DDeviceImpl_GetDepthStencilSurface,
7077 IWineD3DDeviceImpl_SetFVF,
7078 IWineD3DDeviceImpl_GetFVF,
7079 IWineD3DDeviceImpl_SetGammaRamp,
7080 IWineD3DDeviceImpl_GetGammaRamp,
7081 IWineD3DDeviceImpl_SetIndices,
7082 IWineD3DDeviceImpl_GetIndices,
7083 IWineD3DDeviceImpl_SetBaseVertexIndex,
7084 IWineD3DDeviceImpl_GetBaseVertexIndex,
7085 IWineD3DDeviceImpl_SetLight,
7086 IWineD3DDeviceImpl_GetLight,
7087 IWineD3DDeviceImpl_SetLightEnable,
7088 IWineD3DDeviceImpl_GetLightEnable,
7089 IWineD3DDeviceImpl_SetMaterial,
7090 IWineD3DDeviceImpl_GetMaterial,
7091 IWineD3DDeviceImpl_SetNPatchMode,
7092 IWineD3DDeviceImpl_GetNPatchMode,
7093 IWineD3DDeviceImpl_SetPaletteEntries,
7094 IWineD3DDeviceImpl_GetPaletteEntries,
7095 IWineD3DDeviceImpl_SetPixelShader,
7096 IWineD3DDeviceImpl_GetPixelShader,
7097 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7098 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7099 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7100 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7101 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7102 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7103 IWineD3DDeviceImpl_SetRenderState,
7104 IWineD3DDeviceImpl_GetRenderState,
7105 IWineD3DDeviceImpl_SetRenderTarget,
7106 IWineD3DDeviceImpl_GetRenderTarget,
7107 IWineD3DDeviceImpl_SetFrontBackBuffers,
7108 IWineD3DDeviceImpl_SetSamplerState,
7109 IWineD3DDeviceImpl_GetSamplerState,
7110 IWineD3DDeviceImpl_SetScissorRect,
7111 IWineD3DDeviceImpl_GetScissorRect,
7112 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7113 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7114 IWineD3DDeviceImpl_SetStreamSource,
7115 IWineD3DDeviceImpl_GetStreamSource,
7116 IWineD3DDeviceImpl_SetStreamSourceFreq,
7117 IWineD3DDeviceImpl_GetStreamSourceFreq,
7118 IWineD3DDeviceImpl_SetTexture,
7119 IWineD3DDeviceImpl_GetTexture,
7120 IWineD3DDeviceImpl_SetTextureStageState,
7121 IWineD3DDeviceImpl_GetTextureStageState,
7122 IWineD3DDeviceImpl_SetTransform,
7123 IWineD3DDeviceImpl_GetTransform,
7124 IWineD3DDeviceImpl_SetVertexDeclaration,
7125 IWineD3DDeviceImpl_GetVertexDeclaration,
7126 IWineD3DDeviceImpl_SetVertexShader,
7127 IWineD3DDeviceImpl_GetVertexShader,
7128 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7129 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7130 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7131 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7132 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7133 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7134 IWineD3DDeviceImpl_SetViewport,
7135 IWineD3DDeviceImpl_GetViewport,
7136 IWineD3DDeviceImpl_MultiplyTransform,
7137 IWineD3DDeviceImpl_ValidateDevice,
7138 IWineD3DDeviceImpl_ProcessVertices,
7139 /*** State block ***/
7140 IWineD3DDeviceImpl_BeginStateBlock,
7141 IWineD3DDeviceImpl_EndStateBlock,
7142 /*** Scene management ***/
7143 IWineD3DDeviceImpl_BeginScene,
7144 IWineD3DDeviceImpl_EndScene,
7145 IWineD3DDeviceImpl_Present,
7146 IWineD3DDeviceImpl_Clear,
7147 /*** Drawing ***/
7148 IWineD3DDeviceImpl_DrawPrimitive,
7149 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7150 IWineD3DDeviceImpl_DrawPrimitiveUP,
7151 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7152 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7153 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7154 IWineD3DDeviceImpl_DrawRectPatch,
7155 IWineD3DDeviceImpl_DrawTriPatch,
7156 IWineD3DDeviceImpl_DeletePatch,
7157 IWineD3DDeviceImpl_ColorFill,
7158 IWineD3DDeviceImpl_UpdateTexture,
7159 IWineD3DDeviceImpl_UpdateSurface,
7160 IWineD3DDeviceImpl_GetFrontBufferData,
7161 /*** object tracking ***/
7162 IWineD3DDeviceImpl_ResourceReleased
7166 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7167 WINED3DRS_ALPHABLENDENABLE ,
7168 WINED3DRS_ALPHAFUNC ,
7169 WINED3DRS_ALPHAREF ,
7170 WINED3DRS_ALPHATESTENABLE ,
7171 WINED3DRS_BLENDOP ,
7172 WINED3DRS_COLORWRITEENABLE ,
7173 WINED3DRS_DESTBLEND ,
7174 WINED3DRS_DITHERENABLE ,
7175 WINED3DRS_FILLMODE ,
7176 WINED3DRS_FOGDENSITY ,
7177 WINED3DRS_FOGEND ,
7178 WINED3DRS_FOGSTART ,
7179 WINED3DRS_LASTPIXEL ,
7180 WINED3DRS_SHADEMODE ,
7181 WINED3DRS_SRCBLEND ,
7182 WINED3DRS_STENCILENABLE ,
7183 WINED3DRS_STENCILFAIL ,
7184 WINED3DRS_STENCILFUNC ,
7185 WINED3DRS_STENCILMASK ,
7186 WINED3DRS_STENCILPASS ,
7187 WINED3DRS_STENCILREF ,
7188 WINED3DRS_STENCILWRITEMASK ,
7189 WINED3DRS_STENCILZFAIL ,
7190 WINED3DRS_TEXTUREFACTOR ,
7191 WINED3DRS_WRAP0 ,
7192 WINED3DRS_WRAP1 ,
7193 WINED3DRS_WRAP2 ,
7194 WINED3DRS_WRAP3 ,
7195 WINED3DRS_WRAP4 ,
7196 WINED3DRS_WRAP5 ,
7197 WINED3DRS_WRAP6 ,
7198 WINED3DRS_WRAP7 ,
7199 WINED3DRS_ZENABLE ,
7200 WINED3DRS_ZFUNC ,
7201 WINED3DRS_ZWRITEENABLE
7204 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7205 WINED3DTSS_ADDRESSW ,
7206 WINED3DTSS_ALPHAARG0 ,
7207 WINED3DTSS_ALPHAARG1 ,
7208 WINED3DTSS_ALPHAARG2 ,
7209 WINED3DTSS_ALPHAOP ,
7210 WINED3DTSS_BUMPENVLOFFSET ,
7211 WINED3DTSS_BUMPENVLSCALE ,
7212 WINED3DTSS_BUMPENVMAT00 ,
7213 WINED3DTSS_BUMPENVMAT01 ,
7214 WINED3DTSS_BUMPENVMAT10 ,
7215 WINED3DTSS_BUMPENVMAT11 ,
7216 WINED3DTSS_COLORARG0 ,
7217 WINED3DTSS_COLORARG1 ,
7218 WINED3DTSS_COLORARG2 ,
7219 WINED3DTSS_COLOROP ,
7220 WINED3DTSS_RESULTARG ,
7221 WINED3DTSS_TEXCOORDINDEX ,
7222 WINED3DTSS_TEXTURETRANSFORMFLAGS
7225 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7226 WINED3DSAMP_ADDRESSU ,
7227 WINED3DSAMP_ADDRESSV ,
7228 WINED3DSAMP_ADDRESSW ,
7229 WINED3DSAMP_BORDERCOLOR ,
7230 WINED3DSAMP_MAGFILTER ,
7231 WINED3DSAMP_MINFILTER ,
7232 WINED3DSAMP_MIPFILTER ,
7233 WINED3DSAMP_MIPMAPLODBIAS ,
7234 WINED3DSAMP_MAXMIPLEVEL ,
7235 WINED3DSAMP_MAXANISOTROPY ,
7236 WINED3DSAMP_SRGBTEXTURE ,
7237 WINED3DSAMP_ELEMENTINDEX
7240 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7241 WINED3DRS_AMBIENT ,
7242 WINED3DRS_AMBIENTMATERIALSOURCE ,
7243 WINED3DRS_CLIPPING ,
7244 WINED3DRS_CLIPPLANEENABLE ,
7245 WINED3DRS_COLORVERTEX ,
7246 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7247 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7248 WINED3DRS_FOGDENSITY ,
7249 WINED3DRS_FOGEND ,
7250 WINED3DRS_FOGSTART ,
7251 WINED3DRS_FOGTABLEMODE ,
7252 WINED3DRS_FOGVERTEXMODE ,
7253 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7254 WINED3DRS_LIGHTING ,
7255 WINED3DRS_LOCALVIEWER ,
7256 WINED3DRS_MULTISAMPLEANTIALIAS ,
7257 WINED3DRS_MULTISAMPLEMASK ,
7258 WINED3DRS_NORMALIZENORMALS ,
7259 WINED3DRS_PATCHEDGESTYLE ,
7260 WINED3DRS_POINTSCALE_A ,
7261 WINED3DRS_POINTSCALE_B ,
7262 WINED3DRS_POINTSCALE_C ,
7263 WINED3DRS_POINTSCALEENABLE ,
7264 WINED3DRS_POINTSIZE ,
7265 WINED3DRS_POINTSIZE_MAX ,
7266 WINED3DRS_POINTSIZE_MIN ,
7267 WINED3DRS_POINTSPRITEENABLE ,
7268 WINED3DRS_RANGEFOGENABLE ,
7269 WINED3DRS_SPECULARMATERIALSOURCE ,
7270 WINED3DRS_TWEENFACTOR ,
7271 WINED3DRS_VERTEXBLEND ,
7272 WINED3DRS_CULLMODE ,
7273 WINED3DRS_FOGCOLOR
7276 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7277 WINED3DTSS_TEXCOORDINDEX ,
7278 WINED3DTSS_TEXTURETRANSFORMFLAGS
7281 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7282 WINED3DSAMP_DMAPOFFSET
7285 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7286 DWORD rep = StateTable[state].representative;
7287 DWORD idx;
7288 BYTE shift;
7289 UINT i;
7290 WineD3DContext *context;
7292 if(!rep) return;
7293 for(i = 0; i < This->numContexts; i++) {
7294 context = This->contexts[i];
7295 if(isStateDirty(context, rep)) continue;
7297 context->dirtyArray[context->numDirtyEntries++] = rep;
7298 idx = rep >> 5;
7299 shift = rep & 0x1f;
7300 context->isStateDirty[idx] |= (1 << shift);