wined3d: Disconnect allocatedMemory and Heap allocation.
[wine/testsucceed.git] / dlls / wined3d / device.c
blobdb7a4e323b4070b3d524ba02ae16d4a3528aabe9
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.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + 4)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
108 *pp##type = NULL; \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = object->resource.heapMemory; \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
139 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
140 if (IsEqualGUID(riid, &IID_IUnknown)
141 || IsEqualGUID(riid, &IID_IWineD3DBase)
142 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
143 IUnknown_AddRef(iface);
144 *ppobj = This;
145 return S_OK;
147 *ppobj = NULL;
148 return E_NOINTERFACE;
151 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 ULONG refCount = InterlockedIncrement(&This->ref);
155 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
156 return refCount;
159 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 ULONG refCount = InterlockedDecrement(&This->ref);
163 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
165 if (!refCount) {
166 if (This->fbo) {
167 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
169 if (This->src_fbo) {
170 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
172 if (This->dst_fbo) {
173 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
176 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
178 /* TODO: Clean up all the surfaces and textures! */
179 /* NOTE: You must release the parent if the object was created via a callback
180 ** ***************************/
182 if (This->resources != NULL ) {
183 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
184 dumpResources(This->resources);
187 if(This->contexts) ERR("Context array not freed!\n");
188 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
189 This->haveHardwareCursor = FALSE;
191 IWineD3D_Release(This->wineD3D);
192 This->wineD3D = NULL;
193 HeapFree(GetProcessHeap(), 0, This);
194 TRACE("Freed device %p\n", This);
195 This = NULL;
197 return refCount;
200 /**********************************************************
201 * IWineD3DDevice implementation follows
202 **********************************************************/
203 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
205 *pParent = This->parent;
206 IUnknown_AddRef(This->parent);
207 return WINED3D_OK;
210 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
211 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
212 GLenum error, glUsage;
213 DWORD vboUsage = object->resource.usage;
214 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
215 WARN("Creating a vbo failed once, not trying again\n");
216 return;
219 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
221 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
222 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
223 ENTER_GL();
225 /* Make sure that the gl error is cleared. Do not use checkGLcall
226 * here because checkGLcall just prints a fixme and continues. However,
227 * if an error during VBO creation occurs we can fall back to non-vbo operation
228 * with full functionality(but performance loss)
230 while(glGetError() != GL_NO_ERROR);
232 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
233 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
234 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
235 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
236 * to check if the rhw and color values are in the correct format.
239 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
240 error = glGetError();
241 if(object->vbo == 0 || error != GL_NO_ERROR) {
242 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
243 goto error;
246 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
247 error = glGetError();
248 if(error != GL_NO_ERROR) {
249 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
250 goto error;
253 /* Don't use static, because dx apps tend to update the buffer
254 * quite often even if they specify 0 usage. Because we always keep the local copy
255 * we never read from the vbo and can create a write only opengl buffer.
257 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
258 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
259 case WINED3DUSAGE_DYNAMIC:
260 TRACE("Gl usage = GL_STREAM_DRAW\n");
261 glUsage = GL_STREAM_DRAW_ARB;
262 break;
263 case WINED3DUSAGE_WRITEONLY:
264 default:
265 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
266 glUsage = GL_DYNAMIC_DRAW_ARB;
267 break;
270 /* Reserve memory for the buffer. The amount of data won't change
271 * so we are safe with calling glBufferData once with a NULL ptr and
272 * calling glBufferSubData on updates
274 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
275 error = glGetError();
276 if(error != GL_NO_ERROR) {
277 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
278 goto error;
281 LEAVE_GL();
283 return;
284 error:
285 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
286 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
287 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
288 object->vbo = 0;
289 object->Flags |= VBFLAG_VBOCREATEFAIL;
290 LEAVE_GL();
291 return;
294 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
295 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
296 IUnknown *parent) {
297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
298 IWineD3DVertexBufferImpl *object;
299 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
300 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
301 BOOL conv;
303 if(Size == 0) {
304 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
305 *ppVertexBuffer = NULL;
306 return WINED3DERR_INVALIDCALL;
309 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
311 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
312 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
314 object->fvf = FVF;
316 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
317 * drawStridedFast (half-life 2).
319 * Basically converting the vertices in the buffer is quite expensive, and observations
320 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
321 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
323 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
324 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
325 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
326 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
327 * dx7 apps.
328 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
329 * more. In this call we can convert dx7 buffers too.
331 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
332 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
333 (dxVersion > 7 || !conv) ) {
334 CreateVBO(object);
336 return WINED3D_OK;
339 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
340 GLenum error, glUsage;
341 TRACE("Creating VBO for Index Buffer %p\n", object);
343 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
344 * restored on the next draw
346 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
348 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
349 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
350 ENTER_GL();
352 while(glGetError());
354 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
355 error = glGetError();
356 if(error != GL_NO_ERROR || object->vbo == 0) {
357 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
358 goto out;
361 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
362 error = glGetError();
363 if(error != GL_NO_ERROR) {
364 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
365 goto out;
368 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
369 * copy no readback will be needed
371 glUsage = GL_STATIC_DRAW_ARB;
372 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
373 error = glGetError();
374 if(error != GL_NO_ERROR) {
375 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
376 goto out;
378 LEAVE_GL();
379 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
380 return;
382 out:
383 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
384 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
385 LEAVE_GL();
386 object->vbo = 0;
389 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
390 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
391 HANDLE *sharedHandle, IUnknown *parent) {
392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
393 IWineD3DIndexBufferImpl *object;
394 TRACE("(%p) Creating index buffer\n", This);
396 /* Allocate the storage for the device */
397 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
399 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
400 CreateIndexBufferVBO(This, object);
403 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
404 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
405 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
407 return WINED3D_OK;
410 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
413 IWineD3DStateBlockImpl *object;
414 int i, j;
415 HRESULT temp_result;
417 D3DCREATEOBJECTINSTANCE(object, StateBlock)
418 object->blockType = Type;
420 for(i = 0; i < LIGHTMAP_SIZE; i++) {
421 list_init(&object->lightMap[i]);
424 /* Special case - Used during initialization to produce a placeholder stateblock
425 so other functions called can update a state block */
426 if (Type == WINED3DSBT_INIT) {
427 /* Don't bother increasing the reference count otherwise a device will never
428 be freed due to circular dependencies */
429 return WINED3D_OK;
432 temp_result = allocate_shader_constants(object);
433 if (WINED3D_OK != temp_result)
434 return temp_result;
436 /* Otherwise, might as well set the whole state block to the appropriate values */
437 if (This->stateBlock != NULL)
438 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
439 else
440 memset(object->streamFreq, 1, sizeof(object->streamFreq));
442 /* Reset the ref and type after kludging it */
443 object->wineD3DDevice = This;
444 object->ref = 1;
445 object->blockType = Type;
447 TRACE("Updating changed flags appropriate for type %d\n", Type);
449 if (Type == WINED3DSBT_ALL) {
451 TRACE("ALL => Pretend everything has changed\n");
452 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
454 /* Lights are not part of the changed / set structure */
455 for(j = 0; j < LIGHTMAP_SIZE; j++) {
456 struct list *e;
457 LIST_FOR_EACH(e, &object->lightMap[j]) {
458 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
459 light->changed = TRUE;
460 light->enabledChanged = TRUE;
463 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
464 object->contained_render_states[j - 1] = j;
466 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
467 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
468 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
469 object->contained_transform_states[j - 1] = j;
471 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
472 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
473 object->contained_vs_consts_f[j] = j;
475 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
476 for(j = 0; j < MAX_CONST_I; j++) {
477 object->contained_vs_consts_i[j] = j;
479 object->num_contained_vs_consts_i = MAX_CONST_I;
480 for(j = 0; j < MAX_CONST_B; j++) {
481 object->contained_vs_consts_b[j] = j;
483 object->num_contained_vs_consts_b = MAX_CONST_B;
484 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
485 object->contained_ps_consts_f[j] = j;
487 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
488 for(j = 0; j < MAX_CONST_I; j++) {
489 object->contained_ps_consts_i[j] = j;
491 object->num_contained_ps_consts_i = MAX_CONST_I;
492 for(j = 0; j < MAX_CONST_B; j++) {
493 object->contained_ps_consts_b[j] = j;
495 object->num_contained_ps_consts_b = MAX_CONST_B;
496 for(i = 0; i < MAX_TEXTURES; i++) {
497 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
498 object->contained_tss_states[object->num_contained_tss_states].stage = i;
499 object->contained_tss_states[object->num_contained_tss_states].state = j;
500 object->num_contained_tss_states++;
503 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
504 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
505 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
506 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
507 object->num_contained_sampler_states++;
511 for(i = 0; i < MAX_STREAMS; i++) {
512 if(object->streamSource[i]) {
513 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
516 if(object->pIndexData) {
517 IWineD3DIndexBuffer_AddRef(object->pIndexData);
519 if(object->vertexShader) {
520 IWineD3DVertexShader_AddRef(object->vertexShader);
522 if(object->pixelShader) {
523 IWineD3DPixelShader_AddRef(object->pixelShader);
526 } else if (Type == WINED3DSBT_PIXELSTATE) {
528 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
529 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
531 object->changed.pixelShader = TRUE;
533 /* Pixel Shader Constants */
534 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
535 object->contained_ps_consts_f[i] = i;
536 object->changed.pixelShaderConstantsF[i] = TRUE;
538 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
539 for (i = 0; i < MAX_CONST_B; ++i) {
540 object->contained_ps_consts_b[i] = i;
541 object->changed.pixelShaderConstantsB[i] = TRUE;
543 object->num_contained_ps_consts_b = MAX_CONST_B;
544 for (i = 0; i < MAX_CONST_I; ++i) {
545 object->contained_ps_consts_i[i] = i;
546 object->changed.pixelShaderConstantsI[i] = TRUE;
548 object->num_contained_ps_consts_i = MAX_CONST_I;
550 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
551 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
552 object->contained_render_states[i] = SavedPixelStates_R[i];
554 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
555 for (j = 0; j < MAX_TEXTURES; j++) {
556 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
557 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
558 object->contained_tss_states[object->num_contained_tss_states].stage = j;
559 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
560 object->num_contained_tss_states++;
563 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
564 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
565 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
566 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
567 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
568 object->num_contained_sampler_states++;
571 if(object->pixelShader) {
572 IWineD3DPixelShader_AddRef(object->pixelShader);
575 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
576 * on them. This makes releasing the buffer easier
578 for(i = 0; i < MAX_STREAMS; i++) {
579 object->streamSource[i] = NULL;
581 object->pIndexData = NULL;
582 object->vertexShader = NULL;
584 } else if (Type == WINED3DSBT_VERTEXSTATE) {
586 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
587 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
589 object->changed.vertexShader = TRUE;
591 /* Vertex Shader Constants */
592 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
593 object->changed.vertexShaderConstantsF[i] = TRUE;
594 object->contained_vs_consts_f[i] = i;
596 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
597 for (i = 0; i < MAX_CONST_B; ++i) {
598 object->changed.vertexShaderConstantsB[i] = TRUE;
599 object->contained_vs_consts_b[i] = i;
601 object->num_contained_vs_consts_b = MAX_CONST_B;
602 for (i = 0; i < MAX_CONST_I; ++i) {
603 object->changed.vertexShaderConstantsI[i] = TRUE;
604 object->contained_vs_consts_i[i] = i;
606 object->num_contained_vs_consts_i = MAX_CONST_I;
607 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
608 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
609 object->contained_render_states[i] = SavedVertexStates_R[i];
611 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
612 for (j = 0; j < MAX_TEXTURES; j++) {
613 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
614 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
615 object->contained_tss_states[object->num_contained_tss_states].stage = j;
616 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
617 object->num_contained_tss_states++;
620 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
621 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
622 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
623 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
624 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
625 object->num_contained_sampler_states++;
629 for(j = 0; j < LIGHTMAP_SIZE; j++) {
630 struct list *e;
631 LIST_FOR_EACH(e, &object->lightMap[j]) {
632 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
633 light->changed = TRUE;
634 light->enabledChanged = TRUE;
638 for(i = 0; i < MAX_STREAMS; i++) {
639 if(object->streamSource[i]) {
640 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
643 if(object->vertexShader) {
644 IWineD3DVertexShader_AddRef(object->vertexShader);
646 object->pIndexData = NULL;
647 object->pixelShader = NULL;
648 } else {
649 FIXME("Unrecognized state block type %d\n", Type);
652 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
653 return WINED3D_OK;
656 /* ************************************
657 MSDN:
658 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
660 Discard
661 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
663 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.
665 ******************************** */
667 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) {
668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
669 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
670 unsigned int Size = 1;
671 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
672 TRACE("(%p) Create surface\n",This);
674 /** FIXME: Check ranges on the inputs are valid
675 * MSDN
676 * MultisampleQuality
677 * [in] Quality level. The valid range is between zero and one less than the level
678 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
679 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
680 * values of paired render targets, depth stencil surfaces, and the MultiSample type
681 * must all match.
682 *******************************/
686 * TODO: Discard MSDN
687 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
689 * If this flag is set, the contents of the depth stencil buffer will be
690 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
691 * with a different depth surface.
693 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
694 ***************************/
696 if(MultisampleQuality < 0) {
697 FIXME("Invalid multisample level %d\n", MultisampleQuality);
698 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
701 if(MultisampleQuality > 0) {
702 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
703 MultisampleQuality=0;
706 /** FIXME: Check that the format is supported
707 * by the device.
708 *******************************/
710 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
711 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
712 * space!
713 *********************************/
714 if (WINED3DFMT_UNKNOWN == Format) {
715 Size = 0;
716 } else if (Format == WINED3DFMT_DXT1) {
717 /* DXT1 is half byte per pixel */
718 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
720 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
721 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
722 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
723 } else {
724 /* The pitch is a multiple of 4 bytes */
725 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
726 Size *= Height;
729 /** Create and initialise the surface resource **/
730 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
731 /* "Standalone" surface */
732 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
734 object->currentDesc.Width = Width;
735 object->currentDesc.Height = Height;
736 object->currentDesc.MultiSampleType = MultiSample;
737 object->currentDesc.MultiSampleQuality = MultisampleQuality;
738 object->glDescription.level = Level;
740 /* Flags */
741 object->Flags = 0;
742 object->Flags |= Discard ? SFLAG_DISCARD : 0;
743 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
744 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
747 if (WINED3DFMT_UNKNOWN != Format) {
748 object->bytesPerPixel = tableEntry->bpp;
749 } else {
750 object->bytesPerPixel = 0;
753 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
755 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
757 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
758 * this function is too deep to need to care about things like this.
759 * Levels need to be checked too, and possibly Type since they all affect what can be done.
760 * ****************************************/
761 switch(Pool) {
762 case WINED3DPOOL_SCRATCH:
763 if(!Lockable)
764 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
765 "which are mutually exclusive, setting lockable to TRUE\n");
766 Lockable = TRUE;
767 break;
768 case WINED3DPOOL_SYSTEMMEM:
769 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
770 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
771 case WINED3DPOOL_MANAGED:
772 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
773 "Usage of DYNAMIC which are mutually exclusive, not doing "
774 "anything just telling you.\n");
775 break;
776 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
777 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
778 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
779 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
780 break;
781 default:
782 FIXME("(%p) Unknown pool %d\n", This, Pool);
783 break;
786 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
787 FIXME("Trying to create a render target that isn't in the default pool\n");
790 /* mark the texture as dirty so that it gets loaded first time around*/
791 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
792 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
793 This, Width, Height, Format, debug_d3dformat(Format),
794 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
796 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
797 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
798 This->ddraw_primary = (IWineD3DSurface *) object;
800 /* Look at the implementation and set the correct Vtable */
801 switch(Impl) {
802 case SURFACE_OPENGL:
803 /* Check if a 3D adapter is available when creating gl surfaces */
804 if(!This->adapter) {
805 ERR("OpenGL surfaces are not available without opengl\n");
806 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
807 HeapFree(GetProcessHeap(), 0, object);
808 return WINED3DERR_NOTAVAILABLE;
810 break;
812 case SURFACE_GDI:
813 object->lpVtbl = &IWineGDISurface_Vtbl;
814 break;
816 default:
817 /* To be sure to catch this */
818 ERR("Unknown requested surface implementation %d!\n", Impl);
819 IWineD3DSurface_Release((IWineD3DSurface *) object);
820 return WINED3DERR_INVALIDCALL;
823 list_init(&object->renderbuffers);
825 /* Call the private setup routine */
826 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
830 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
831 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
832 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
833 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
836 IWineD3DTextureImpl *object;
837 unsigned int i;
838 UINT tmpW;
839 UINT tmpH;
840 HRESULT hr;
841 unsigned int pow2Width;
842 unsigned int pow2Height;
843 const GlPixelFormatDesc *glDesc;
844 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
847 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
848 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
849 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
851 /* TODO: It should only be possible to create textures for formats
852 that are reported as supported */
853 if (WINED3DFMT_UNKNOWN >= Format) {
854 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
855 return WINED3DERR_INVALIDCALL;
858 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
859 D3DINITIALIZEBASETEXTURE(object->baseTexture);
860 object->width = Width;
861 object->height = Height;
863 /** Non-power2 support **/
864 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
865 pow2Width = Width;
866 pow2Height = Height;
867 } else {
868 /* Find the nearest pow2 match */
869 pow2Width = pow2Height = 1;
870 while (pow2Width < Width) pow2Width <<= 1;
871 while (pow2Height < Height) pow2Height <<= 1;
874 /** FIXME: add support for real non-power-two if it's provided by the video card **/
875 /* Precalculated scaling for 'faked' non power of two texture coords */
876 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
877 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
878 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
880 /* Calculate levels for mip mapping */
881 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
882 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
883 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
884 return WINED3DERR_INVALIDCALL;
886 if(Levels > 1) {
887 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
888 return WINED3DERR_INVALIDCALL;
890 object->baseTexture.levels = 1;
891 } else if (Levels == 0) {
892 TRACE("calculating levels %d\n", object->baseTexture.levels);
893 object->baseTexture.levels++;
894 tmpW = Width;
895 tmpH = Height;
896 while (tmpW > 1 || tmpH > 1) {
897 tmpW = max(1, tmpW >> 1);
898 tmpH = max(1, tmpH >> 1);
899 object->baseTexture.levels++;
901 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
904 /* Generate all the surfaces */
905 tmpW = Width;
906 tmpH = Height;
907 for (i = 0; i < object->baseTexture.levels; i++)
909 /* use the callback to create the texture surface */
910 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
911 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
912 FIXME("Failed to create surface %p\n", object);
913 /* clean up */
914 object->surfaces[i] = NULL;
915 IWineD3DTexture_Release((IWineD3DTexture *)object);
917 *ppTexture = NULL;
918 return hr;
921 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
922 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
923 /* calculate the next mipmap level */
924 tmpW = max(1, tmpW >> 1);
925 tmpH = max(1, tmpH >> 1);
927 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
929 TRACE("(%p) : Created texture %p\n", This, object);
930 return WINED3D_OK;
933 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
934 UINT Width, UINT Height, UINT Depth,
935 UINT Levels, DWORD Usage,
936 WINED3DFORMAT Format, WINED3DPOOL Pool,
937 IWineD3DVolumeTexture **ppVolumeTexture,
938 HANDLE *pSharedHandle, IUnknown *parent,
939 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
942 IWineD3DVolumeTextureImpl *object;
943 unsigned int i;
944 UINT tmpW;
945 UINT tmpH;
946 UINT tmpD;
947 const GlPixelFormatDesc *glDesc;
948 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
950 /* TODO: It should only be possible to create textures for formats
951 that are reported as supported */
952 if (WINED3DFMT_UNKNOWN >= Format) {
953 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
954 return WINED3DERR_INVALIDCALL;
957 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
958 D3DINITIALIZEBASETEXTURE(object->baseTexture);
960 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
961 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
963 object->width = Width;
964 object->height = Height;
965 object->depth = Depth;
967 /* Calculate levels for mip mapping */
968 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
969 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
970 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
971 return WINED3DERR_INVALIDCALL;
973 if(Levels > 1) {
974 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
975 return WINED3DERR_INVALIDCALL;
977 Levels = 1;
978 } else if (Levels == 0) {
979 object->baseTexture.levels++;
980 tmpW = Width;
981 tmpH = Height;
982 tmpD = Depth;
983 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
984 tmpW = max(1, tmpW >> 1);
985 tmpH = max(1, tmpH >> 1);
986 tmpD = max(1, tmpD >> 1);
987 object->baseTexture.levels++;
989 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
992 /* Generate all the surfaces */
993 tmpW = Width;
994 tmpH = Height;
995 tmpD = Depth;
997 for (i = 0; i < object->baseTexture.levels; i++)
999 HRESULT hr;
1000 /* Create the volume */
1001 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
1002 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1004 if(FAILED(hr)) {
1005 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1006 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1007 *ppVolumeTexture = NULL;
1008 return hr;
1011 /* Set its container to this object */
1012 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1014 /* calcualte the next mipmap level */
1015 tmpW = max(1, tmpW >> 1);
1016 tmpH = max(1, tmpH >> 1);
1017 tmpD = max(1, tmpD >> 1);
1019 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1021 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1022 TRACE("(%p) : Created volume texture %p\n", This, object);
1023 return WINED3D_OK;
1026 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1027 UINT Width, UINT Height, UINT Depth,
1028 DWORD Usage,
1029 WINED3DFORMAT Format, WINED3DPOOL Pool,
1030 IWineD3DVolume** ppVolume,
1031 HANDLE* pSharedHandle, IUnknown *parent) {
1033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1034 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1035 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1037 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1039 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1040 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1042 object->currentDesc.Width = Width;
1043 object->currentDesc.Height = Height;
1044 object->currentDesc.Depth = Depth;
1045 object->bytesPerPixel = formatDesc->bpp;
1047 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1048 object->lockable = TRUE;
1049 object->locked = FALSE;
1050 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1051 object->dirty = TRUE;
1053 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1056 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1057 UINT Levels, DWORD Usage,
1058 WINED3DFORMAT Format, WINED3DPOOL Pool,
1059 IWineD3DCubeTexture **ppCubeTexture,
1060 HANDLE *pSharedHandle, IUnknown *parent,
1061 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1064 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1065 unsigned int i, j;
1066 UINT tmpW;
1067 HRESULT hr;
1068 unsigned int pow2EdgeLength = EdgeLength;
1069 const GlPixelFormatDesc *glDesc;
1070 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1072 /* TODO: It should only be possible to create textures for formats
1073 that are reported as supported */
1074 if (WINED3DFMT_UNKNOWN >= Format) {
1075 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1076 return WINED3DERR_INVALIDCALL;
1079 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1080 WARN("(%p) : Tried to create not supported cube texture\n", This);
1081 return WINED3DERR_INVALIDCALL;
1084 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1085 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1087 TRACE("(%p) Create Cube Texture\n", This);
1089 /** Non-power2 support **/
1091 /* Find the nearest pow2 match */
1092 pow2EdgeLength = 1;
1093 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1095 object->edgeLength = EdgeLength;
1096 /* TODO: support for native non-power 2 */
1097 /* Precalculated scaling for 'faked' non power of two texture coords */
1098 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1100 /* Calculate levels for mip mapping */
1101 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1102 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1103 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1104 HeapFree(GetProcessHeap(), 0, object);
1105 *ppCubeTexture = NULL;
1107 return WINED3DERR_INVALIDCALL;
1109 if(Levels > 1) {
1110 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1111 HeapFree(GetProcessHeap(), 0, object);
1112 *ppCubeTexture = NULL;
1114 return WINED3DERR_INVALIDCALL;
1116 Levels = 1;
1117 } else if (Levels == 0) {
1118 object->baseTexture.levels++;
1119 tmpW = EdgeLength;
1120 while (tmpW > 1) {
1121 tmpW = max(1, tmpW >> 1);
1122 object->baseTexture.levels++;
1124 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1127 /* Generate all the surfaces */
1128 tmpW = EdgeLength;
1129 for (i = 0; i < object->baseTexture.levels; i++) {
1131 /* Create the 6 faces */
1132 for (j = 0; j < 6; j++) {
1134 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1135 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1137 if(hr!= WINED3D_OK) {
1138 /* clean up */
1139 int k;
1140 int l;
1141 for (l = 0; l < j; l++) {
1142 IWineD3DSurface_Release(object->surfaces[l][i]);
1144 for (k = 0; k < i; k++) {
1145 for (l = 0; l < 6; l++) {
1146 IWineD3DSurface_Release(object->surfaces[l][k]);
1150 FIXME("(%p) Failed to create surface\n",object);
1151 HeapFree(GetProcessHeap(),0,object);
1152 *ppCubeTexture = NULL;
1153 return hr;
1155 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1156 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1158 tmpW = max(1, tmpW >> 1);
1160 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1162 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1163 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1164 return WINED3D_OK;
1167 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1169 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1170 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1172 /* Just a check to see if we support this type of query */
1173 switch(Type) {
1174 case WINED3DQUERYTYPE_OCCLUSION:
1175 TRACE("(%p) occlusion query\n", This);
1176 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1177 hr = WINED3D_OK;
1178 else
1179 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1180 break;
1182 case WINED3DQUERYTYPE_EVENT:
1183 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1184 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1185 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1187 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1189 hr = WINED3D_OK;
1190 break;
1192 case WINED3DQUERYTYPE_VCACHE:
1193 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1194 case WINED3DQUERYTYPE_VERTEXSTATS:
1195 case WINED3DQUERYTYPE_TIMESTAMP:
1196 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1197 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1198 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1199 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1200 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1201 case WINED3DQUERYTYPE_PIXELTIMINGS:
1202 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1203 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1204 default:
1205 FIXME("(%p) Unhandled query type %d\n", This, Type);
1207 if(NULL == ppQuery || hr != WINED3D_OK) {
1208 return hr;
1211 D3DCREATEOBJECTINSTANCE(object, Query)
1212 object->type = Type;
1213 /* allocated the 'extended' data based on the type of query requested */
1214 switch(Type){
1215 case WINED3DQUERYTYPE_OCCLUSION:
1216 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1217 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1219 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1220 TRACE("(%p) Allocating data for an occlusion query\n", This);
1221 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1222 break;
1224 case WINED3DQUERYTYPE_EVENT:
1225 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1226 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1228 if(GL_SUPPORT(APPLE_FENCE)) {
1229 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1230 checkGLcall("glGenFencesAPPLE");
1231 } else if(GL_SUPPORT(NV_FENCE)) {
1232 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1233 checkGLcall("glGenFencesNV");
1235 break;
1237 case WINED3DQUERYTYPE_VCACHE:
1238 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1239 case WINED3DQUERYTYPE_VERTEXSTATS:
1240 case WINED3DQUERYTYPE_TIMESTAMP:
1241 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1242 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1243 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1244 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1245 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1246 case WINED3DQUERYTYPE_PIXELTIMINGS:
1247 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1248 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1249 default:
1250 object->extendedData = 0;
1251 FIXME("(%p) Unhandled query type %d\n",This , Type);
1253 TRACE("(%p) : Created Query %p\n", This, object);
1254 return WINED3D_OK;
1257 /*****************************************************************************
1258 * IWineD3DDeviceImpl_SetupFullscreenWindow
1260 * Helper function that modifies a HWND's Style and ExStyle for proper
1261 * fullscreen use.
1263 * Params:
1264 * iface: Pointer to the IWineD3DDevice interface
1265 * window: Window to setup
1267 *****************************************************************************/
1268 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1271 LONG style, exStyle;
1272 /* Don't do anything if an original style is stored.
1273 * That shouldn't happen
1275 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1276 if (This->style || This->exStyle) {
1277 ERR("(%p): Want to change the window parameters of HWND %p, but "
1278 "another style is stored for restoration afterwards\n", This, window);
1281 /* Get the parameters and save them */
1282 style = GetWindowLongW(window, GWL_STYLE);
1283 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1284 This->style = style;
1285 This->exStyle = exStyle;
1287 /* Filter out window decorations */
1288 style &= ~WS_CAPTION;
1289 style &= ~WS_THICKFRAME;
1290 exStyle &= ~WS_EX_WINDOWEDGE;
1291 exStyle &= ~WS_EX_CLIENTEDGE;
1293 /* Make sure the window is managed, otherwise we won't get keyboard input */
1294 style |= WS_POPUP | WS_SYSMENU;
1296 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1297 This->style, This->exStyle, style, exStyle);
1299 SetWindowLongW(window, GWL_STYLE, style);
1300 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1302 /* Inform the window about the update. */
1303 SetWindowPos(window, HWND_TOP, 0, 0,
1304 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1305 ShowWindow(window, SW_NORMAL);
1308 /*****************************************************************************
1309 * IWineD3DDeviceImpl_RestoreWindow
1311 * Helper function that restores a windows' properties when taking it out
1312 * of fullscreen mode
1314 * Params:
1315 * iface: Pointer to the IWineD3DDevice interface
1316 * window: Window to setup
1318 *****************************************************************************/
1319 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1322 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1323 * switch, do nothing
1325 if (!This->style && !This->exStyle) return;
1327 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1328 This, window, This->style, This->exStyle);
1330 SetWindowLongW(window, GWL_STYLE, This->style);
1331 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1333 /* Delete the old values */
1334 This->style = 0;
1335 This->exStyle = 0;
1337 /* Inform the window about the update */
1338 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1339 0, 0, 0, 0, /* Pos, Size, ignored */
1340 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1343 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1344 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1345 IUnknown* parent,
1346 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1347 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1350 HDC hDc;
1351 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1352 HRESULT hr = WINED3D_OK;
1353 IUnknown *bufferParent;
1355 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1357 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1358 * does a device hold a reference to a swap chain giving them a lifetime of the device
1359 * or does the swap chain notify the device of its destruction.
1360 *******************************/
1362 /* Check the params */
1363 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1364 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1365 return WINED3DERR_INVALIDCALL;
1366 } else if (pPresentationParameters->BackBufferCount > 1) {
1367 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");
1370 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1372 /*********************
1373 * Lookup the window Handle and the relating X window handle
1374 ********************/
1376 /* Setup hwnd we are using, plus which display this equates to */
1377 object->win_handle = pPresentationParameters->hDeviceWindow;
1378 if (!object->win_handle) {
1379 object->win_handle = This->createParms.hFocusWindow;
1382 hDc = GetDC(object->win_handle);
1383 TRACE("Using hDc %p\n", hDc);
1385 if (NULL == hDc) {
1386 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1387 return WINED3DERR_NOTAVAILABLE;
1390 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1391 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1392 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1393 ReleaseDC(object->win_handle, hDc);
1395 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1396 * then the corresponding dimension of the client area of the hDeviceWindow
1397 * (or the focus window, if hDeviceWindow is NULL) is taken.
1398 **********************/
1400 if (pPresentationParameters->Windowed &&
1401 ((pPresentationParameters->BackBufferWidth == 0) ||
1402 (pPresentationParameters->BackBufferHeight == 0) ||
1403 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1405 RECT Rect;
1406 GetClientRect(object->win_handle, &Rect);
1408 if (pPresentationParameters->BackBufferWidth == 0) {
1409 pPresentationParameters->BackBufferWidth = Rect.right;
1410 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1412 if (pPresentationParameters->BackBufferHeight == 0) {
1413 pPresentationParameters->BackBufferHeight = Rect.bottom;
1414 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1416 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1417 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1418 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1422 /* Put the correct figures in the presentation parameters */
1423 TRACE("Copying across presentation parameters\n");
1424 object->presentParms = *pPresentationParameters;
1426 TRACE("calling rendertarget CB\n");
1427 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1428 parent,
1429 object->presentParms.BackBufferWidth,
1430 object->presentParms.BackBufferHeight,
1431 object->presentParms.BackBufferFormat,
1432 object->presentParms.MultiSampleType,
1433 object->presentParms.MultiSampleQuality,
1434 TRUE /* Lockable */,
1435 &object->frontBuffer,
1436 NULL /* pShared (always null)*/);
1437 if (object->frontBuffer != NULL) {
1438 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1439 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1440 } else {
1441 ERR("Failed to create the front buffer\n");
1442 goto error;
1446 * Create an opengl context for the display visual
1447 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1448 * use different properties after that point in time. FIXME: How to handle when requested format
1449 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1450 * it chooses is identical to the one already being used!
1451 **********************************/
1452 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1454 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1455 if(!object->context)
1456 return E_OUTOFMEMORY;
1457 object->num_contexts = 1;
1459 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1460 if (!object->context[0]) {
1461 ERR("Failed to create a new context\n");
1462 hr = WINED3DERR_NOTAVAILABLE;
1463 goto error;
1464 } else {
1465 TRACE("Context created (HWND=%p, glContext=%p)\n",
1466 object->win_handle, object->context[0]->glCtx);
1469 /*********************
1470 * Windowed / Fullscreen
1471 *******************/
1474 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1475 * so we should really check to see if there is a fullscreen swapchain already
1476 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1477 **************************************/
1479 if (!pPresentationParameters->Windowed) {
1481 DEVMODEW devmode;
1482 HDC hdc;
1483 int bpp = 0;
1484 RECT clip_rc;
1486 /* Get info on the current display setup */
1487 hdc = GetDC(0);
1488 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1489 ReleaseDC(0, hdc);
1491 /* Change the display settings */
1492 memset(&devmode, 0, sizeof(devmode));
1493 devmode.dmSize = sizeof(devmode);
1494 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1495 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1496 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1497 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1498 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1500 /* For GetDisplayMode */
1501 This->ddraw_width = devmode.dmPelsWidth;
1502 This->ddraw_height = devmode.dmPelsHeight;
1503 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1505 IWineD3DDevice_SetFullscreen(iface, TRUE);
1507 /* And finally clip mouse to our screen */
1508 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1509 ClipCursor(&clip_rc);
1512 /*********************
1513 * Create the back, front and stencil buffers
1514 *******************/
1515 if(object->presentParms.BackBufferCount > 0) {
1516 int i;
1518 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1519 if(!object->backBuffer) {
1520 ERR("Out of memory\n");
1521 hr = E_OUTOFMEMORY;
1522 goto error;
1525 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1526 TRACE("calling rendertarget CB\n");
1527 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1528 parent,
1529 object->presentParms.BackBufferWidth,
1530 object->presentParms.BackBufferHeight,
1531 object->presentParms.BackBufferFormat,
1532 object->presentParms.MultiSampleType,
1533 object->presentParms.MultiSampleQuality,
1534 TRUE /* Lockable */,
1535 &object->backBuffer[i],
1536 NULL /* pShared (always null)*/);
1537 if(hr == WINED3D_OK && object->backBuffer[i]) {
1538 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1539 } else {
1540 ERR("Cannot create new back buffer\n");
1541 goto error;
1543 ENTER_GL();
1544 glDrawBuffer(GL_BACK);
1545 checkGLcall("glDrawBuffer(GL_BACK)");
1546 LEAVE_GL();
1548 } else {
1549 object->backBuffer = NULL;
1551 /* Single buffering - draw to front buffer */
1552 ENTER_GL();
1553 glDrawBuffer(GL_FRONT);
1554 checkGLcall("glDrawBuffer(GL_FRONT)");
1555 LEAVE_GL();
1558 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1559 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1560 TRACE("Creating depth stencil buffer\n");
1561 if (This->depthStencilBuffer == NULL ) {
1562 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1563 parent,
1564 object->presentParms.BackBufferWidth,
1565 object->presentParms.BackBufferHeight,
1566 object->presentParms.AutoDepthStencilFormat,
1567 object->presentParms.MultiSampleType,
1568 object->presentParms.MultiSampleQuality,
1569 FALSE /* FIXME: Discard */,
1570 &This->depthStencilBuffer,
1571 NULL /* pShared (always null)*/ );
1572 if (This->depthStencilBuffer != NULL)
1573 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1576 /** TODO: A check on width, height and multisample types
1577 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1578 ****************************/
1579 object->wantsDepthStencilBuffer = TRUE;
1580 } else {
1581 object->wantsDepthStencilBuffer = FALSE;
1584 TRACE("Created swapchain %p\n", object);
1585 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1586 return WINED3D_OK;
1588 error:
1589 if (object->backBuffer) {
1590 int i;
1591 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1592 if(object->backBuffer[i]) {
1593 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1594 IUnknown_Release(bufferParent); /* once for the get parent */
1595 if (IUnknown_Release(bufferParent) > 0) {
1596 FIXME("(%p) Something's still holding the back buffer\n",This);
1600 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1601 object->backBuffer = NULL;
1603 if(object->context[0])
1604 DestroyContext(This, object->context[0]);
1605 if(object->frontBuffer) {
1606 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1607 IUnknown_Release(bufferParent); /* once for the get parent */
1608 if (IUnknown_Release(bufferParent) > 0) {
1609 FIXME("(%p) Something's still holding the front buffer\n",This);
1612 HeapFree(GetProcessHeap(), 0, object);
1613 return hr;
1616 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1617 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1619 TRACE("(%p)\n", This);
1621 return This->NumberOfSwapChains;
1624 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1626 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1628 if(iSwapChain < This->NumberOfSwapChains) {
1629 *pSwapChain = This->swapchains[iSwapChain];
1630 IWineD3DSwapChain_AddRef(*pSwapChain);
1631 TRACE("(%p) returning %p\n", This, *pSwapChain);
1632 return WINED3D_OK;
1633 } else {
1634 TRACE("Swapchain out of range\n");
1635 *pSwapChain = NULL;
1636 return WINED3DERR_INVALIDCALL;
1640 /*****
1641 * Vertex Declaration
1642 *****/
1643 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1644 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1646 IWineD3DVertexDeclarationImpl *object = NULL;
1647 HRESULT hr = WINED3D_OK;
1649 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1650 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1652 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1654 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1656 return hr;
1659 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1661 unsigned int idx, idx2;
1662 unsigned int offset;
1663 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1664 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1665 BOOL has_blend_idx = has_blend &&
1666 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1667 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1668 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1669 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1670 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1671 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1672 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1674 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1675 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1677 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1678 WINED3DVERTEXELEMENT *elements = NULL;
1680 unsigned int size;
1681 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1682 if (has_blend_idx) num_blends--;
1684 /* Compute declaration size */
1685 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1686 has_psize + has_diffuse + has_specular + num_textures + 1;
1688 /* convert the declaration */
1689 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1690 if (!elements)
1691 return 0;
1693 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1694 idx = 0;
1695 if (has_pos) {
1696 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1697 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1698 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1700 else {
1701 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1702 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1704 elements[idx].UsageIndex = 0;
1705 idx++;
1707 if (has_blend && (num_blends > 0)) {
1708 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1709 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1710 else
1711 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1712 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1713 elements[idx].UsageIndex = 0;
1714 idx++;
1716 if (has_blend_idx) {
1717 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1718 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1719 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1720 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1721 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1722 else
1723 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1724 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1725 elements[idx].UsageIndex = 0;
1726 idx++;
1728 if (has_normal) {
1729 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1730 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1731 elements[idx].UsageIndex = 0;
1732 idx++;
1734 if (has_psize) {
1735 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1736 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1737 elements[idx].UsageIndex = 0;
1738 idx++;
1740 if (has_diffuse) {
1741 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1742 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1743 elements[idx].UsageIndex = 0;
1744 idx++;
1746 if (has_specular) {
1747 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1748 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1749 elements[idx].UsageIndex = 1;
1750 idx++;
1752 for (idx2 = 0; idx2 < num_textures; idx2++) {
1753 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1754 switch (numcoords) {
1755 case WINED3DFVF_TEXTUREFORMAT1:
1756 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1757 break;
1758 case WINED3DFVF_TEXTUREFORMAT2:
1759 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1760 break;
1761 case WINED3DFVF_TEXTUREFORMAT3:
1762 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1763 break;
1764 case WINED3DFVF_TEXTUREFORMAT4:
1765 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1766 break;
1768 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1769 elements[idx].UsageIndex = idx2;
1770 idx++;
1773 /* Now compute offsets, and initialize the rest of the fields */
1774 for (idx = 0, offset = 0; idx < size-1; idx++) {
1775 elements[idx].Stream = 0;
1776 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1777 elements[idx].Offset = offset;
1778 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1781 *ppVertexElements = elements;
1782 return size;
1785 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1786 WINED3DVERTEXELEMENT* elements = NULL;
1787 size_t size;
1788 DWORD hr;
1790 size = ConvertFvfToDeclaration(Fvf, &elements);
1791 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1793 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1794 HeapFree(GetProcessHeap(), 0, elements);
1795 if (hr != S_OK) return hr;
1797 return WINED3D_OK;
1800 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1801 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1803 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1804 HRESULT hr = WINED3D_OK;
1805 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1806 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1808 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1810 if (vertex_declaration) {
1811 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1814 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1816 if (WINED3D_OK != hr) {
1817 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1818 IWineD3DVertexShader_Release(*ppVertexShader);
1819 return WINED3DERR_INVALIDCALL;
1822 return WINED3D_OK;
1825 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1826 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1827 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1828 HRESULT hr = WINED3D_OK;
1830 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1831 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1832 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1833 if (WINED3D_OK == hr) {
1834 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1835 } else {
1836 WARN("(%p) : Failed to create pixel shader\n", This);
1839 return hr;
1842 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1844 IWineD3DPaletteImpl *object;
1845 HRESULT hr;
1846 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1848 /* Create the new object */
1849 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1850 if(!object) {
1851 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1852 return E_OUTOFMEMORY;
1855 object->lpVtbl = &IWineD3DPalette_Vtbl;
1856 object->ref = 1;
1857 object->Flags = Flags;
1858 object->parent = Parent;
1859 object->wineD3DDevice = This;
1860 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1862 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1864 if(!object->hpal) {
1865 HeapFree( GetProcessHeap(), 0, object);
1866 return E_OUTOFMEMORY;
1869 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1870 if(FAILED(hr)) {
1871 IWineD3DPalette_Release((IWineD3DPalette *) object);
1872 return hr;
1875 *Palette = (IWineD3DPalette *) object;
1877 return WINED3D_OK;
1880 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1881 HBITMAP hbm;
1882 BITMAP bm;
1883 HRESULT hr;
1884 HDC dcb = NULL, dcs = NULL;
1885 WINEDDCOLORKEY colorkey;
1887 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1888 if(hbm)
1890 GetObjectA(hbm, sizeof(BITMAP), &bm);
1891 dcb = CreateCompatibleDC(NULL);
1892 if(!dcb) goto out;
1893 SelectObject(dcb, hbm);
1895 else
1897 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1898 * couldn't be loaded
1900 memset(&bm, 0, sizeof(bm));
1901 bm.bmWidth = 32;
1902 bm.bmHeight = 32;
1905 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1906 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1907 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1908 if(FAILED(hr)) {
1909 ERR("Wine logo requested, but failed to create surface\n");
1910 goto out;
1913 if(dcb) {
1914 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1915 if(FAILED(hr)) goto out;
1916 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1917 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1919 colorkey.dwColorSpaceLowValue = 0;
1920 colorkey.dwColorSpaceHighValue = 0;
1921 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1922 } else {
1923 /* Fill the surface with a white color to show that wined3d is there */
1924 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1927 out:
1928 if(dcb) {
1929 DeleteDC(dcb);
1931 if(hbm) {
1932 DeleteObject(hbm);
1934 return;
1937 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1939 IWineD3DSwapChainImpl *swapchain;
1940 HRESULT hr;
1941 DWORD state;
1943 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1944 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1946 /* TODO: Test if OpenGL is compiled in and loaded */
1948 TRACE("(%p) : Creating stateblock\n", This);
1949 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1950 hr = IWineD3DDevice_CreateStateBlock(iface,
1951 WINED3DSBT_INIT,
1952 (IWineD3DStateBlock **)&This->stateBlock,
1953 NULL);
1954 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1955 WARN("Failed to create stateblock\n");
1956 goto err_out;
1958 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1959 This->updateStateBlock = This->stateBlock;
1960 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1962 hr = allocate_shader_constants(This->updateStateBlock);
1963 if (WINED3D_OK != hr) {
1964 goto err_out;
1967 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1968 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1969 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1971 /* Initialize the texture unit mapping to a 1:1 mapping */
1972 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1973 if (state < GL_LIMITS(fragment_samplers)) {
1974 This->texUnitMap[state] = state;
1975 This->rev_tex_unit_map[state] = state;
1976 } else {
1977 This->texUnitMap[state] = -1;
1978 This->rev_tex_unit_map[state] = -1;
1982 /* Setup the implicit swapchain */
1983 TRACE("Creating implicit swapchain\n");
1984 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1985 if (FAILED(hr) || !swapchain) {
1986 WARN("Failed to create implicit swapchain\n");
1987 goto err_out;
1990 This->NumberOfSwapChains = 1;
1991 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1992 if(!This->swapchains) {
1993 ERR("Out of memory!\n");
1994 goto err_out;
1996 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1998 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
2000 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2001 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2002 This->render_targets[0] = swapchain->backBuffer[0];
2003 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2005 else {
2006 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2007 This->render_targets[0] = swapchain->frontBuffer;
2008 This->lastActiveRenderTarget = swapchain->frontBuffer;
2010 IWineD3DSurface_AddRef(This->render_targets[0]);
2011 This->activeContext = swapchain->context[0];
2012 This->lastThread = GetCurrentThreadId();
2014 /* Depth Stencil support */
2015 This->stencilBufferTarget = This->depthStencilBuffer;
2016 if (NULL != This->stencilBufferTarget) {
2017 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2020 /* Set up some starting GL setup */
2021 ENTER_GL();
2023 /* Setup all the devices defaults */
2024 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2025 #if 0
2026 IWineD3DImpl_CheckGraphicsMemory();
2027 #endif
2029 { /* Set a default viewport */
2030 WINED3DVIEWPORT vp;
2031 vp.X = 0;
2032 vp.Y = 0;
2033 vp.Width = pPresentationParameters->BackBufferWidth;
2034 vp.Height = pPresentationParameters->BackBufferHeight;
2035 vp.MinZ = 0.0f;
2036 vp.MaxZ = 1.0f;
2037 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2040 /* Initialize the current view state */
2041 This->view_ident = 1;
2042 This->contexts[0]->last_was_rhw = 0;
2043 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2044 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2046 switch(wined3d_settings.offscreen_rendering_mode) {
2047 case ORM_FBO:
2048 case ORM_PBUFFER:
2049 This->offscreenBuffer = GL_BACK;
2050 break;
2052 case ORM_BACKBUFFER:
2054 if(GL_LIMITS(aux_buffers) > 0) {
2055 TRACE("Using auxilliary buffer for offscreen rendering\n");
2056 This->offscreenBuffer = GL_AUX0;
2057 } else {
2058 TRACE("Using back buffer for offscreen rendering\n");
2059 This->offscreenBuffer = GL_BACK;
2064 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2065 LEAVE_GL();
2067 /* Clear the screen */
2068 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2069 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2070 0x00, 1.0, 0);
2072 This->d3d_initialized = TRUE;
2074 if(wined3d_settings.logo) {
2075 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2077 return WINED3D_OK;
2079 err_out:
2080 HeapFree(GetProcessHeap(), 0, This->render_targets);
2081 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2082 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2083 HeapFree(GetProcessHeap(), 0, This->swapchains);
2084 This->NumberOfSwapChains = 0;
2085 if(swapchain) {
2086 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2088 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2089 if(This->stateBlock) {
2090 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2091 This->stateBlock = NULL;
2093 return hr;
2096 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2098 int sampler;
2099 UINT i;
2100 TRACE("(%p)\n", This);
2102 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2104 /* I don't think that the interface guarants that the device is destroyed from the same thread
2105 * it was created. Thus make sure a context is active for the glDelete* calls
2107 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2109 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2111 TRACE("Deleting high order patches\n");
2112 for(i = 0; i < PATCHMAP_SIZE; i++) {
2113 struct list *e1, *e2;
2114 struct WineD3DRectPatch *patch;
2115 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2116 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2117 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2121 /* Delete the palette conversion shader if it is around */
2122 if(This->paletteConversionShader) {
2123 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2126 /* Delete the pbuffer context if there is any */
2127 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2129 /* Delete the mouse cursor texture */
2130 if(This->cursorTexture) {
2131 ENTER_GL();
2132 glDeleteTextures(1, &This->cursorTexture);
2133 LEAVE_GL();
2134 This->cursorTexture = 0;
2137 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2138 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2140 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2141 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2144 /* Release the update stateblock */
2145 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2146 if(This->updateStateBlock != This->stateBlock)
2147 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2149 This->updateStateBlock = NULL;
2151 { /* because were not doing proper internal refcounts releasing the primary state block
2152 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2153 to set this->stateBlock = NULL; first */
2154 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2155 This->stateBlock = NULL;
2157 /* Release the stateblock */
2158 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2159 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2163 /* Release the buffers (with sanity checks)*/
2164 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2165 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2166 if(This->depthStencilBuffer != This->stencilBufferTarget)
2167 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2169 This->stencilBufferTarget = NULL;
2171 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2172 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2173 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2175 TRACE("Setting rendertarget to NULL\n");
2176 This->render_targets[0] = NULL;
2178 if (This->depthStencilBuffer) {
2179 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2180 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2182 This->depthStencilBuffer = NULL;
2185 for(i=0; i < This->NumberOfSwapChains; i++) {
2186 TRACE("Releasing the implicit swapchain %d\n", i);
2187 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2188 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2192 HeapFree(GetProcessHeap(), 0, This->swapchains);
2193 This->swapchains = NULL;
2194 This->NumberOfSwapChains = 0;
2196 HeapFree(GetProcessHeap(), 0, This->render_targets);
2197 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2198 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2199 This->render_targets = NULL;
2200 This->fbo_color_attachments = NULL;
2201 This->draw_buffers = NULL;
2204 This->d3d_initialized = FALSE;
2205 return WINED3D_OK;
2208 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2210 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2212 /* Setup the window for fullscreen mode */
2213 if(fullscreen && !This->ddraw_fullscreen) {
2214 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2215 } else if(!fullscreen && This->ddraw_fullscreen) {
2216 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2219 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2220 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2221 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2222 * separately.
2224 This->ddraw_fullscreen = fullscreen;
2227 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2228 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2229 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2231 * There is no way to deactivate thread safety once it is enabled.
2233 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2236 /*For now just store the flag(needed in case of ddraw) */
2237 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2239 return;
2242 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2243 DEVMODEW devmode;
2244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2245 LONG ret;
2246 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2247 RECT clip_rc;
2249 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2251 /* Resize the screen even without a window:
2252 * The app could have unset it with SetCooperativeLevel, but not called
2253 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2254 * but we don't have any hwnd
2257 memset(&devmode, 0, sizeof(devmode));
2258 devmode.dmSize = sizeof(devmode);
2259 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2260 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2261 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2262 devmode.dmPelsWidth = pMode->Width;
2263 devmode.dmPelsHeight = pMode->Height;
2265 devmode.dmDisplayFrequency = pMode->RefreshRate;
2266 if (pMode->RefreshRate != 0) {
2267 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2270 /* Only change the mode if necessary */
2271 if( (This->ddraw_width == pMode->Width) &&
2272 (This->ddraw_height == pMode->Height) &&
2273 (This->ddraw_format == pMode->Format) &&
2274 (pMode->RefreshRate == 0) ) {
2275 return WINED3D_OK;
2278 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2279 if (ret != DISP_CHANGE_SUCCESSFUL) {
2280 if(devmode.dmDisplayFrequency != 0) {
2281 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2282 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2283 devmode.dmDisplayFrequency = 0;
2284 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2286 if(ret != DISP_CHANGE_SUCCESSFUL) {
2287 return WINED3DERR_NOTAVAILABLE;
2291 /* Store the new values */
2292 This->ddraw_width = pMode->Width;
2293 This->ddraw_height = pMode->Height;
2294 This->ddraw_format = pMode->Format;
2296 /* Only do this with a window of course */
2297 if(This->ddraw_window)
2298 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2300 /* And finally clip mouse to our screen */
2301 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2302 ClipCursor(&clip_rc);
2304 return WINED3D_OK;
2307 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2309 *ppD3D= This->wineD3D;
2310 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2311 IWineD3D_AddRef(*ppD3D);
2312 return WINED3D_OK;
2315 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2318 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2319 (This->adapter->TextureRam/(1024*1024)),
2320 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2321 /* return simulated texture memory left */
2322 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2327 /*****
2328 * Get / Set FVF
2329 *****/
2330 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2333 /* Update the current state block */
2334 This->updateStateBlock->changed.fvf = TRUE;
2336 if(This->updateStateBlock->fvf == fvf) {
2337 TRACE("Application is setting the old fvf over, nothing to do\n");
2338 return WINED3D_OK;
2341 This->updateStateBlock->fvf = fvf;
2342 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2343 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2344 return WINED3D_OK;
2348 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2350 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2351 *pfvf = This->stateBlock->fvf;
2352 return WINED3D_OK;
2355 /*****
2356 * Get / Set Stream Source
2357 *****/
2358 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2360 IWineD3DVertexBuffer *oldSrc;
2362 if (StreamNumber >= MAX_STREAMS) {
2363 WARN("Stream out of range %d\n", StreamNumber);
2364 return WINED3DERR_INVALIDCALL;
2367 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2368 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2370 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2372 if(oldSrc == pStreamData &&
2373 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2374 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2375 TRACE("Application is setting the old values over, nothing to do\n");
2376 return WINED3D_OK;
2379 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2380 if (pStreamData) {
2381 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2382 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2385 /* Handle recording of state blocks */
2386 if (This->isRecordingState) {
2387 TRACE("Recording... not performing anything\n");
2388 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2389 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2390 return WINED3D_OK;
2393 /* Need to do a getParent and pass the reffs up */
2394 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2395 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2396 so for now, just count internally */
2397 if (pStreamData != NULL) {
2398 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2399 InterlockedIncrement(&vbImpl->bindCount);
2400 IWineD3DVertexBuffer_AddRef(pStreamData);
2402 if (oldSrc != NULL) {
2403 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2404 IWineD3DVertexBuffer_Release(oldSrc);
2407 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2409 return WINED3D_OK;
2412 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2415 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2416 This->stateBlock->streamSource[StreamNumber],
2417 This->stateBlock->streamOffset[StreamNumber],
2418 This->stateBlock->streamStride[StreamNumber]);
2420 if (StreamNumber >= MAX_STREAMS) {
2421 WARN("Stream out of range %d\n", StreamNumber);
2422 return WINED3DERR_INVALIDCALL;
2424 *pStream = This->stateBlock->streamSource[StreamNumber];
2425 *pStride = This->stateBlock->streamStride[StreamNumber];
2426 if (pOffset) {
2427 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2430 if (*pStream != NULL) {
2431 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2433 return WINED3D_OK;
2436 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2438 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2439 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2441 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2442 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2444 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2445 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2447 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2448 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2449 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2452 return WINED3D_OK;
2455 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2458 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2459 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2461 TRACE("(%p) : returning %d\n", This, *Divider);
2463 return WINED3D_OK;
2466 /*****
2467 * Get / Set & Multiply Transform
2468 *****/
2469 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2472 /* Most of this routine, comments included copied from ddraw tree initially: */
2473 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2475 /* Handle recording of state blocks */
2476 if (This->isRecordingState) {
2477 TRACE("Recording... not performing anything\n");
2478 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2479 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2480 return WINED3D_OK;
2484 * If the new matrix is the same as the current one,
2485 * we cut off any further processing. this seems to be a reasonable
2486 * optimization because as was noticed, some apps (warcraft3 for example)
2487 * tend towards setting the same matrix repeatedly for some reason.
2489 * From here on we assume that the new matrix is different, wherever it matters.
2491 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2492 TRACE("The app is setting the same matrix over again\n");
2493 return WINED3D_OK;
2494 } else {
2495 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2499 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2500 where ViewMat = Camera space, WorldMat = world space.
2502 In OpenGL, camera and world space is combined into GL_MODELVIEW
2503 matrix. The Projection matrix stay projection matrix.
2506 /* Capture the times we can just ignore the change for now */
2507 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2508 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2509 /* Handled by the state manager */
2512 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2513 return WINED3D_OK;
2516 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2518 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2519 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2520 return WINED3D_OK;
2523 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2524 WINED3DMATRIX *mat = NULL;
2525 WINED3DMATRIX temp;
2527 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2528 * below means it will be recorded in a state block change, but it
2529 * works regardless where it is recorded.
2530 * If this is found to be wrong, change to StateBlock.
2532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2533 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2535 if (State < HIGHEST_TRANSFORMSTATE)
2537 mat = &This->updateStateBlock->transforms[State];
2538 } else {
2539 FIXME("Unhandled transform state!!\n");
2542 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2544 /* Apply change via set transform - will reapply to eg. lights this way */
2545 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2548 /*****
2549 * Get / Set Light
2550 *****/
2551 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2552 you can reference any indexes you want as long as that number max are enabled at any
2553 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2554 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2555 but when recording, just build a chain pretty much of commands to be replayed. */
2557 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2558 float rho;
2559 PLIGHTINFOEL *object = NULL;
2560 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2561 struct list *e;
2563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2564 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2566 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2567 * the gl driver.
2569 if(!pLight) {
2570 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2571 return WINED3DERR_INVALIDCALL;
2574 switch(pLight->Type) {
2575 case WINED3DLIGHT_POINT:
2576 case WINED3DLIGHT_SPOT:
2577 case WINED3DLIGHT_PARALLELPOINT:
2578 case WINED3DLIGHT_GLSPOT:
2579 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2580 * most wanted
2582 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2583 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2584 return WINED3DERR_INVALIDCALL;
2586 break;
2588 case WINED3DLIGHT_DIRECTIONAL:
2589 /* Ignores attenuation */
2590 break;
2592 default:
2593 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2594 return WINED3DERR_INVALIDCALL;
2597 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2598 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2599 if(object->OriginalIndex == Index) break;
2600 object = NULL;
2603 if(!object) {
2604 TRACE("Adding new light\n");
2605 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2606 if(!object) {
2607 ERR("Out of memory error when allocating a light\n");
2608 return E_OUTOFMEMORY;
2610 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2611 object->glIndex = -1;
2612 object->OriginalIndex = Index;
2613 object->changed = TRUE;
2616 /* Initialize the object */
2617 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,
2618 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2619 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2620 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2621 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2622 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2623 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2625 /* Save away the information */
2626 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2628 switch (pLight->Type) {
2629 case WINED3DLIGHT_POINT:
2630 /* Position */
2631 object->lightPosn[0] = pLight->Position.x;
2632 object->lightPosn[1] = pLight->Position.y;
2633 object->lightPosn[2] = pLight->Position.z;
2634 object->lightPosn[3] = 1.0f;
2635 object->cutoff = 180.0f;
2636 /* FIXME: Range */
2637 break;
2639 case WINED3DLIGHT_DIRECTIONAL:
2640 /* Direction */
2641 object->lightPosn[0] = -pLight->Direction.x;
2642 object->lightPosn[1] = -pLight->Direction.y;
2643 object->lightPosn[2] = -pLight->Direction.z;
2644 object->lightPosn[3] = 0.0;
2645 object->exponent = 0.0f;
2646 object->cutoff = 180.0f;
2647 break;
2649 case WINED3DLIGHT_SPOT:
2650 /* Position */
2651 object->lightPosn[0] = pLight->Position.x;
2652 object->lightPosn[1] = pLight->Position.y;
2653 object->lightPosn[2] = pLight->Position.z;
2654 object->lightPosn[3] = 1.0;
2656 /* Direction */
2657 object->lightDirn[0] = pLight->Direction.x;
2658 object->lightDirn[1] = pLight->Direction.y;
2659 object->lightDirn[2] = pLight->Direction.z;
2660 object->lightDirn[3] = 1.0;
2663 * opengl-ish and d3d-ish spot lights use too different models for the
2664 * light "intensity" as a function of the angle towards the main light direction,
2665 * so we only can approximate very roughly.
2666 * however spot lights are rather rarely used in games (if ever used at all).
2667 * furthermore if still used, probably nobody pays attention to such details.
2669 if (pLight->Falloff == 0) {
2670 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2671 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2672 * will always be 1.0 for both of them, and we don't have to care for the
2673 * rest of the rather complex calculation
2675 object->exponent = 0;
2676 } else {
2677 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2678 if (rho < 0.0001) rho = 0.0001f;
2679 object->exponent = -0.3/log(cos(rho/2));
2681 if (object->exponent > 128.0) {
2682 object->exponent = 128.0;
2684 object->cutoff = pLight->Phi*90/M_PI;
2686 /* FIXME: Range */
2687 break;
2689 default:
2690 FIXME("Unrecognized light type %d\n", pLight->Type);
2693 /* Update the live definitions if the light is currently assigned a glIndex */
2694 if (object->glIndex != -1 && !This->isRecordingState) {
2695 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2697 return WINED3D_OK;
2700 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2701 PLIGHTINFOEL *lightInfo = NULL;
2702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2703 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2704 struct list *e;
2705 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2707 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2708 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2709 if(lightInfo->OriginalIndex == Index) break;
2710 lightInfo = NULL;
2713 if (lightInfo == NULL) {
2714 TRACE("Light information requested but light not defined\n");
2715 return WINED3DERR_INVALIDCALL;
2718 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2719 return WINED3D_OK;
2722 /*****
2723 * Get / Set Light Enable
2724 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2725 *****/
2726 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2727 PLIGHTINFOEL *lightInfo = NULL;
2728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2729 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2730 struct list *e;
2731 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2733 /* Tests show true = 128...not clear why */
2734 Enable = Enable? 128: 0;
2736 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2737 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2738 if(lightInfo->OriginalIndex == Index) break;
2739 lightInfo = NULL;
2741 TRACE("Found light: %p\n", lightInfo);
2743 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2744 if (lightInfo == NULL) {
2746 TRACE("Light enabled requested but light not defined, so defining one!\n");
2747 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2749 /* Search for it again! Should be fairly quick as near head of list */
2750 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2751 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2752 if(lightInfo->OriginalIndex == Index) break;
2753 lightInfo = NULL;
2755 if (lightInfo == NULL) {
2756 FIXME("Adding default lights has failed dismally\n");
2757 return WINED3DERR_INVALIDCALL;
2761 lightInfo->enabledChanged = TRUE;
2762 if(!Enable) {
2763 if(lightInfo->glIndex != -1) {
2764 if(!This->isRecordingState) {
2765 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2768 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2769 lightInfo->glIndex = -1;
2770 } else {
2771 TRACE("Light already disabled, nothing to do\n");
2773 } else {
2774 if (lightInfo->glIndex != -1) {
2775 /* nop */
2776 TRACE("Nothing to do as light was enabled\n");
2777 } else {
2778 int i;
2779 /* Find a free gl light */
2780 for(i = 0; i < This->maxConcurrentLights; i++) {
2781 if(This->stateBlock->activeLights[i] == NULL) {
2782 This->stateBlock->activeLights[i] = lightInfo;
2783 lightInfo->glIndex = i;
2784 break;
2787 if(lightInfo->glIndex == -1) {
2788 ERR("Too many concurrently active lights\n");
2789 return WINED3DERR_INVALIDCALL;
2792 /* i == lightInfo->glIndex */
2793 if(!This->isRecordingState) {
2794 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2799 return WINED3D_OK;
2802 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2804 PLIGHTINFOEL *lightInfo = NULL;
2805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2806 struct list *e;
2807 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2808 TRACE("(%p) : for idx(%d)\n", This, Index);
2810 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2811 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2812 if(lightInfo->OriginalIndex == Index) break;
2813 lightInfo = NULL;
2816 if (lightInfo == NULL) {
2817 TRACE("Light enabled state requested but light not defined\n");
2818 return WINED3DERR_INVALIDCALL;
2820 /* true is 128 according to SetLightEnable */
2821 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2822 return WINED3D_OK;
2825 /*****
2826 * Get / Set Clip Planes
2827 *****/
2828 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2830 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2832 /* Validate Index */
2833 if (Index >= GL_LIMITS(clipplanes)) {
2834 TRACE("Application has requested clipplane this device doesn't support\n");
2835 return WINED3DERR_INVALIDCALL;
2838 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2840 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2841 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2842 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2843 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2844 TRACE("Application is setting old values over, nothing to do\n");
2845 return WINED3D_OK;
2848 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2849 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2850 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2851 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2853 /* Handle recording of state blocks */
2854 if (This->isRecordingState) {
2855 TRACE("Recording... not performing anything\n");
2856 return WINED3D_OK;
2859 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2861 return WINED3D_OK;
2864 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2866 TRACE("(%p) : for idx %d\n", This, Index);
2868 /* Validate Index */
2869 if (Index >= GL_LIMITS(clipplanes)) {
2870 TRACE("Application has requested clipplane this device doesn't support\n");
2871 return WINED3DERR_INVALIDCALL;
2874 pPlane[0] = This->stateBlock->clipplane[Index][0];
2875 pPlane[1] = This->stateBlock->clipplane[Index][1];
2876 pPlane[2] = This->stateBlock->clipplane[Index][2];
2877 pPlane[3] = This->stateBlock->clipplane[Index][3];
2878 return WINED3D_OK;
2881 /*****
2882 * Get / Set Clip Plane Status
2883 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2884 *****/
2885 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2887 FIXME("(%p) : stub\n", This);
2888 if (NULL == pClipStatus) {
2889 return WINED3DERR_INVALIDCALL;
2891 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2892 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2893 return WINED3D_OK;
2896 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2898 FIXME("(%p) : stub\n", This);
2899 if (NULL == pClipStatus) {
2900 return WINED3DERR_INVALIDCALL;
2902 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2903 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2904 return WINED3D_OK;
2907 /*****
2908 * Get / Set Material
2909 *****/
2910 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2913 This->updateStateBlock->changed.material = TRUE;
2914 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2916 /* Handle recording of state blocks */
2917 if (This->isRecordingState) {
2918 TRACE("Recording... not performing anything\n");
2919 return WINED3D_OK;
2922 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2923 return WINED3D_OK;
2926 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2928 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2929 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2930 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2931 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2932 pMaterial->Ambient.b, pMaterial->Ambient.a);
2933 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2934 pMaterial->Specular.b, pMaterial->Specular.a);
2935 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2936 pMaterial->Emissive.b, pMaterial->Emissive.a);
2937 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2939 return WINED3D_OK;
2942 /*****
2943 * Get / Set Indices
2944 *****/
2945 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2947 IWineD3DIndexBuffer *oldIdxs;
2949 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2950 oldIdxs = This->updateStateBlock->pIndexData;
2952 This->updateStateBlock->changed.indices = TRUE;
2953 This->updateStateBlock->pIndexData = pIndexData;
2955 /* Handle recording of state blocks */
2956 if (This->isRecordingState) {
2957 TRACE("Recording... not performing anything\n");
2958 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2959 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2960 return WINED3D_OK;
2963 if(oldIdxs != pIndexData) {
2964 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2965 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2966 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2968 return WINED3D_OK;
2971 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2974 *ppIndexData = This->stateBlock->pIndexData;
2976 /* up ref count on ppindexdata */
2977 if (*ppIndexData) {
2978 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2979 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2980 }else{
2981 TRACE("(%p) No index data set\n", This);
2983 TRACE("Returning %p\n", *ppIndexData);
2985 return WINED3D_OK;
2988 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2989 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2991 TRACE("(%p)->(%d)\n", This, BaseIndex);
2993 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2994 TRACE("Application is setting the old value over, nothing to do\n");
2995 return WINED3D_OK;
2998 This->updateStateBlock->baseVertexIndex = BaseIndex;
3000 if (This->isRecordingState) {
3001 TRACE("Recording... not performing anything\n");
3002 return WINED3D_OK;
3004 /* The base vertex index affects the stream sources */
3005 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3006 return WINED3D_OK;
3009 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3011 TRACE("(%p) : base_index %p\n", This, base_index);
3013 *base_index = This->stateBlock->baseVertexIndex;
3015 TRACE("Returning %u\n", *base_index);
3017 return WINED3D_OK;
3020 /*****
3021 * Get / Set Viewports
3022 *****/
3023 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3026 TRACE("(%p)\n", This);
3027 This->updateStateBlock->changed.viewport = TRUE;
3028 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3030 /* Handle recording of state blocks */
3031 if (This->isRecordingState) {
3032 TRACE("Recording... not performing anything\n");
3033 return WINED3D_OK;
3036 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3037 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3039 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3040 return WINED3D_OK;
3044 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3046 TRACE("(%p)\n", This);
3047 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3048 return WINED3D_OK;
3051 /*****
3052 * Get / Set Render States
3053 * TODO: Verify against dx9 definitions
3054 *****/
3055 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3058 DWORD oldValue = This->stateBlock->renderState[State];
3060 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3062 This->updateStateBlock->changed.renderState[State] = TRUE;
3063 This->updateStateBlock->renderState[State] = Value;
3065 /* Handle recording of state blocks */
3066 if (This->isRecordingState) {
3067 TRACE("Recording... not performing anything\n");
3068 return WINED3D_OK;
3071 /* Compared here and not before the assignment to allow proper stateblock recording */
3072 if(Value == oldValue) {
3073 TRACE("Application is setting the old value over, nothing to do\n");
3074 } else {
3075 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3078 return WINED3D_OK;
3081 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3083 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3084 *pValue = This->stateBlock->renderState[State];
3085 return WINED3D_OK;
3088 /*****
3089 * Get / Set Sampler States
3090 * TODO: Verify against dx9 definitions
3091 *****/
3093 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3094 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3095 DWORD oldValue;
3097 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3098 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3100 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3101 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3105 * SetSampler is designed to allow for more than the standard up to 8 textures
3106 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3107 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3109 * http://developer.nvidia.com/object/General_FAQ.html#t6
3111 * There are two new settings for GForce
3112 * the sampler one:
3113 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3114 * and the texture one:
3115 * GL_MAX_TEXTURE_COORDS_ARB.
3116 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3117 ******************/
3119 oldValue = This->stateBlock->samplerState[Sampler][Type];
3120 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3121 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3123 /* Handle recording of state blocks */
3124 if (This->isRecordingState) {
3125 TRACE("Recording... not performing anything\n");
3126 return WINED3D_OK;
3129 if(oldValue == Value) {
3130 TRACE("Application is setting the old value over, nothing to do\n");
3131 return WINED3D_OK;
3134 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3136 return WINED3D_OK;
3139 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3142 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3143 This, Sampler, debug_d3dsamplerstate(Type), Type);
3145 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3146 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3149 *Value = This->stateBlock->samplerState[Sampler][Type];
3150 TRACE("(%p) : Returning %#x\n", This, *Value);
3152 return WINED3D_OK;
3155 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3158 This->updateStateBlock->changed.scissorRect = TRUE;
3159 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3160 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3161 return WINED3D_OK;
3163 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3165 if(This->isRecordingState) {
3166 TRACE("Recording... not performing anything\n");
3167 return WINED3D_OK;
3170 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3172 return WINED3D_OK;
3175 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3178 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3179 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3180 return WINED3D_OK;
3183 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3185 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3187 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3189 This->updateStateBlock->vertexDecl = pDecl;
3190 This->updateStateBlock->changed.vertexDecl = TRUE;
3192 if (This->isRecordingState) {
3193 TRACE("Recording... not performing anything\n");
3194 return WINED3D_OK;
3195 } else if(pDecl == oldDecl) {
3196 /* Checked after the assignment to allow proper stateblock recording */
3197 TRACE("Application is setting the old declaration over, nothing to do\n");
3198 return WINED3D_OK;
3201 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3202 return WINED3D_OK;
3205 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3208 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3210 *ppDecl = This->stateBlock->vertexDecl;
3211 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3212 return WINED3D_OK;
3215 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3217 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3219 This->updateStateBlock->vertexShader = pShader;
3220 This->updateStateBlock->changed.vertexShader = TRUE;
3222 if (This->isRecordingState) {
3223 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3224 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3225 TRACE("Recording... not performing anything\n");
3226 return WINED3D_OK;
3227 } else if(oldShader == pShader) {
3228 /* Checked here to allow proper stateblock recording */
3229 TRACE("App is setting the old shader over, nothing to do\n");
3230 return WINED3D_OK;
3233 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3234 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3235 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3237 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3239 return WINED3D_OK;
3242 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3245 if (NULL == ppShader) {
3246 return WINED3DERR_INVALIDCALL;
3248 *ppShader = This->stateBlock->vertexShader;
3249 if( NULL != *ppShader)
3250 IWineD3DVertexShader_AddRef(*ppShader);
3252 TRACE("(%p) : returning %p\n", This, *ppShader);
3253 return WINED3D_OK;
3256 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3257 IWineD3DDevice *iface,
3258 UINT start,
3259 CONST BOOL *srcData,
3260 UINT count) {
3262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3263 int i, cnt = min(count, MAX_CONST_B - start);
3265 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3266 iface, srcData, start, count);
3268 if (srcData == NULL || cnt < 0)
3269 return WINED3DERR_INVALIDCALL;
3271 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3272 for (i = 0; i < cnt; i++)
3273 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3275 for (i = start; i < cnt + start; ++i) {
3276 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3279 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3281 return WINED3D_OK;
3284 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3285 IWineD3DDevice *iface,
3286 UINT start,
3287 BOOL *dstData,
3288 UINT count) {
3290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3291 int cnt = min(count, MAX_CONST_B - start);
3293 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3294 iface, dstData, start, count);
3296 if (dstData == NULL || cnt < 0)
3297 return WINED3DERR_INVALIDCALL;
3299 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3300 return WINED3D_OK;
3303 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3304 IWineD3DDevice *iface,
3305 UINT start,
3306 CONST int *srcData,
3307 UINT count) {
3309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3310 int i, cnt = min(count, MAX_CONST_I - start);
3312 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3313 iface, srcData, start, count);
3315 if (srcData == NULL || cnt < 0)
3316 return WINED3DERR_INVALIDCALL;
3318 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3319 for (i = 0; i < cnt; i++)
3320 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3321 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3323 for (i = start; i < cnt + start; ++i) {
3324 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3327 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3329 return WINED3D_OK;
3332 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3333 IWineD3DDevice *iface,
3334 UINT start,
3335 int *dstData,
3336 UINT count) {
3338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3339 int cnt = min(count, MAX_CONST_I - start);
3341 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3342 iface, dstData, start, count);
3344 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3345 return WINED3DERR_INVALIDCALL;
3347 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3348 return WINED3D_OK;
3351 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3352 IWineD3DDevice *iface,
3353 UINT start,
3354 CONST float *srcData,
3355 UINT count) {
3357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3358 int i;
3360 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3361 iface, srcData, start, count);
3363 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3364 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3365 return WINED3DERR_INVALIDCALL;
3367 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3368 if(TRACE_ON(d3d)) {
3369 for (i = 0; i < count; i++)
3370 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3371 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3374 for (i = start; i < count + start; ++i) {
3375 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3376 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3377 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3378 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3379 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3381 ptr->idx[ptr->count++] = i;
3382 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3386 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3388 return WINED3D_OK;
3391 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3392 IWineD3DDevice *iface,
3393 UINT start,
3394 float *dstData,
3395 UINT count) {
3397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3398 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3400 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3401 iface, dstData, start, count);
3403 if (dstData == NULL || cnt < 0)
3404 return WINED3DERR_INVALIDCALL;
3406 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3407 return WINED3D_OK;
3410 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3411 DWORD i;
3412 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3413 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3417 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3418 int i = This->rev_tex_unit_map[unit];
3419 int j = This->texUnitMap[stage];
3421 This->texUnitMap[stage] = unit;
3422 if (i != -1 && i != stage) {
3423 This->texUnitMap[i] = -1;
3426 This->rev_tex_unit_map[unit] = stage;
3427 if (j != -1 && j != unit) {
3428 This->rev_tex_unit_map[j] = -1;
3432 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3433 int i;
3435 for (i = 0; i < MAX_TEXTURES; ++i) {
3436 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3437 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3438 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3439 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3440 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3441 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3442 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3443 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3445 if (color_op == WINED3DTOP_DISABLE) {
3446 /* Not used, and disable higher stages */
3447 while (i < MAX_TEXTURES) {
3448 This->fixed_function_usage_map[i] = FALSE;
3449 ++i;
3451 break;
3454 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3455 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3456 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3457 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3458 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3459 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3460 This->fixed_function_usage_map[i] = TRUE;
3461 } else {
3462 This->fixed_function_usage_map[i] = FALSE;
3465 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3466 This->fixed_function_usage_map[i+1] = TRUE;
3471 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3472 int i, tex;
3474 device_update_fixed_function_usage_map(This);
3476 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3477 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3478 if (!This->fixed_function_usage_map[i]) continue;
3480 if (This->texUnitMap[i] != i) {
3481 device_map_stage(This, i, i);
3482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3483 markTextureStagesDirty(This, i);
3486 return;
3489 /* Now work out the mapping */
3490 tex = 0;
3491 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3492 if (!This->fixed_function_usage_map[i]) continue;
3494 if (This->texUnitMap[i] != tex) {
3495 device_map_stage(This, i, tex);
3496 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3497 markTextureStagesDirty(This, i);
3500 ++tex;
3504 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3505 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3506 int i;
3508 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3509 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3510 device_map_stage(This, i, i);
3511 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3512 if (i < MAX_TEXTURES) {
3513 markTextureStagesDirty(This, i);
3519 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3520 int current_mapping = This->rev_tex_unit_map[unit];
3522 if (current_mapping == -1) {
3523 /* Not currently used */
3524 return TRUE;
3527 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3528 /* Used by a fragment sampler */
3530 if (!pshader_sampler_tokens) {
3531 /* No pixel shader, check fixed function */
3532 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3535 /* Pixel shader, check the shader's sampler map */
3536 return !pshader_sampler_tokens[current_mapping];
3539 /* Used by a vertex sampler */
3540 return !vshader_sampler_tokens[current_mapping];
3543 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3544 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3545 DWORD *pshader_sampler_tokens = NULL;
3546 int start = GL_LIMITS(combined_samplers) - 1;
3547 int i;
3549 if (ps) {
3550 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3552 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3553 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3554 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3557 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3558 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3559 if (vshader_sampler_tokens[i]) {
3560 if (This->texUnitMap[vsampler_idx] != -1) {
3561 /* Already mapped somewhere */
3562 continue;
3565 while (start >= 0) {
3566 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3567 device_map_stage(This, vsampler_idx, start);
3568 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3570 --start;
3571 break;
3574 --start;
3580 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3581 BOOL vs = use_vs(This);
3582 BOOL ps = use_ps(This);
3584 * Rules are:
3585 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3586 * that would be really messy and require shader recompilation
3587 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3588 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3590 if (ps) {
3591 device_map_psamplers(This);
3592 } else {
3593 device_map_fixed_function_samplers(This);
3596 if (vs) {
3597 device_map_vsamplers(This, ps);
3601 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3603 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3604 This->updateStateBlock->pixelShader = pShader;
3605 This->updateStateBlock->changed.pixelShader = TRUE;
3607 /* Handle recording of state blocks */
3608 if (This->isRecordingState) {
3609 TRACE("Recording... not performing anything\n");
3612 if (This->isRecordingState) {
3613 TRACE("Recording... not performing anything\n");
3614 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3615 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3616 return WINED3D_OK;
3619 if(pShader == oldShader) {
3620 TRACE("App is setting the old pixel shader over, nothing to do\n");
3621 return WINED3D_OK;
3624 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3625 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3627 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3628 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3630 return WINED3D_OK;
3633 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3636 if (NULL == ppShader) {
3637 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3638 return WINED3DERR_INVALIDCALL;
3641 *ppShader = This->stateBlock->pixelShader;
3642 if (NULL != *ppShader) {
3643 IWineD3DPixelShader_AddRef(*ppShader);
3645 TRACE("(%p) : returning %p\n", This, *ppShader);
3646 return WINED3D_OK;
3649 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3650 IWineD3DDevice *iface,
3651 UINT start,
3652 CONST BOOL *srcData,
3653 UINT count) {
3655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3656 int i, cnt = min(count, MAX_CONST_B - start);
3658 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3659 iface, srcData, start, count);
3661 if (srcData == NULL || cnt < 0)
3662 return WINED3DERR_INVALIDCALL;
3664 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3665 for (i = 0; i < cnt; i++)
3666 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3668 for (i = start; i < cnt + start; ++i) {
3669 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3672 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3674 return WINED3D_OK;
3677 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3678 IWineD3DDevice *iface,
3679 UINT start,
3680 BOOL *dstData,
3681 UINT count) {
3683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3684 int cnt = min(count, MAX_CONST_B - start);
3686 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3687 iface, dstData, start, count);
3689 if (dstData == NULL || cnt < 0)
3690 return WINED3DERR_INVALIDCALL;
3692 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3693 return WINED3D_OK;
3696 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3697 IWineD3DDevice *iface,
3698 UINT start,
3699 CONST int *srcData,
3700 UINT count) {
3702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3703 int i, cnt = min(count, MAX_CONST_I - start);
3705 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3706 iface, srcData, start, count);
3708 if (srcData == NULL || cnt < 0)
3709 return WINED3DERR_INVALIDCALL;
3711 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3712 for (i = 0; i < cnt; i++)
3713 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3714 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3716 for (i = start; i < cnt + start; ++i) {
3717 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3720 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3722 return WINED3D_OK;
3725 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3726 IWineD3DDevice *iface,
3727 UINT start,
3728 int *dstData,
3729 UINT count) {
3731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3732 int cnt = min(count, MAX_CONST_I - start);
3734 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3735 iface, dstData, start, count);
3737 if (dstData == NULL || cnt < 0)
3738 return WINED3DERR_INVALIDCALL;
3740 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3741 return WINED3D_OK;
3744 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3745 IWineD3DDevice *iface,
3746 UINT start,
3747 CONST float *srcData,
3748 UINT count) {
3750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3751 int i;
3753 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3754 iface, srcData, start, count);
3756 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3757 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3758 return WINED3DERR_INVALIDCALL;
3760 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3761 if(TRACE_ON(d3d)) {
3762 for (i = 0; i < count; i++)
3763 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3764 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3767 for (i = start; i < count + start; ++i) {
3768 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3769 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3770 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3771 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3772 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3774 ptr->idx[ptr->count++] = i;
3775 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3779 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3781 return WINED3D_OK;
3784 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3785 IWineD3DDevice *iface,
3786 UINT start,
3787 float *dstData,
3788 UINT count) {
3790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3791 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3793 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3794 iface, dstData, start, count);
3796 if (dstData == NULL || cnt < 0)
3797 return WINED3DERR_INVALIDCALL;
3799 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3800 return WINED3D_OK;
3803 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3804 static HRESULT
3805 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3806 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3807 unsigned int i;
3808 DWORD DestFVF = dest->fvf;
3809 WINED3DVIEWPORT vp;
3810 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3811 BOOL doClip;
3812 int numTextures;
3814 if (lpStrideData->u.s.normal.lpData) {
3815 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3818 if (lpStrideData->u.s.position.lpData == NULL) {
3819 ERR("Source has no position mask\n");
3820 return WINED3DERR_INVALIDCALL;
3823 /* We might access VBOs from this code, so hold the lock */
3824 ENTER_GL();
3826 if (dest->resource.allocatedMemory == NULL) {
3827 /* This may happen if we do direct locking into a vbo. Unlikely,
3828 * but theoretically possible(ddraw processvertices test)
3830 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3831 if(!dest->resource.allocatedMemory) {
3832 LEAVE_GL();
3833 ERR("Out of memory\n");
3834 return E_OUTOFMEMORY;
3836 if(dest->vbo) {
3837 void *src;
3838 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3839 checkGLcall("glBindBufferARB");
3840 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3841 if(src) {
3842 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3844 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3845 checkGLcall("glUnmapBufferARB");
3849 /* Get a pointer into the destination vbo(create one if none exists) and
3850 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3852 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3853 CreateVBO(dest);
3856 if(dest->vbo) {
3857 unsigned char extrabytes = 0;
3858 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3859 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3860 * this may write 4 extra bytes beyond the area that should be written
3862 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3863 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3864 if(!dest_conv_addr) {
3865 ERR("Out of memory\n");
3866 /* Continue without storing converted vertices */
3868 dest_conv = dest_conv_addr;
3871 /* Should I clip?
3872 * a) WINED3DRS_CLIPPING is enabled
3873 * b) WINED3DVOP_CLIP is passed
3875 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3876 static BOOL warned = FALSE;
3878 * The clipping code is not quite correct. Some things need
3879 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3880 * so disable clipping for now.
3881 * (The graphics in Half-Life are broken, and my processvertices
3882 * test crashes with IDirect3DDevice3)
3883 doClip = TRUE;
3885 doClip = FALSE;
3886 if(!warned) {
3887 warned = TRUE;
3888 FIXME("Clipping is broken and disabled for now\n");
3890 } else doClip = FALSE;
3891 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3893 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3894 WINED3DTS_VIEW,
3895 &view_mat);
3896 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3897 WINED3DTS_PROJECTION,
3898 &proj_mat);
3899 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3900 WINED3DTS_WORLDMATRIX(0),
3901 &world_mat);
3903 TRACE("View mat:\n");
3904 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);
3905 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);
3906 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);
3907 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);
3909 TRACE("Proj mat:\n");
3910 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);
3911 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);
3912 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);
3913 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);
3915 TRACE("World mat:\n");
3916 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);
3917 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);
3918 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);
3919 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);
3921 /* Get the viewport */
3922 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3923 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3924 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3926 multiply_matrix(&mat,&view_mat,&world_mat);
3927 multiply_matrix(&mat,&proj_mat,&mat);
3929 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3931 for (i = 0; i < dwCount; i+= 1) {
3932 unsigned int tex_index;
3934 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3935 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3936 /* The position first */
3937 float *p =
3938 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3939 float x, y, z, rhw;
3940 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3942 /* Multiplication with world, view and projection matrix */
3943 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);
3944 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);
3945 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);
3946 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);
3948 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3950 /* WARNING: The following things are taken from d3d7 and were not yet checked
3951 * against d3d8 or d3d9!
3954 /* Clipping conditions: From
3955 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3957 * A vertex is clipped if it does not match the following requirements
3958 * -rhw < x <= rhw
3959 * -rhw < y <= rhw
3960 * 0 < z <= rhw
3961 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3963 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3964 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3968 if( !doClip ||
3969 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3970 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3971 ( rhw > eps ) ) ) {
3973 /* "Normal" viewport transformation (not clipped)
3974 * 1) The values are divided by rhw
3975 * 2) The y axis is negative, so multiply it with -1
3976 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3977 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3978 * 4) Multiply x with Width/2 and add Width/2
3979 * 5) The same for the height
3980 * 6) Add the viewpoint X and Y to the 2D coordinates and
3981 * The minimum Z value to z
3982 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3984 * Well, basically it's simply a linear transformation into viewport
3985 * coordinates
3988 x /= rhw;
3989 y /= rhw;
3990 z /= rhw;
3992 y *= -1;
3994 x *= vp.Width / 2;
3995 y *= vp.Height / 2;
3996 z *= vp.MaxZ - vp.MinZ;
3998 x += vp.Width / 2 + vp.X;
3999 y += vp.Height / 2 + vp.Y;
4000 z += vp.MinZ;
4002 rhw = 1 / rhw;
4003 } else {
4004 /* That vertex got clipped
4005 * Contrary to OpenGL it is not dropped completely, it just
4006 * undergoes a different calculation.
4008 TRACE("Vertex got clipped\n");
4009 x += rhw;
4010 y += rhw;
4012 x /= 2;
4013 y /= 2;
4015 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4016 * outside of the main vertex buffer memory. That needs some more
4017 * investigation...
4021 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4024 ( (float *) dest_ptr)[0] = x;
4025 ( (float *) dest_ptr)[1] = y;
4026 ( (float *) dest_ptr)[2] = z;
4027 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4029 dest_ptr += 3 * sizeof(float);
4031 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4032 dest_ptr += sizeof(float);
4035 if(dest_conv) {
4036 float w = 1 / rhw;
4037 ( (float *) dest_conv)[0] = x * w;
4038 ( (float *) dest_conv)[1] = y * w;
4039 ( (float *) dest_conv)[2] = z * w;
4040 ( (float *) dest_conv)[3] = w;
4042 dest_conv += 3 * sizeof(float);
4044 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4045 dest_conv += sizeof(float);
4049 if (DestFVF & WINED3DFVF_PSIZE) {
4050 dest_ptr += sizeof(DWORD);
4051 if(dest_conv) dest_conv += sizeof(DWORD);
4053 if (DestFVF & WINED3DFVF_NORMAL) {
4054 float *normal =
4055 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4056 /* AFAIK this should go into the lighting information */
4057 FIXME("Didn't expect the destination to have a normal\n");
4058 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4059 if(dest_conv) {
4060 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4064 if (DestFVF & WINED3DFVF_DIFFUSE) {
4065 DWORD *color_d =
4066 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4067 if(!color_d) {
4068 static BOOL warned = FALSE;
4070 if(!warned) {
4071 ERR("No diffuse color in source, but destination has one\n");
4072 warned = TRUE;
4075 *( (DWORD *) dest_ptr) = 0xffffffff;
4076 dest_ptr += sizeof(DWORD);
4078 if(dest_conv) {
4079 *( (DWORD *) dest_conv) = 0xffffffff;
4080 dest_conv += sizeof(DWORD);
4083 else {
4084 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4085 if(dest_conv) {
4086 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4087 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4088 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4089 dest_conv += sizeof(DWORD);
4094 if (DestFVF & WINED3DFVF_SPECULAR) {
4095 /* What's the color value in the feedback buffer? */
4096 DWORD *color_s =
4097 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4098 if(!color_s) {
4099 static BOOL warned = FALSE;
4101 if(!warned) {
4102 ERR("No specular color in source, but destination has one\n");
4103 warned = TRUE;
4106 *( (DWORD *) dest_ptr) = 0xFF000000;
4107 dest_ptr += sizeof(DWORD);
4109 if(dest_conv) {
4110 *( (DWORD *) dest_conv) = 0xFF000000;
4111 dest_conv += sizeof(DWORD);
4114 else {
4115 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4116 if(dest_conv) {
4117 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4118 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4119 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4120 dest_conv += sizeof(DWORD);
4125 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4126 float *tex_coord =
4127 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4128 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4129 if(!tex_coord) {
4130 ERR("No source texture, but destination requests one\n");
4131 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4132 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4134 else {
4135 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4136 if(dest_conv) {
4137 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4143 if(dest_conv) {
4144 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4145 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4146 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4147 dwCount * get_flexible_vertex_size(DestFVF),
4148 dest_conv_addr));
4149 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4150 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4153 LEAVE_GL();
4155 return WINED3D_OK;
4157 #undef copy_and_next
4159 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4161 WineDirect3DVertexStridedData strided;
4162 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4163 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4165 if(pVertexDecl) {
4166 ERR("Output vertex declaration not implemented yet\n");
4169 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
4170 * and this call is quite performance critical, so don't call needlessly
4172 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4173 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4176 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4177 * control the streamIsUP flag, thus restore it afterwards.
4179 This->stateBlock->streamIsUP = FALSE;
4180 memset(&strided, 0, sizeof(strided));
4181 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4182 This->stateBlock->streamIsUP = streamWasUP;
4184 if(vbo || SrcStartIndex) {
4185 unsigned int i;
4186 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4187 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4189 * Also get the start index in, but only loop over all elements if there's something to add at all.
4191 #define FIXSRC(type) \
4192 if(strided.u.s.type.VBO) { \
4193 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4194 strided.u.s.type.VBO = 0; \
4195 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4196 ENTER_GL(); \
4197 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4198 vb->vbo = 0; \
4199 LEAVE_GL(); \
4201 if(strided.u.s.type.lpData) { \
4202 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4204 FIXSRC(position);
4205 FIXSRC(blendWeights);
4206 FIXSRC(blendMatrixIndices);
4207 FIXSRC(normal);
4208 FIXSRC(pSize);
4209 FIXSRC(diffuse);
4210 FIXSRC(specular);
4211 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4212 FIXSRC(texCoords[i]);
4214 FIXSRC(position2);
4215 FIXSRC(normal2);
4216 FIXSRC(tangent);
4217 FIXSRC(binormal);
4218 FIXSRC(tessFactor);
4219 FIXSRC(fog);
4220 FIXSRC(depth);
4221 FIXSRC(sample);
4222 #undef FIXSRC
4225 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4228 /*****
4229 * Get / Set Texture Stage States
4230 * TODO: Verify against dx9 definitions
4231 *****/
4232 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4234 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4236 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4238 if (Stage >= MAX_TEXTURES) {
4239 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4240 return WINED3D_OK;
4243 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4244 This->updateStateBlock->textureState[Stage][Type] = Value;
4246 if (This->isRecordingState) {
4247 TRACE("Recording... not performing anything\n");
4248 return WINED3D_OK;
4251 /* Checked after the assignments to allow proper stateblock recording */
4252 if(oldValue == Value) {
4253 TRACE("App is setting the old value over, nothing to do\n");
4254 return WINED3D_OK;
4257 if(Stage > This->stateBlock->lowest_disabled_stage &&
4258 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4259 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4260 * Changes in other states are important on disabled stages too
4262 return WINED3D_OK;
4265 if(Type == WINED3DTSS_COLOROP) {
4266 int i;
4268 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4269 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4270 * they have to be disabled
4272 * The current stage is dirtified below.
4274 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4275 TRACE("Additionally dirtifying stage %d\n", i);
4276 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4278 This->stateBlock->lowest_disabled_stage = Stage;
4279 TRACE("New lowest disabled: %d\n", Stage);
4280 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4281 /* Previously disabled stage enabled. Stages above it may need enabling
4282 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4283 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4285 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4288 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4289 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4290 break;
4292 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4293 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4295 This->stateBlock->lowest_disabled_stage = i;
4296 TRACE("New lowest disabled: %d\n", i);
4298 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4299 /* TODO: Built a stage -> texture unit mapping for register combiners */
4303 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4305 return WINED3D_OK;
4308 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4310 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4311 *pValue = This->updateStateBlock->textureState[Stage][Type];
4312 return WINED3D_OK;
4315 /*****
4316 * Get / Set Texture
4317 *****/
4318 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4320 IWineD3DBaseTexture *oldTexture;
4322 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4324 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4325 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4328 oldTexture = This->updateStateBlock->textures[Stage];
4330 if(pTexture != NULL) {
4331 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4333 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4334 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4335 return WINED3DERR_INVALIDCALL;
4337 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4340 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4341 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4343 This->updateStateBlock->changed.textures[Stage] = TRUE;
4344 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4345 This->updateStateBlock->textures[Stage] = pTexture;
4347 /* Handle recording of state blocks */
4348 if (This->isRecordingState) {
4349 TRACE("Recording... not performing anything\n");
4350 return WINED3D_OK;
4353 if(oldTexture == pTexture) {
4354 TRACE("App is setting the same texture again, nothing to do\n");
4355 return WINED3D_OK;
4358 /** NOTE: MSDN says that setTexture increases the reference count,
4359 * and that the application must set the texture back to null (or have a leaky application),
4360 * This means we should pass the refcount up to the parent
4361 *******************************/
4362 if (NULL != This->updateStateBlock->textures[Stage]) {
4363 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4364 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4366 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4367 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4368 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4369 * so the COLOROP and ALPHAOP have to be dirtified.
4371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4372 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4374 if(bindCount == 1) {
4375 new->baseTexture.sampler = Stage;
4377 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4381 if (NULL != oldTexture) {
4382 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4383 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4385 IWineD3DBaseTexture_Release(oldTexture);
4386 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4387 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4388 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4391 if(bindCount && old->baseTexture.sampler == Stage) {
4392 int i;
4393 /* Have to do a search for the other sampler(s) where the texture is bound to
4394 * Shouldn't happen as long as apps bind a texture only to one stage
4396 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4397 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4398 if(This->updateStateBlock->textures[i] == oldTexture) {
4399 old->baseTexture.sampler = i;
4400 break;
4406 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4408 return WINED3D_OK;
4411 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4414 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4416 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4417 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4420 *ppTexture=This->stateBlock->textures[Stage];
4421 if (*ppTexture)
4422 IWineD3DBaseTexture_AddRef(*ppTexture);
4424 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4426 return WINED3D_OK;
4429 /*****
4430 * Get Back Buffer
4431 *****/
4432 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4433 IWineD3DSurface **ppBackBuffer) {
4434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4435 IWineD3DSwapChain *swapChain;
4436 HRESULT hr;
4438 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4440 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4441 if (hr == WINED3D_OK) {
4442 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4443 IWineD3DSwapChain_Release(swapChain);
4444 } else {
4445 *ppBackBuffer = NULL;
4447 return hr;
4450 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4452 WARN("(%p) : stub, calling idirect3d for now\n", This);
4453 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4456 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4458 IWineD3DSwapChain *swapChain;
4459 HRESULT hr;
4461 if(iSwapChain > 0) {
4462 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4463 if (hr == WINED3D_OK) {
4464 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4465 IWineD3DSwapChain_Release(swapChain);
4466 } else {
4467 FIXME("(%p) Error getting display mode\n", This);
4469 } else {
4470 /* Don't read the real display mode,
4471 but return the stored mode instead. X11 can't change the color
4472 depth, and some apps are pretty angry if they SetDisplayMode from
4473 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4475 Also don't relay to the swapchain because with ddraw it's possible
4476 that there isn't a swapchain at all */
4477 pMode->Width = This->ddraw_width;
4478 pMode->Height = This->ddraw_height;
4479 pMode->Format = This->ddraw_format;
4480 pMode->RefreshRate = 0;
4481 hr = WINED3D_OK;
4484 return hr;
4487 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4489 TRACE("(%p)->(%p)\n", This, hWnd);
4491 if(This->ddraw_fullscreen) {
4492 if(This->ddraw_window && This->ddraw_window != hWnd) {
4493 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4495 if(hWnd && This->ddraw_window != hWnd) {
4496 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4500 This->ddraw_window = hWnd;
4501 return WINED3D_OK;
4504 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4506 TRACE("(%p)->(%p)\n", This, hWnd);
4508 *hWnd = This->ddraw_window;
4509 return WINED3D_OK;
4512 /*****
4513 * Stateblock related functions
4514 *****/
4516 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4518 IWineD3DStateBlockImpl *object;
4519 HRESULT temp_result;
4520 int i;
4522 TRACE("(%p)\n", This);
4524 if (This->isRecordingState) {
4525 return WINED3DERR_INVALIDCALL;
4528 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4529 if (NULL == object ) {
4530 FIXME("(%p)Error allocating memory for stateblock\n", This);
4531 return E_OUTOFMEMORY;
4533 TRACE("(%p) created object %p\n", This, object);
4534 object->wineD3DDevice= This;
4535 /** FIXME: object->parent = parent; **/
4536 object->parent = NULL;
4537 object->blockType = WINED3DSBT_RECORDED;
4538 object->ref = 1;
4539 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4541 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4542 list_init(&object->lightMap[i]);
4545 temp_result = allocate_shader_constants(object);
4546 if (WINED3D_OK != temp_result)
4547 return temp_result;
4549 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4550 This->updateStateBlock = object;
4551 This->isRecordingState = TRUE;
4553 TRACE("(%p) recording stateblock %p\n",This , object);
4554 return WINED3D_OK;
4557 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4559 unsigned int i, j;
4560 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4562 if (!This->isRecordingState) {
4563 FIXME("(%p) not recording! returning error\n", This);
4564 *ppStateBlock = NULL;
4565 return WINED3DERR_INVALIDCALL;
4568 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4569 if(object->changed.renderState[i]) {
4570 object->contained_render_states[object->num_contained_render_states] = i;
4571 object->num_contained_render_states++;
4574 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4575 if(object->changed.transform[i]) {
4576 object->contained_transform_states[object->num_contained_transform_states] = i;
4577 object->num_contained_transform_states++;
4580 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4581 if(object->changed.vertexShaderConstantsF[i]) {
4582 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4583 object->num_contained_vs_consts_f++;
4586 for(i = 0; i < MAX_CONST_I; i++) {
4587 if(object->changed.vertexShaderConstantsI[i]) {
4588 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4589 object->num_contained_vs_consts_i++;
4592 for(i = 0; i < MAX_CONST_B; i++) {
4593 if(object->changed.vertexShaderConstantsB[i]) {
4594 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4595 object->num_contained_vs_consts_b++;
4598 for(i = 0; i < MAX_CONST_I; i++) {
4599 if(object->changed.pixelShaderConstantsI[i]) {
4600 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4601 object->num_contained_ps_consts_i++;
4604 for(i = 0; i < MAX_CONST_B; i++) {
4605 if(object->changed.pixelShaderConstantsB[i]) {
4606 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4607 object->num_contained_ps_consts_b++;
4610 for(i = 0; i < MAX_TEXTURES; i++) {
4611 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4612 if(object->changed.textureState[i][j]) {
4613 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4614 object->contained_tss_states[object->num_contained_tss_states].state = j;
4615 object->num_contained_tss_states++;
4619 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4620 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4621 if(object->changed.samplerState[i][j]) {
4622 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4623 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4624 object->num_contained_sampler_states++;
4629 *ppStateBlock = (IWineD3DStateBlock*) object;
4630 This->isRecordingState = FALSE;
4631 This->updateStateBlock = This->stateBlock;
4632 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4633 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4634 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4635 return WINED3D_OK;
4638 /*****
4639 * Scene related functions
4640 *****/
4641 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4642 /* At the moment we have no need for any functionality at the beginning
4643 of a scene */
4644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4645 TRACE("(%p)\n", This);
4647 if(This->inScene) {
4648 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4649 return WINED3DERR_INVALIDCALL;
4651 This->inScene = TRUE;
4652 return WINED3D_OK;
4655 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4657 TRACE("(%p)\n", This);
4659 if(!This->inScene) {
4660 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4661 return WINED3DERR_INVALIDCALL;
4664 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4665 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4667 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4668 ENTER_GL();
4669 glFlush();
4670 checkGLcall("glFlush");
4671 LEAVE_GL();
4673 This->inScene = FALSE;
4674 return WINED3D_OK;
4677 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4678 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4679 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4681 IWineD3DSwapChain *swapChain = NULL;
4682 int i;
4683 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4685 TRACE("(%p) Presenting the frame\n", This);
4687 for(i = 0 ; i < swapchains ; i ++) {
4689 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4690 TRACE("presentinng chain %d, %p\n", i, swapChain);
4691 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4692 IWineD3DSwapChain_Release(swapChain);
4695 return WINED3D_OK;
4698 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4699 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4700 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4701 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4703 GLbitfield glMask = 0;
4704 unsigned int i;
4705 CONST WINED3DRECT* curRect;
4707 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4708 Count, pRects, Flags, Color, Z, Stencil);
4710 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4711 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4712 /* TODO: What about depth stencil buffers without stencil bits? */
4713 return WINED3DERR_INVALIDCALL;
4716 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4717 * and not the last active one.
4719 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4720 ENTER_GL();
4722 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4723 apply_fbo_state(iface);
4726 if (Count > 0 && pRects) {
4727 curRect = pRects;
4728 } else {
4729 curRect = NULL;
4732 /* Only set the values up once, as they are not changing */
4733 if (Flags & WINED3DCLEAR_STENCIL) {
4734 glClearStencil(Stencil);
4735 checkGLcall("glClearStencil");
4736 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4737 glStencilMask(0xFFFFFFFF);
4740 if (Flags & WINED3DCLEAR_ZBUFFER) {
4741 glDepthMask(GL_TRUE);
4742 glClearDepth(Z);
4743 checkGLcall("glClearDepth");
4744 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4745 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4748 if (Flags & WINED3DCLEAR_TARGET) {
4749 TRACE("Clearing screen with glClear to color %x\n", Color);
4750 glClearColor(D3DCOLOR_R(Color),
4751 D3DCOLOR_G(Color),
4752 D3DCOLOR_B(Color),
4753 D3DCOLOR_A(Color));
4754 checkGLcall("glClearColor");
4756 /* Clear ALL colors! */
4757 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4758 glMask = glMask | GL_COLOR_BUFFER_BIT;
4761 if (!curRect) {
4762 /* In drawable flag is set below */
4764 if (This->render_offscreen) {
4765 glScissor(This->stateBlock->viewport.X,
4766 This->stateBlock->viewport.Y,
4767 This->stateBlock->viewport.Width,
4768 This->stateBlock->viewport.Height);
4769 } else {
4770 glScissor(This->stateBlock->viewport.X,
4771 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4772 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4773 This->stateBlock->viewport.Width,
4774 This->stateBlock->viewport.Height);
4776 checkGLcall("glScissor");
4777 glClear(glMask);
4778 checkGLcall("glClear");
4779 } else {
4780 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4781 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4783 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4784 curRect[0].x2 < target->currentDesc.Width ||
4785 curRect[0].y2 < target->currentDesc.Height) {
4786 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4787 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4791 /* Now process each rect in turn */
4792 for (i = 0; i < Count; i++) {
4793 /* Note gl uses lower left, width/height */
4794 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4795 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4796 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4797 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4799 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4800 * The rectangle is not cleared, no error is returned, but further rectanlges are
4801 * still cleared if they are valid
4803 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4804 TRACE("Rectangle with negative dimensions, ignoring\n");
4805 continue;
4808 if(This->render_offscreen) {
4809 glScissor(curRect[i].x1, curRect[i].y1,
4810 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4811 } else {
4812 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4813 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4815 checkGLcall("glScissor");
4817 glClear(glMask);
4818 checkGLcall("glClear");
4822 /* Restore the old values (why..?) */
4823 if (Flags & WINED3DCLEAR_STENCIL) {
4824 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4826 if (Flags & WINED3DCLEAR_TARGET) {
4827 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4828 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4829 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4830 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4831 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4834 LEAVE_GL();
4836 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4837 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4839 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
4840 /* TODO: Move the fbo logic into ModifyLocation() */
4841 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4842 target->Flags |= SFLAG_INTEXTURE;
4844 return WINED3D_OK;
4847 /*****
4848 * Drawing functions
4849 *****/
4850 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4851 UINT PrimitiveCount) {
4853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4855 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4856 debug_d3dprimitivetype(PrimitiveType),
4857 StartVertex, PrimitiveCount);
4859 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4860 if(This->stateBlock->streamIsUP) {
4861 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4862 This->stateBlock->streamIsUP = FALSE;
4865 if(This->stateBlock->loadBaseVertexIndex != 0) {
4866 This->stateBlock->loadBaseVertexIndex = 0;
4867 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4869 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4870 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4871 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4872 return WINED3D_OK;
4875 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4876 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4877 WINED3DPRIMITIVETYPE PrimitiveType,
4878 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4881 UINT idxStride = 2;
4882 IWineD3DIndexBuffer *pIB;
4883 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4884 GLuint vbo;
4886 pIB = This->stateBlock->pIndexData;
4887 if (!pIB) {
4888 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4889 * without an index buffer set. (The first time at least...)
4890 * D3D8 simply dies, but I doubt it can do much harm to return
4891 * D3DERR_INVALIDCALL there as well. */
4892 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4893 return WINED3DERR_INVALIDCALL;
4896 if(This->stateBlock->streamIsUP) {
4897 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4898 This->stateBlock->streamIsUP = FALSE;
4900 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4902 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4903 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4904 minIndex, NumVertices, startIndex, primCount);
4906 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4907 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4908 idxStride = 2;
4909 } else {
4910 idxStride = 4;
4913 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4914 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4915 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4918 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4919 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4921 return WINED3D_OK;
4924 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4925 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4926 UINT VertexStreamZeroStride) {
4927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4928 IWineD3DVertexBuffer *vb;
4930 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4931 debug_d3dprimitivetype(PrimitiveType),
4932 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4934 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4935 vb = This->stateBlock->streamSource[0];
4936 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4937 if(vb) IWineD3DVertexBuffer_Release(vb);
4938 This->stateBlock->streamOffset[0] = 0;
4939 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4940 This->stateBlock->streamIsUP = TRUE;
4941 This->stateBlock->loadBaseVertexIndex = 0;
4943 /* TODO: Only mark dirty if drawing from a different UP address */
4944 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4946 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4947 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4949 /* MSDN specifies stream zero settings must be set to NULL */
4950 This->stateBlock->streamStride[0] = 0;
4951 This->stateBlock->streamSource[0] = NULL;
4953 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4954 * the new stream sources or use UP drawing again
4956 return WINED3D_OK;
4959 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4960 UINT MinVertexIndex, UINT NumVertices,
4961 UINT PrimitiveCount, CONST void* pIndexData,
4962 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4963 UINT VertexStreamZeroStride) {
4964 int idxStride;
4965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4966 IWineD3DVertexBuffer *vb;
4967 IWineD3DIndexBuffer *ib;
4969 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4970 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4971 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4972 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4974 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4975 idxStride = 2;
4976 } else {
4977 idxStride = 4;
4980 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4981 vb = This->stateBlock->streamSource[0];
4982 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4983 if(vb) IWineD3DVertexBuffer_Release(vb);
4984 This->stateBlock->streamIsUP = TRUE;
4985 This->stateBlock->streamOffset[0] = 0;
4986 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4988 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4989 This->stateBlock->baseVertexIndex = 0;
4990 This->stateBlock->loadBaseVertexIndex = 0;
4991 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4992 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4993 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4995 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4997 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4998 This->stateBlock->streamSource[0] = NULL;
4999 This->stateBlock->streamStride[0] = 0;
5000 ib = This->stateBlock->pIndexData;
5001 if(ib) {
5002 IWineD3DIndexBuffer_Release(ib);
5003 This->stateBlock->pIndexData = NULL;
5005 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5006 * SetStreamSource to specify a vertex buffer
5009 return WINED3D_OK;
5012 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5015 /* Mark the state dirty until we have nicer tracking
5016 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5017 * that value.
5019 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5020 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5021 This->stateBlock->baseVertexIndex = 0;
5022 This->up_strided = DrawPrimStrideData;
5023 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5024 This->up_strided = NULL;
5025 return WINED3D_OK;
5028 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5030 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5032 /* Mark the state dirty until we have nicer tracking
5033 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5034 * that value.
5036 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5037 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5038 This->stateBlock->streamIsUP = TRUE;
5039 This->stateBlock->baseVertexIndex = 0;
5040 This->up_strided = DrawPrimStrideData;
5041 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5042 This->up_strided = NULL;
5043 return WINED3D_OK;
5046 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5047 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5048 * not callable by the app directly no parameter validation checks are needed here.
5050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5051 WINED3DLOCKED_BOX src;
5052 WINED3DLOCKED_BOX dst;
5053 HRESULT hr;
5054 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5056 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5057 * dirtification to improve loading performance.
5059 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5060 if(FAILED(hr)) return hr;
5061 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5062 if(FAILED(hr)) {
5063 IWineD3DVolume_UnlockBox(pSourceVolume);
5064 return hr;
5067 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5069 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5070 if(FAILED(hr)) {
5071 IWineD3DVolume_UnlockBox(pSourceVolume);
5072 } else {
5073 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5075 return hr;
5078 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5079 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5080 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5081 HRESULT hr = WINED3D_OK;
5082 WINED3DRESOURCETYPE sourceType;
5083 WINED3DRESOURCETYPE destinationType;
5084 int i ,levels;
5086 /* TODO: think about moving the code into IWineD3DBaseTexture */
5088 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5090 /* verify that the source and destination textures aren't NULL */
5091 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5092 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5093 This, pSourceTexture, pDestinationTexture);
5094 hr = WINED3DERR_INVALIDCALL;
5097 if (pSourceTexture == pDestinationTexture) {
5098 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5099 This, pSourceTexture, pDestinationTexture);
5100 hr = WINED3DERR_INVALIDCALL;
5102 /* Verify that the source and destination textures are the same type */
5103 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5104 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5106 if (sourceType != destinationType) {
5107 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5108 This);
5109 hr = WINED3DERR_INVALIDCALL;
5112 /* check that both textures have the identical numbers of levels */
5113 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5114 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5115 hr = WINED3DERR_INVALIDCALL;
5118 if (WINED3D_OK == hr) {
5120 /* Make sure that the destination texture is loaded */
5121 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5123 /* Update every surface level of the texture */
5124 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5126 switch (sourceType) {
5127 case WINED3DRTYPE_TEXTURE:
5129 IWineD3DSurface *srcSurface;
5130 IWineD3DSurface *destSurface;
5132 for (i = 0 ; i < levels ; ++i) {
5133 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5134 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5135 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5136 IWineD3DSurface_Release(srcSurface);
5137 IWineD3DSurface_Release(destSurface);
5138 if (WINED3D_OK != hr) {
5139 WARN("(%p) : Call to update surface failed\n", This);
5140 return hr;
5144 break;
5145 case WINED3DRTYPE_CUBETEXTURE:
5147 IWineD3DSurface *srcSurface;
5148 IWineD3DSurface *destSurface;
5149 WINED3DCUBEMAP_FACES faceType;
5151 for (i = 0 ; i < levels ; ++i) {
5152 /* Update each cube face */
5153 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5154 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5155 if (WINED3D_OK != hr) {
5156 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5157 } else {
5158 TRACE("Got srcSurface %p\n", srcSurface);
5160 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
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 desrSurface %p\n", destSurface);
5166 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5167 IWineD3DSurface_Release(srcSurface);
5168 IWineD3DSurface_Release(destSurface);
5169 if (WINED3D_OK != hr) {
5170 WARN("(%p) : Call to update surface failed\n", This);
5171 return hr;
5176 break;
5178 case WINED3DRTYPE_VOLUMETEXTURE:
5180 IWineD3DVolume *srcVolume = NULL;
5181 IWineD3DVolume *destVolume = NULL;
5183 for (i = 0 ; i < levels ; ++i) {
5184 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5185 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5186 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5187 IWineD3DVolume_Release(srcVolume);
5188 IWineD3DVolume_Release(destVolume);
5189 if (WINED3D_OK != hr) {
5190 WARN("(%p) : Call to update volume failed\n", This);
5191 return hr;
5195 break;
5197 default:
5198 FIXME("(%p) : Unsupported source and destination type\n", This);
5199 hr = WINED3DERR_INVALIDCALL;
5203 return hr;
5206 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5207 IWineD3DSwapChain *swapChain;
5208 HRESULT hr;
5209 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5210 if(hr == WINED3D_OK) {
5211 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5212 IWineD3DSwapChain_Release(swapChain);
5214 return hr;
5217 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5219 /* return a sensible default */
5220 *pNumPasses = 1;
5221 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5222 FIXME("(%p) : stub\n", This);
5223 return WINED3D_OK;
5226 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5228 int j;
5229 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5230 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5231 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5232 return WINED3DERR_INVALIDCALL;
5234 for (j = 0; j < 256; ++j) {
5235 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5236 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5237 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5238 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5240 TRACE("(%p) : returning\n", This);
5241 return WINED3D_OK;
5244 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5246 int j;
5247 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5248 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5249 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5250 return WINED3DERR_INVALIDCALL;
5252 for (j = 0; j < 256; ++j) {
5253 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5254 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5255 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5256 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5258 TRACE("(%p) : returning\n", This);
5259 return WINED3D_OK;
5262 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5264 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5265 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5266 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5267 return WINED3DERR_INVALIDCALL;
5269 /*TODO: stateblocks */
5270 This->currentPalette = PaletteNumber;
5271 TRACE("(%p) : returning\n", This);
5272 return WINED3D_OK;
5275 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5277 if (PaletteNumber == NULL) {
5278 WARN("(%p) : returning Invalid Call\n", This);
5279 return WINED3DERR_INVALIDCALL;
5281 /*TODO: stateblocks */
5282 *PaletteNumber = This->currentPalette;
5283 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5284 return WINED3D_OK;
5287 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5289 static BOOL showFixmes = TRUE;
5290 if (showFixmes) {
5291 FIXME("(%p) : stub\n", This);
5292 showFixmes = FALSE;
5295 This->softwareVertexProcessing = bSoftware;
5296 return WINED3D_OK;
5300 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5302 static BOOL showFixmes = TRUE;
5303 if (showFixmes) {
5304 FIXME("(%p) : stub\n", This);
5305 showFixmes = FALSE;
5307 return This->softwareVertexProcessing;
5311 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5313 IWineD3DSwapChain *swapChain;
5314 HRESULT hr;
5316 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5318 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5319 if(hr == WINED3D_OK){
5320 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5321 IWineD3DSwapChain_Release(swapChain);
5322 }else{
5323 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5325 return hr;
5329 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5331 static BOOL showfixmes = TRUE;
5332 if(nSegments != 0.0f) {
5333 if( showfixmes) {
5334 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5335 showfixmes = FALSE;
5338 return WINED3D_OK;
5341 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5343 static BOOL showfixmes = TRUE;
5344 if( showfixmes) {
5345 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5346 showfixmes = FALSE;
5348 return 0.0f;
5351 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5353 /** TODO: remove casts to IWineD3DSurfaceImpl
5354 * NOTE: move code to surface to accomplish this
5355 ****************************************/
5356 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5357 int srcWidth, srcHeight;
5358 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5359 WINED3DFORMAT destFormat, srcFormat;
5360 UINT destSize;
5361 int srcLeft, destLeft, destTop;
5362 WINED3DPOOL srcPool, destPool;
5363 int offset = 0;
5364 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5365 glDescriptor *glDescription = NULL;
5366 GLenum dummy;
5367 int bpp;
5368 CONVERT_TYPES convert = NO_CONVERSION;
5370 WINED3DSURFACE_DESC winedesc;
5372 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5373 memset(&winedesc, 0, sizeof(winedesc));
5374 winedesc.Width = &srcSurfaceWidth;
5375 winedesc.Height = &srcSurfaceHeight;
5376 winedesc.Pool = &srcPool;
5377 winedesc.Format = &srcFormat;
5379 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5381 winedesc.Width = &destSurfaceWidth;
5382 winedesc.Height = &destSurfaceHeight;
5383 winedesc.Pool = &destPool;
5384 winedesc.Format = &destFormat;
5385 winedesc.Size = &destSize;
5387 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5389 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5390 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5391 return WINED3DERR_INVALIDCALL;
5394 /* This call loads the opengl surface directly, instead of copying the surface to the
5395 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5396 * copy in sysmem and use regular surface loading.
5398 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5399 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5400 if(convert != NO_CONVERSION) {
5401 return IWineD3DSurface_BltFast(pDestinationSurface,
5402 pDestPoint ? pDestPoint->x : 0,
5403 pDestPoint ? pDestPoint->y : 0,
5404 pSourceSurface, (RECT *) pSourceRect, 0);
5407 if (destFormat == WINED3DFMT_UNKNOWN) {
5408 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5409 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5411 /* Get the update surface description */
5412 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5415 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5417 ENTER_GL();
5419 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5420 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5421 checkGLcall("glActiveTextureARB");
5424 /* Make sure the surface is loaded and up to date */
5425 IWineD3DSurface_PreLoad(pDestinationSurface);
5427 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5429 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5430 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5431 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5432 srcLeft = pSourceRect ? pSourceRect->left : 0;
5433 destLeft = pDestPoint ? pDestPoint->x : 0;
5434 destTop = pDestPoint ? pDestPoint->y : 0;
5437 /* This function doesn't support compressed textures
5438 the pitch is just bytesPerPixel * width */
5439 if(srcWidth != srcSurfaceWidth || srcLeft ){
5440 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5441 offset += srcLeft * pSrcSurface->bytesPerPixel;
5442 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5444 /* TODO DXT formats */
5446 if(pSourceRect != NULL && pSourceRect->top != 0){
5447 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5449 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5450 ,This
5451 ,glDescription->level
5452 ,destLeft
5453 ,destTop
5454 ,srcWidth
5455 ,srcHeight
5456 ,glDescription->glFormat
5457 ,glDescription->glType
5458 ,IWineD3DSurface_GetData(pSourceSurface)
5461 /* Sanity check */
5462 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5464 /* need to lock the surface to get the data */
5465 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5468 /* TODO: Cube and volume support */
5469 if(rowoffset != 0){
5470 /* not a whole row so we have to do it a line at a time */
5471 int j;
5473 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5474 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5476 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5478 glTexSubImage2D(glDescription->target
5479 ,glDescription->level
5480 ,destLeft
5482 ,srcWidth
5484 ,glDescription->glFormat
5485 ,glDescription->glType
5486 ,data /* could be quicker using */
5488 data += rowoffset;
5491 } else { /* Full width, so just write out the whole texture */
5493 if (WINED3DFMT_DXT1 == destFormat ||
5494 WINED3DFMT_DXT2 == destFormat ||
5495 WINED3DFMT_DXT3 == destFormat ||
5496 WINED3DFMT_DXT4 == destFormat ||
5497 WINED3DFMT_DXT5 == destFormat) {
5498 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5499 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5500 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5501 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5502 } if (destFormat != srcFormat) {
5503 FIXME("Updating mixed format compressed texture is not curretly support\n");
5504 } else {
5505 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5506 glDescription->level,
5507 glDescription->glFormatInternal,
5508 srcWidth,
5509 srcHeight,
5511 destSize,
5512 IWineD3DSurface_GetData(pSourceSurface));
5514 } else {
5515 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5519 } else {
5520 glTexSubImage2D(glDescription->target
5521 ,glDescription->level
5522 ,destLeft
5523 ,destTop
5524 ,srcWidth
5525 ,srcHeight
5526 ,glDescription->glFormat
5527 ,glDescription->glType
5528 ,IWineD3DSurface_GetData(pSourceSurface)
5532 checkGLcall("glTexSubImage2D");
5534 LEAVE_GL();
5536 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5537 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5539 return WINED3D_OK;
5542 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5544 struct WineD3DRectPatch *patch;
5545 unsigned int i;
5546 struct list *e;
5547 BOOL found;
5548 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5550 if(!(Handle || pRectPatchInfo)) {
5551 /* TODO: Write a test for the return value, thus the FIXME */
5552 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5553 return WINED3DERR_INVALIDCALL;
5556 if(Handle) {
5557 i = PATCHMAP_HASHFUNC(Handle);
5558 found = FALSE;
5559 LIST_FOR_EACH(e, &This->patches[i]) {
5560 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5561 if(patch->Handle == Handle) {
5562 found = TRUE;
5563 break;
5567 if(!found) {
5568 TRACE("Patch does not exist. Creating a new one\n");
5569 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5570 patch->Handle = Handle;
5571 list_add_head(&This->patches[i], &patch->entry);
5572 } else {
5573 TRACE("Found existing patch %p\n", patch);
5575 } else {
5576 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5577 * attributes we have to tesselate, read back, and draw. This needs a patch
5578 * management structure instance. Create one.
5580 * A possible improvement is to check if a vertex shader is used, and if not directly
5581 * draw the patch.
5583 FIXME("Drawing an uncached patch. This is slow\n");
5584 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5587 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5588 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5589 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5590 HRESULT hr;
5591 TRACE("Tesselation density or patch info changed, retesselating\n");
5593 if(pRectPatchInfo) {
5594 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5596 patch->numSegs[0] = pNumSegs[0];
5597 patch->numSegs[1] = pNumSegs[1];
5598 patch->numSegs[2] = pNumSegs[2];
5599 patch->numSegs[3] = pNumSegs[3];
5601 hr = tesselate_rectpatch(This, patch);
5602 if(FAILED(hr)) {
5603 WARN("Patch tesselation failed\n");
5605 /* Do not release the handle to store the params of the patch */
5606 if(!Handle) {
5607 HeapFree(GetProcessHeap(), 0, patch);
5609 return hr;
5613 This->currentPatch = patch;
5614 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5615 This->currentPatch = NULL;
5617 /* Destroy uncached patches */
5618 if(!Handle) {
5619 HeapFree(GetProcessHeap(), 0, patch->mem);
5620 HeapFree(GetProcessHeap(), 0, patch);
5622 return WINED3D_OK;
5625 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5626 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5628 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5629 FIXME("(%p) : Stub\n", This);
5630 return WINED3D_OK;
5633 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5635 int i;
5636 struct WineD3DRectPatch *patch;
5637 struct list *e;
5638 TRACE("(%p) Handle(%d)\n", This, Handle);
5640 i = PATCHMAP_HASHFUNC(Handle);
5641 LIST_FOR_EACH(e, &This->patches[i]) {
5642 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5643 if(patch->Handle == Handle) {
5644 TRACE("Deleting patch %p\n", patch);
5645 list_remove(&patch->entry);
5646 HeapFree(GetProcessHeap(), 0, patch->mem);
5647 HeapFree(GetProcessHeap(), 0, patch);
5648 return WINED3D_OK;
5652 /* TODO: Write a test for the return value */
5653 FIXME("Attempt to destroy nonexistant patch\n");
5654 return WINED3DERR_INVALIDCALL;
5657 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5658 HRESULT hr;
5659 IWineD3DSwapChain *swapchain;
5661 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5662 if (SUCCEEDED(hr)) {
5663 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5664 return swapchain;
5667 return NULL;
5670 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5673 if (!*fbo) {
5674 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5675 checkGLcall("glGenFramebuffersEXT()");
5677 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5678 checkGLcall("glBindFramebuffer()");
5681 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5682 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5683 IWineD3DBaseTextureImpl *texture_impl;
5684 GLenum texttarget, target;
5685 GLint old_binding;
5687 texttarget = surface_impl->glDescription.target;
5688 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5689 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5691 IWineD3DSurface_PreLoad(surface);
5693 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5694 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5695 glBindTexture(target, old_binding);
5697 /* Update base texture states array */
5698 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5699 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5700 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5701 if (texture_impl->baseTexture.bindCount) {
5702 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5705 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5708 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5709 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5711 checkGLcall("attach_surface_fbo");
5714 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5716 IWineD3DSwapChain *swapchain;
5718 swapchain = get_swapchain(surface);
5719 if (swapchain) {
5720 GLenum buffer;
5722 TRACE("Surface %p is onscreen\n", surface);
5724 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5725 buffer = surface_get_gl_buffer(surface, swapchain);
5726 glDrawBuffer(buffer);
5727 checkGLcall("glDrawBuffer()");
5728 } else {
5729 TRACE("Surface %p is offscreen\n", surface);
5730 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5731 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5734 if (rect) {
5735 glEnable(GL_SCISSOR_TEST);
5736 if(!swapchain) {
5737 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5738 } else {
5739 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5740 rect->x2 - rect->x1, rect->y2 - rect->y1);
5742 checkGLcall("glScissor");
5743 } else {
5744 glDisable(GL_SCISSOR_TEST);
5746 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5748 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5749 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5751 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5752 glClear(GL_COLOR_BUFFER_BIT);
5753 checkGLcall("glClear");
5755 if (This->render_offscreen) {
5756 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5757 } else {
5758 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5759 checkGLcall("glBindFramebuffer()");
5762 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5763 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5764 glDrawBuffer(GL_BACK);
5765 checkGLcall("glDrawBuffer()");
5769 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5770 unsigned int r, g, b, a;
5771 DWORD ret;
5773 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
5774 destfmt == WINED3DFMT_R8G8B8)
5775 return color;
5777 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5779 a = (color & 0xff000000) >> 24;
5780 r = (color & 0x00ff0000) >> 16;
5781 g = (color & 0x0000ff00) >> 8;
5782 b = (color & 0x000000ff) >> 0;
5784 switch(destfmt)
5786 case WINED3DFMT_R5G6B5:
5787 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5788 r = (r * 32) / 256;
5789 g = (g * 64) / 256;
5790 b = (b * 32) / 256;
5791 ret = r << 11;
5792 ret |= g << 5;
5793 ret |= b;
5794 TRACE("Returning %08x\n", ret);
5795 return ret;
5797 case WINED3DFMT_X1R5G5B5:
5798 case WINED3DFMT_A1R5G5B5:
5799 a = (a * 2) / 256;
5800 r = (r * 32) / 256;
5801 g = (g * 32) / 256;
5802 b = (b * 32) / 256;
5803 ret = a << 15;
5804 ret |= r << 10;
5805 ret |= g << 5;
5806 ret |= b << 0;
5807 TRACE("Returning %08x\n", ret);
5808 return ret;
5810 case WINED3DFMT_A8:
5811 TRACE("Returning %08x\n", a);
5812 return a;
5814 case WINED3DFMT_X4R4G4B4:
5815 case WINED3DFMT_A4R4G4B4:
5816 a = (a * 16) / 256;
5817 r = (r * 16) / 256;
5818 g = (g * 16) / 256;
5819 b = (b * 16) / 256;
5820 ret = a << 12;
5821 ret |= r << 8;
5822 ret |= g << 4;
5823 ret |= b << 0;
5824 TRACE("Returning %08x\n", ret);
5825 return ret;
5827 case WINED3DFMT_R3G3B2:
5828 r = (r * 8) / 256;
5829 g = (g * 8) / 256;
5830 b = (b * 4) / 256;
5831 ret = r << 5;
5832 ret |= g << 2;
5833 ret |= b << 0;
5834 TRACE("Returning %08x\n", ret);
5835 return ret;
5837 case WINED3DFMT_X8B8G8R8:
5838 case WINED3DFMT_A8B8G8R8:
5839 ret = a << 24;
5840 ret |= b << 16;
5841 ret |= g << 8;
5842 ret |= r << 0;
5843 TRACE("Returning %08x\n", ret);
5844 return ret;
5846 case WINED3DFMT_A2R10G10B10:
5847 a = (a * 4) / 256;
5848 r = (r * 1024) / 256;
5849 g = (g * 1024) / 256;
5850 b = (b * 1024) / 256;
5851 ret = a << 30;
5852 ret |= r << 20;
5853 ret |= g << 10;
5854 ret |= b << 0;
5855 TRACE("Returning %08x\n", ret);
5856 return ret;
5858 case WINED3DFMT_A2B10G10R10:
5859 a = (a * 4) / 256;
5860 r = (r * 1024) / 256;
5861 g = (g * 1024) / 256;
5862 b = (b * 1024) / 256;
5863 ret = a << 30;
5864 ret |= b << 20;
5865 ret |= g << 10;
5866 ret |= r << 0;
5867 TRACE("Returning %08x\n", ret);
5868 return ret;
5870 default:
5871 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5872 return 0;
5876 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5878 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5879 WINEDDBLTFX BltFx;
5880 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5882 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5883 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5884 return WINED3DERR_INVALIDCALL;
5887 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5888 color_fill_fbo(iface, pSurface, pRect, color);
5889 return WINED3D_OK;
5890 } else {
5891 /* Just forward this to the DirectDraw blitting engine */
5892 memset(&BltFx, 0, sizeof(BltFx));
5893 BltFx.dwSize = sizeof(BltFx);
5894 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
5895 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5899 /* rendertarget and deptth stencil functions */
5900 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5903 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5904 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5905 return WINED3DERR_INVALIDCALL;
5908 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5909 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5910 /* Note inc ref on returned surface */
5911 if(*ppRenderTarget != NULL)
5912 IWineD3DSurface_AddRef(*ppRenderTarget);
5913 return WINED3D_OK;
5916 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5918 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5919 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5920 IWineD3DSwapChainImpl *Swapchain;
5921 HRESULT hr;
5923 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5925 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5926 if(hr != WINED3D_OK) {
5927 ERR("Can't get the swapchain\n");
5928 return hr;
5931 /* Make sure to release the swapchain */
5932 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5934 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5935 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5936 return WINED3DERR_INVALIDCALL;
5938 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5939 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5940 return WINED3DERR_INVALIDCALL;
5943 if(Swapchain->frontBuffer != Front) {
5944 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5946 if(Swapchain->frontBuffer)
5947 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5948 Swapchain->frontBuffer = Front;
5950 if(Swapchain->frontBuffer) {
5951 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5955 if(Back && !Swapchain->backBuffer) {
5956 /* We need memory for the back buffer array - only one back buffer this way */
5957 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5958 if(!Swapchain->backBuffer) {
5959 ERR("Out of memory\n");
5960 return E_OUTOFMEMORY;
5964 if(Swapchain->backBuffer[0] != Back) {
5965 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5967 /* What to do about the context here in the case of multithreading? Not sure.
5968 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5970 ENTER_GL();
5971 if(!Swapchain->backBuffer[0]) {
5972 /* GL was told to draw to the front buffer at creation,
5973 * undo that
5975 glDrawBuffer(GL_BACK);
5976 checkGLcall("glDrawBuffer(GL_BACK)");
5977 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5978 Swapchain->presentParms.BackBufferCount = 1;
5979 } else if (!Back) {
5980 /* That makes problems - disable for now */
5981 /* glDrawBuffer(GL_FRONT); */
5982 checkGLcall("glDrawBuffer(GL_FRONT)");
5983 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5984 Swapchain->presentParms.BackBufferCount = 0;
5986 LEAVE_GL();
5988 if(Swapchain->backBuffer[0])
5989 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5990 Swapchain->backBuffer[0] = Back;
5992 if(Swapchain->backBuffer[0]) {
5993 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5994 } else {
5995 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6000 return WINED3D_OK;
6003 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6005 *ppZStencilSurface = This->depthStencilBuffer;
6006 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6008 if(*ppZStencilSurface != NULL) {
6009 /* Note inc ref on returned surface */
6010 IWineD3DSurface_AddRef(*ppZStencilSurface);
6011 return WINED3D_OK;
6012 } else {
6013 return WINED3DERR_NOTFOUND;
6017 /* TODO: Handle stencil attachments */
6018 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6020 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6022 TRACE("Set depth stencil to %p\n", depth_stencil);
6024 if (depth_stencil_impl) {
6025 if (depth_stencil_impl->current_renderbuffer) {
6026 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6027 checkGLcall("glFramebufferRenderbufferEXT()");
6028 } else {
6029 IWineD3DBaseTextureImpl *texture_impl;
6030 GLenum texttarget, target;
6031 GLint old_binding = 0;
6033 texttarget = depth_stencil_impl->glDescription.target;
6034 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
6035 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6037 IWineD3DSurface_PreLoad(depth_stencil);
6039 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6040 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6041 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6042 glBindTexture(target, old_binding);
6044 /* Update base texture states array */
6045 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6046 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6047 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6048 if (texture_impl->baseTexture.bindCount) {
6049 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6052 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6055 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6056 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6057 checkGLcall("glFramebufferTexture2DEXT()");
6059 } else {
6060 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6061 checkGLcall("glFramebufferTexture2DEXT()");
6065 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6067 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6069 TRACE("Set render target %u to %p\n", idx, render_target);
6071 if (rtimpl) {
6072 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6073 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6074 } else {
6075 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6076 checkGLcall("glFramebufferTexture2DEXT()");
6078 This->draw_buffers[idx] = GL_NONE;
6082 static void check_fbo_status(IWineD3DDevice *iface) {
6083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6084 GLenum status;
6086 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6087 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6088 TRACE("FBO complete\n");
6089 } else {
6090 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6092 /* Dump the FBO attachments */
6093 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
6094 IWineD3DSurfaceImpl *attachment;
6095 int i;
6097 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6098 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6099 if (attachment) {
6100 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6101 attachment->pow2Width, attachment->pow2Height);
6104 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6105 if (attachment) {
6106 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6107 attachment->pow2Width, attachment->pow2Height);
6113 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6114 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6115 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6116 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6118 if (!ds_impl) return FALSE;
6120 if (ds_impl->current_renderbuffer) {
6121 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6122 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6125 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6126 rt_impl->pow2Height != ds_impl->pow2Height);
6129 void apply_fbo_state(IWineD3DDevice *iface) {
6130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6131 unsigned int i;
6133 if (This->render_offscreen) {
6134 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6136 /* Apply render targets */
6137 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6138 IWineD3DSurface *render_target = This->render_targets[i];
6139 if (This->fbo_color_attachments[i] != render_target) {
6140 set_render_target_fbo(iface, i, render_target);
6141 This->fbo_color_attachments[i] = render_target;
6145 /* Apply depth targets */
6146 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6147 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6148 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6150 if (This->stencilBufferTarget) {
6151 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6153 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6154 This->fbo_depth_attachment = This->stencilBufferTarget;
6157 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6158 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6159 checkGLcall("glDrawBuffers()");
6160 } else {
6161 glDrawBuffer(This->draw_buffers[0]);
6162 checkGLcall("glDrawBuffer()");
6164 } else {
6165 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6168 check_fbo_status(iface);
6171 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6172 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6174 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6175 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6176 GLenum gl_filter;
6178 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6179 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6180 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6181 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6183 switch (filter) {
6184 case WINED3DTEXF_LINEAR:
6185 gl_filter = GL_LINEAR;
6186 break;
6188 default:
6189 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6190 case WINED3DTEXF_NONE:
6191 case WINED3DTEXF_POINT:
6192 gl_filter = GL_NEAREST;
6193 break;
6196 /* Attach src surface to src fbo */
6197 src_swapchain = get_swapchain(src_surface);
6198 if (src_swapchain) {
6199 GLenum buffer;
6201 TRACE("Source surface %p is onscreen\n", src_surface);
6202 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6204 ENTER_GL();
6205 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6206 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6207 glReadBuffer(buffer);
6208 checkGLcall("glReadBuffer()");
6210 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6211 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6212 } else {
6213 TRACE("Source surface %p is offscreen\n", src_surface);
6214 ENTER_GL();
6215 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6216 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6217 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6218 checkGLcall("glReadBuffer()");
6220 LEAVE_GL();
6222 /* Attach dst surface to dst fbo */
6223 dst_swapchain = get_swapchain(dst_surface);
6224 if (dst_swapchain) {
6225 GLenum buffer;
6227 TRACE("Destination surface %p is onscreen\n", dst_surface);
6228 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6230 ENTER_GL();
6231 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6232 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6233 glDrawBuffer(buffer);
6234 checkGLcall("glDrawBuffer()");
6236 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6237 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6238 } else {
6239 TRACE("Destination surface %p is offscreen\n", dst_surface);
6241 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6242 if(!src_swapchain) {
6243 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6246 ENTER_GL();
6247 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6248 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6249 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6250 checkGLcall("glDrawBuffer()");
6252 glDisable(GL_SCISSOR_TEST);
6253 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6255 if (flip) {
6256 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6257 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6258 checkGLcall("glBlitFramebuffer()");
6259 } else {
6260 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6261 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6262 checkGLcall("glBlitFramebuffer()");
6265 if (This->render_offscreen) {
6266 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6267 } else {
6268 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6269 checkGLcall("glBindFramebuffer()");
6272 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6273 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6274 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6275 glDrawBuffer(GL_BACK);
6276 checkGLcall("glDrawBuffer()");
6278 LEAVE_GL();
6281 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6283 WINED3DVIEWPORT viewport;
6285 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6287 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6288 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6289 return WINED3DERR_INVALIDCALL;
6292 /* MSDN says that null disables the render target
6293 but a device must always be associated with a render target
6294 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6296 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6297 for more details
6299 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6300 FIXME("Trying to set render target 0 to NULL\n");
6301 return WINED3DERR_INVALIDCALL;
6303 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
6304 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);
6305 return WINED3DERR_INVALIDCALL;
6308 /* If we are trying to set what we already have, don't bother */
6309 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6310 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6311 return WINED3D_OK;
6313 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6314 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6315 This->render_targets[RenderTargetIndex] = pRenderTarget;
6317 /* Render target 0 is special */
6318 if(RenderTargetIndex == 0) {
6319 /* Finally, reset the viewport as the MSDN states. */
6320 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6321 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6322 viewport.X = 0;
6323 viewport.Y = 0;
6324 viewport.MaxZ = 1.0f;
6325 viewport.MinZ = 0.0f;
6326 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6327 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6328 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6330 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6332 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6333 * ctx properly.
6334 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6335 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6337 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6339 return WINED3D_OK;
6342 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6344 HRESULT hr = WINED3D_OK;
6345 IWineD3DSurface *tmp;
6347 TRACE("(%p) Swapping z-buffer\n",This);
6349 if (pNewZStencil == This->stencilBufferTarget) {
6350 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6351 } else {
6352 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6353 * depending on the renter target implementation being used.
6354 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6355 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6356 * stencil buffer and incure an extra memory overhead
6357 ******************************************************/
6359 tmp = This->stencilBufferTarget;
6360 This->stencilBufferTarget = pNewZStencil;
6361 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6362 /* should we be calling the parent or the wined3d surface? */
6363 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6364 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6365 hr = WINED3D_OK;
6367 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6368 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6369 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6370 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6375 return hr;
6378 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6379 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6381 /* TODO: the use of Impl is deprecated. */
6382 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6383 WINED3DLOCKED_RECT lockedRect;
6385 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6387 /* some basic validation checks */
6388 if(This->cursorTexture) {
6389 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6390 ENTER_GL();
6391 glDeleteTextures(1, &This->cursorTexture);
6392 LEAVE_GL();
6393 This->cursorTexture = 0;
6396 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6397 This->haveHardwareCursor = TRUE;
6398 else
6399 This->haveHardwareCursor = FALSE;
6401 if(pCursorBitmap) {
6402 WINED3DLOCKED_RECT rect;
6404 /* MSDN: Cursor must be A8R8G8B8 */
6405 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6406 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6407 return WINED3DERR_INVALIDCALL;
6410 /* MSDN: Cursor must be smaller than the display mode */
6411 if(pSur->currentDesc.Width > This->ddraw_width ||
6412 pSur->currentDesc.Height > This->ddraw_height) {
6413 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);
6414 return WINED3DERR_INVALIDCALL;
6417 if (!This->haveHardwareCursor) {
6418 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6420 /* Do not store the surface's pointer because the application may
6421 * release it after setting the cursor image. Windows doesn't
6422 * addref the set surface, so we can't do this either without
6423 * creating circular refcount dependencies. Copy out the gl texture
6424 * instead.
6426 This->cursorWidth = pSur->currentDesc.Width;
6427 This->cursorHeight = pSur->currentDesc.Height;
6428 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6430 const GlPixelFormatDesc *glDesc;
6431 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6432 char *mem, *bits = (char *)rect.pBits;
6433 GLint intfmt = glDesc->glInternal;
6434 GLint format = glDesc->glFormat;
6435 GLint type = glDesc->glType;
6436 INT height = This->cursorHeight;
6437 INT width = This->cursorWidth;
6438 INT bpp = tableEntry->bpp;
6439 INT i;
6441 /* Reformat the texture memory (pitch and width can be
6442 * different) */
6443 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6444 for(i = 0; i < height; i++)
6445 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6446 IWineD3DSurface_UnlockRect(pCursorBitmap);
6447 ENTER_GL();
6449 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6450 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6451 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6454 /* Make sure that a proper texture unit is selected */
6455 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6456 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6457 checkGLcall("glActiveTextureARB");
6459 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6460 /* Create a new cursor texture */
6461 glGenTextures(1, &This->cursorTexture);
6462 checkGLcall("glGenTextures");
6463 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6464 checkGLcall("glBindTexture");
6465 /* Copy the bitmap memory into the cursor texture */
6466 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6467 HeapFree(GetProcessHeap(), 0, mem);
6468 checkGLcall("glTexImage2D");
6470 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6471 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6472 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6475 LEAVE_GL();
6477 else
6479 FIXME("A cursor texture was not returned.\n");
6480 This->cursorTexture = 0;
6483 else
6485 /* Draw a hardware cursor */
6486 ICONINFO cursorInfo;
6487 HCURSOR cursor;
6488 /* Create and clear maskBits because it is not needed for
6489 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6490 * chunks. */
6491 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6492 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6493 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6494 WINED3DLOCK_NO_DIRTY_UPDATE |
6495 WINED3DLOCK_READONLY
6497 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6498 pSur->currentDesc.Height);
6500 cursorInfo.fIcon = FALSE;
6501 cursorInfo.xHotspot = XHotSpot;
6502 cursorInfo.yHotspot = YHotSpot;
6503 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6504 pSur->currentDesc.Height, 1,
6505 1, &maskBits);
6506 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6507 pSur->currentDesc.Height, 1,
6508 32, lockedRect.pBits);
6509 IWineD3DSurface_UnlockRect(pCursorBitmap);
6510 /* Create our cursor and clean up. */
6511 cursor = CreateIconIndirect(&cursorInfo);
6512 SetCursor(cursor);
6513 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6514 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6515 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6516 This->hardwareCursor = cursor;
6517 HeapFree(GetProcessHeap(), 0, maskBits);
6521 This->xHotSpot = XHotSpot;
6522 This->yHotSpot = YHotSpot;
6523 return WINED3D_OK;
6526 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6528 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6530 This->xScreenSpace = XScreenSpace;
6531 This->yScreenSpace = YScreenSpace;
6533 return;
6537 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6539 BOOL oldVisible = This->bCursorVisible;
6540 POINT pt;
6542 TRACE("(%p) : visible(%d)\n", This, bShow);
6545 * When ShowCursor is first called it should make the cursor appear at the OS's last
6546 * known cursor position. Because of this, some applications just repetitively call
6547 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6549 GetCursorPos(&pt);
6550 This->xScreenSpace = pt.x;
6551 This->yScreenSpace = pt.y;
6553 if (This->haveHardwareCursor) {
6554 This->bCursorVisible = bShow;
6555 if (bShow)
6556 SetCursor(This->hardwareCursor);
6557 else
6558 SetCursor(NULL);
6560 else
6562 if (This->cursorTexture)
6563 This->bCursorVisible = bShow;
6566 return oldVisible;
6569 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6571 TRACE("(%p) : state (%u)\n", This, This->state);
6572 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6573 switch (This->state) {
6574 case WINED3D_OK:
6575 return WINED3D_OK;
6576 case WINED3DERR_DEVICELOST:
6578 ResourceList *resourceList = This->resources;
6579 while (NULL != resourceList) {
6580 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6581 return WINED3DERR_DEVICENOTRESET;
6582 resourceList = resourceList->next;
6584 return WINED3DERR_DEVICELOST;
6586 case WINED3DERR_DRIVERINTERNALERROR:
6587 return WINED3DERR_DRIVERINTERNALERROR;
6590 /* Unknown state */
6591 return WINED3DERR_DRIVERINTERNALERROR;
6595 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6597 /** FIXME: Resource tracking needs to be done,
6598 * The closes we can do to this is set the priorities of all managed textures low
6599 * and then reset them.
6600 ***********************************************************/
6601 FIXME("(%p) : stub\n", This);
6602 return WINED3D_OK;
6605 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6606 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6608 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6609 if(surface->Flags & SFLAG_DIBSECTION) {
6610 /* Release the DC */
6611 SelectObject(surface->hDC, surface->dib.holdbitmap);
6612 DeleteDC(surface->hDC);
6613 /* Release the DIB section */
6614 DeleteObject(surface->dib.DIBsection);
6615 surface->dib.bitmap_data = NULL;
6616 surface->resource.allocatedMemory = NULL;
6617 surface->Flags &= ~SFLAG_DIBSECTION;
6619 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6620 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6621 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6622 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6623 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6624 } else {
6625 surface->pow2Width = surface->pow2Height = 1;
6626 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6627 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6629 if(surface->glDescription.textureName) {
6630 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6631 ENTER_GL();
6632 glDeleteTextures(1, &surface->glDescription.textureName);
6633 LEAVE_GL();
6634 surface->glDescription.textureName = 0;
6635 surface->Flags &= ~SFLAG_CLIENT;
6637 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6638 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6639 surface->Flags |= SFLAG_NONPOW2;
6640 } else {
6641 surface->Flags &= ~SFLAG_NONPOW2;
6643 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6644 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6647 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6649 IWineD3DSwapChainImpl *swapchain;
6650 HRESULT hr;
6651 BOOL DisplayModeChanged = FALSE;
6652 WINED3DDISPLAYMODE mode;
6653 TRACE("(%p)\n", This);
6655 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6656 if(FAILED(hr)) {
6657 ERR("Failed to get the first implicit swapchain\n");
6658 return hr;
6661 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6662 * on an existing gl context, so there's no real need for recreation.
6664 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6666 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6668 TRACE("New params:\n");
6669 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6670 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6671 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6672 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6673 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6674 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6675 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6676 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6677 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6678 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6679 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6680 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6681 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6683 /* No special treatment of these parameters. Just store them */
6684 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6685 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6686 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6687 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6689 /* What to do about these? */
6690 if(pPresentationParameters->BackBufferCount != 0 &&
6691 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6692 ERR("Cannot change the back buffer count yet\n");
6694 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6695 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6696 ERR("Cannot change the back buffer format yet\n");
6698 if(pPresentationParameters->hDeviceWindow != NULL &&
6699 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6700 ERR("Cannot change the device window yet\n");
6702 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6703 ERR("What do do about a changed auto depth stencil parameter?\n");
6706 if(pPresentationParameters->Windowed) {
6707 mode.Width = swapchain->orig_width;
6708 mode.Height = swapchain->orig_height;
6709 mode.RefreshRate = 0;
6710 mode.Format = swapchain->presentParms.BackBufferFormat;
6711 } else {
6712 mode.Width = pPresentationParameters->BackBufferWidth;
6713 mode.Height = pPresentationParameters->BackBufferHeight;
6714 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6715 mode.Format = swapchain->presentParms.BackBufferFormat;
6718 /* Should Width == 800 && Height == 0 set 800x600? */
6719 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6720 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6721 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6723 WINED3DVIEWPORT vp;
6724 int i;
6726 vp.X = 0;
6727 vp.Y = 0;
6728 vp.Width = pPresentationParameters->BackBufferWidth;
6729 vp.Height = pPresentationParameters->BackBufferHeight;
6730 vp.MinZ = 0;
6731 vp.MaxZ = 1;
6733 if(!pPresentationParameters->Windowed) {
6734 DisplayModeChanged = TRUE;
6736 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6737 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6739 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6740 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6741 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6744 /* Now set the new viewport */
6745 IWineD3DDevice_SetViewport(iface, &vp);
6748 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6749 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6750 DisplayModeChanged) {
6752 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6753 if(!pPresentationParameters->Windowed) {
6754 IWineD3DDevice_SetFullscreen(iface, TRUE);
6757 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6759 /* Switching out of fullscreen mode? First set the original res, then change the window */
6760 if(pPresentationParameters->Windowed) {
6761 IWineD3DDevice_SetFullscreen(iface, FALSE);
6763 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6766 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6767 return WINED3D_OK;
6770 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6772 /** FIXME: always true at the moment **/
6773 if(!bEnableDialogs) {
6774 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6776 return WINED3D_OK;
6780 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6782 TRACE("(%p) : pParameters %p\n", This, pParameters);
6784 *pParameters = This->createParms;
6785 return WINED3D_OK;
6788 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6789 IWineD3DSwapChain *swapchain;
6790 HRESULT hrc = WINED3D_OK;
6792 TRACE("Relaying to swapchain\n");
6794 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6795 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6796 IWineD3DSwapChain_Release(swapchain);
6798 return;
6801 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6802 IWineD3DSwapChain *swapchain;
6803 HRESULT hrc = WINED3D_OK;
6805 TRACE("Relaying to swapchain\n");
6807 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6808 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6809 IWineD3DSwapChain_Release(swapchain);
6811 return;
6815 /** ********************************************************
6816 * Notification functions
6817 ** ********************************************************/
6818 /** This function must be called in the release of a resource when ref == 0,
6819 * the contents of resource must still be correct,
6820 * any handels to other resource held by the caller must be closed
6821 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6822 *****************************************************/
6823 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6825 ResourceList* resourceList;
6827 TRACE("(%p) : resource %p\n", This, resource);
6828 /* add a new texture to the frot of the linked list */
6829 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6830 resourceList->resource = resource;
6832 /* Get the old head */
6833 resourceList->next = This->resources;
6835 This->resources = resourceList;
6836 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6838 return;
6841 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6843 ResourceList* resourceList = NULL;
6844 ResourceList* previousResourceList = NULL;
6846 TRACE("(%p) : resource %p\n", This, resource);
6848 resourceList = This->resources;
6850 while (resourceList != NULL) {
6851 if(resourceList->resource == resource) break;
6852 previousResourceList = resourceList;
6853 resourceList = resourceList->next;
6856 if (resourceList == NULL) {
6857 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6858 return;
6859 } else {
6860 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6862 /* make sure we don't leave a hole in the list */
6863 if (previousResourceList != NULL) {
6864 previousResourceList->next = resourceList->next;
6865 } else {
6866 This->resources = resourceList->next;
6869 return;
6873 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6875 int counter;
6877 TRACE("(%p) : resource %p\n", This, resource);
6878 switch(IWineD3DResource_GetType(resource)){
6879 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6880 case WINED3DRTYPE_SURFACE: {
6881 unsigned int i;
6883 /* Cleanup any FBO attachments if d3d is enabled */
6884 if(This->d3d_initialized) {
6885 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
6886 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
6888 TRACE("Last active render target destroyed\n");
6889 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
6890 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
6891 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
6892 * and the lastActiveRenderTarget member shouldn't matter
6894 if(swapchain) {
6895 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
6896 TRACE("Activating primary back buffer\n");
6897 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
6898 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
6899 /* Single buffering environment */
6900 TRACE("Activating primary front buffer\n");
6901 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
6902 } else {
6903 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
6904 /* Implicit render target destroyed, that means the device is being destroyed
6905 * whatever we set here, it shouldn't matter
6907 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
6909 } else {
6910 /* May happen during ddraw uninitialization */
6911 TRACE("Render target set, but swapchain does not exist!\n");
6912 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
6916 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6917 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6918 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6919 set_render_target_fbo(iface, i, NULL);
6920 This->fbo_color_attachments[i] = NULL;
6923 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6924 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6925 set_depth_stencil_fbo(iface, NULL);
6926 This->fbo_depth_attachment = NULL;
6930 break;
6932 case WINED3DRTYPE_TEXTURE:
6933 case WINED3DRTYPE_CUBETEXTURE:
6934 case WINED3DRTYPE_VOLUMETEXTURE:
6935 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6936 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6937 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6938 This->stateBlock->textures[counter] = NULL;
6940 if (This->updateStateBlock != This->stateBlock ){
6941 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6942 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6943 This->updateStateBlock->textures[counter] = NULL;
6947 break;
6948 case WINED3DRTYPE_VOLUME:
6949 /* TODO: nothing really? */
6950 break;
6951 case WINED3DRTYPE_VERTEXBUFFER:
6952 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6954 int streamNumber;
6955 TRACE("Cleaning up stream pointers\n");
6957 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6958 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6959 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6961 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6962 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6963 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6964 This->updateStateBlock->streamSource[streamNumber] = 0;
6965 /* Set changed flag? */
6968 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) */
6969 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6970 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6971 This->stateBlock->streamSource[streamNumber] = 0;
6974 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6975 else { /* This shouldn't happen */
6976 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6978 #endif
6982 break;
6983 case WINED3DRTYPE_INDEXBUFFER:
6984 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6985 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6986 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6987 This->updateStateBlock->pIndexData = NULL;
6990 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6991 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6992 This->stateBlock->pIndexData = NULL;
6996 break;
6997 default:
6998 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6999 break;
7003 /* Remove the resoruce from the resourceStore */
7004 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7006 TRACE("Resource released\n");
7010 /**********************************************************
7011 * IWineD3DDevice VTbl follows
7012 **********************************************************/
7014 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7016 /*** IUnknown methods ***/
7017 IWineD3DDeviceImpl_QueryInterface,
7018 IWineD3DDeviceImpl_AddRef,
7019 IWineD3DDeviceImpl_Release,
7020 /*** IWineD3DDevice methods ***/
7021 IWineD3DDeviceImpl_GetParent,
7022 /*** Creation methods**/
7023 IWineD3DDeviceImpl_CreateVertexBuffer,
7024 IWineD3DDeviceImpl_CreateIndexBuffer,
7025 IWineD3DDeviceImpl_CreateStateBlock,
7026 IWineD3DDeviceImpl_CreateSurface,
7027 IWineD3DDeviceImpl_CreateTexture,
7028 IWineD3DDeviceImpl_CreateVolumeTexture,
7029 IWineD3DDeviceImpl_CreateVolume,
7030 IWineD3DDeviceImpl_CreateCubeTexture,
7031 IWineD3DDeviceImpl_CreateQuery,
7032 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7033 IWineD3DDeviceImpl_CreateVertexDeclaration,
7034 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7035 IWineD3DDeviceImpl_CreateVertexShader,
7036 IWineD3DDeviceImpl_CreatePixelShader,
7037 IWineD3DDeviceImpl_CreatePalette,
7038 /*** Odd functions **/
7039 IWineD3DDeviceImpl_Init3D,
7040 IWineD3DDeviceImpl_Uninit3D,
7041 IWineD3DDeviceImpl_SetFullscreen,
7042 IWineD3DDeviceImpl_SetMultithreaded,
7043 IWineD3DDeviceImpl_EvictManagedResources,
7044 IWineD3DDeviceImpl_GetAvailableTextureMem,
7045 IWineD3DDeviceImpl_GetBackBuffer,
7046 IWineD3DDeviceImpl_GetCreationParameters,
7047 IWineD3DDeviceImpl_GetDeviceCaps,
7048 IWineD3DDeviceImpl_GetDirect3D,
7049 IWineD3DDeviceImpl_GetDisplayMode,
7050 IWineD3DDeviceImpl_SetDisplayMode,
7051 IWineD3DDeviceImpl_GetHWND,
7052 IWineD3DDeviceImpl_SetHWND,
7053 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7054 IWineD3DDeviceImpl_GetRasterStatus,
7055 IWineD3DDeviceImpl_GetSwapChain,
7056 IWineD3DDeviceImpl_Reset,
7057 IWineD3DDeviceImpl_SetDialogBoxMode,
7058 IWineD3DDeviceImpl_SetCursorProperties,
7059 IWineD3DDeviceImpl_SetCursorPosition,
7060 IWineD3DDeviceImpl_ShowCursor,
7061 IWineD3DDeviceImpl_TestCooperativeLevel,
7062 /*** Getters and setters **/
7063 IWineD3DDeviceImpl_SetClipPlane,
7064 IWineD3DDeviceImpl_GetClipPlane,
7065 IWineD3DDeviceImpl_SetClipStatus,
7066 IWineD3DDeviceImpl_GetClipStatus,
7067 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7068 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7069 IWineD3DDeviceImpl_SetDepthStencilSurface,
7070 IWineD3DDeviceImpl_GetDepthStencilSurface,
7071 IWineD3DDeviceImpl_SetFVF,
7072 IWineD3DDeviceImpl_GetFVF,
7073 IWineD3DDeviceImpl_SetGammaRamp,
7074 IWineD3DDeviceImpl_GetGammaRamp,
7075 IWineD3DDeviceImpl_SetIndices,
7076 IWineD3DDeviceImpl_GetIndices,
7077 IWineD3DDeviceImpl_SetBaseVertexIndex,
7078 IWineD3DDeviceImpl_GetBaseVertexIndex,
7079 IWineD3DDeviceImpl_SetLight,
7080 IWineD3DDeviceImpl_GetLight,
7081 IWineD3DDeviceImpl_SetLightEnable,
7082 IWineD3DDeviceImpl_GetLightEnable,
7083 IWineD3DDeviceImpl_SetMaterial,
7084 IWineD3DDeviceImpl_GetMaterial,
7085 IWineD3DDeviceImpl_SetNPatchMode,
7086 IWineD3DDeviceImpl_GetNPatchMode,
7087 IWineD3DDeviceImpl_SetPaletteEntries,
7088 IWineD3DDeviceImpl_GetPaletteEntries,
7089 IWineD3DDeviceImpl_SetPixelShader,
7090 IWineD3DDeviceImpl_GetPixelShader,
7091 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7092 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7093 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7094 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7095 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7096 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7097 IWineD3DDeviceImpl_SetRenderState,
7098 IWineD3DDeviceImpl_GetRenderState,
7099 IWineD3DDeviceImpl_SetRenderTarget,
7100 IWineD3DDeviceImpl_GetRenderTarget,
7101 IWineD3DDeviceImpl_SetFrontBackBuffers,
7102 IWineD3DDeviceImpl_SetSamplerState,
7103 IWineD3DDeviceImpl_GetSamplerState,
7104 IWineD3DDeviceImpl_SetScissorRect,
7105 IWineD3DDeviceImpl_GetScissorRect,
7106 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7107 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7108 IWineD3DDeviceImpl_SetStreamSource,
7109 IWineD3DDeviceImpl_GetStreamSource,
7110 IWineD3DDeviceImpl_SetStreamSourceFreq,
7111 IWineD3DDeviceImpl_GetStreamSourceFreq,
7112 IWineD3DDeviceImpl_SetTexture,
7113 IWineD3DDeviceImpl_GetTexture,
7114 IWineD3DDeviceImpl_SetTextureStageState,
7115 IWineD3DDeviceImpl_GetTextureStageState,
7116 IWineD3DDeviceImpl_SetTransform,
7117 IWineD3DDeviceImpl_GetTransform,
7118 IWineD3DDeviceImpl_SetVertexDeclaration,
7119 IWineD3DDeviceImpl_GetVertexDeclaration,
7120 IWineD3DDeviceImpl_SetVertexShader,
7121 IWineD3DDeviceImpl_GetVertexShader,
7122 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7123 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7124 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7125 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7126 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7127 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7128 IWineD3DDeviceImpl_SetViewport,
7129 IWineD3DDeviceImpl_GetViewport,
7130 IWineD3DDeviceImpl_MultiplyTransform,
7131 IWineD3DDeviceImpl_ValidateDevice,
7132 IWineD3DDeviceImpl_ProcessVertices,
7133 /*** State block ***/
7134 IWineD3DDeviceImpl_BeginStateBlock,
7135 IWineD3DDeviceImpl_EndStateBlock,
7136 /*** Scene management ***/
7137 IWineD3DDeviceImpl_BeginScene,
7138 IWineD3DDeviceImpl_EndScene,
7139 IWineD3DDeviceImpl_Present,
7140 IWineD3DDeviceImpl_Clear,
7141 /*** Drawing ***/
7142 IWineD3DDeviceImpl_DrawPrimitive,
7143 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7144 IWineD3DDeviceImpl_DrawPrimitiveUP,
7145 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7146 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7147 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7148 IWineD3DDeviceImpl_DrawRectPatch,
7149 IWineD3DDeviceImpl_DrawTriPatch,
7150 IWineD3DDeviceImpl_DeletePatch,
7151 IWineD3DDeviceImpl_ColorFill,
7152 IWineD3DDeviceImpl_UpdateTexture,
7153 IWineD3DDeviceImpl_UpdateSurface,
7154 IWineD3DDeviceImpl_GetFrontBufferData,
7155 /*** object tracking ***/
7156 IWineD3DDeviceImpl_ResourceReleased
7160 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7161 WINED3DRS_ALPHABLENDENABLE ,
7162 WINED3DRS_ALPHAFUNC ,
7163 WINED3DRS_ALPHAREF ,
7164 WINED3DRS_ALPHATESTENABLE ,
7165 WINED3DRS_BLENDOP ,
7166 WINED3DRS_COLORWRITEENABLE ,
7167 WINED3DRS_DESTBLEND ,
7168 WINED3DRS_DITHERENABLE ,
7169 WINED3DRS_FILLMODE ,
7170 WINED3DRS_FOGDENSITY ,
7171 WINED3DRS_FOGEND ,
7172 WINED3DRS_FOGSTART ,
7173 WINED3DRS_LASTPIXEL ,
7174 WINED3DRS_SHADEMODE ,
7175 WINED3DRS_SRCBLEND ,
7176 WINED3DRS_STENCILENABLE ,
7177 WINED3DRS_STENCILFAIL ,
7178 WINED3DRS_STENCILFUNC ,
7179 WINED3DRS_STENCILMASK ,
7180 WINED3DRS_STENCILPASS ,
7181 WINED3DRS_STENCILREF ,
7182 WINED3DRS_STENCILWRITEMASK ,
7183 WINED3DRS_STENCILZFAIL ,
7184 WINED3DRS_TEXTUREFACTOR ,
7185 WINED3DRS_WRAP0 ,
7186 WINED3DRS_WRAP1 ,
7187 WINED3DRS_WRAP2 ,
7188 WINED3DRS_WRAP3 ,
7189 WINED3DRS_WRAP4 ,
7190 WINED3DRS_WRAP5 ,
7191 WINED3DRS_WRAP6 ,
7192 WINED3DRS_WRAP7 ,
7193 WINED3DRS_ZENABLE ,
7194 WINED3DRS_ZFUNC ,
7195 WINED3DRS_ZWRITEENABLE
7198 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7199 WINED3DTSS_ADDRESSW ,
7200 WINED3DTSS_ALPHAARG0 ,
7201 WINED3DTSS_ALPHAARG1 ,
7202 WINED3DTSS_ALPHAARG2 ,
7203 WINED3DTSS_ALPHAOP ,
7204 WINED3DTSS_BUMPENVLOFFSET ,
7205 WINED3DTSS_BUMPENVLSCALE ,
7206 WINED3DTSS_BUMPENVMAT00 ,
7207 WINED3DTSS_BUMPENVMAT01 ,
7208 WINED3DTSS_BUMPENVMAT10 ,
7209 WINED3DTSS_BUMPENVMAT11 ,
7210 WINED3DTSS_COLORARG0 ,
7211 WINED3DTSS_COLORARG1 ,
7212 WINED3DTSS_COLORARG2 ,
7213 WINED3DTSS_COLOROP ,
7214 WINED3DTSS_RESULTARG ,
7215 WINED3DTSS_TEXCOORDINDEX ,
7216 WINED3DTSS_TEXTURETRANSFORMFLAGS
7219 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7220 WINED3DSAMP_ADDRESSU ,
7221 WINED3DSAMP_ADDRESSV ,
7222 WINED3DSAMP_ADDRESSW ,
7223 WINED3DSAMP_BORDERCOLOR ,
7224 WINED3DSAMP_MAGFILTER ,
7225 WINED3DSAMP_MINFILTER ,
7226 WINED3DSAMP_MIPFILTER ,
7227 WINED3DSAMP_MIPMAPLODBIAS ,
7228 WINED3DSAMP_MAXMIPLEVEL ,
7229 WINED3DSAMP_MAXANISOTROPY ,
7230 WINED3DSAMP_SRGBTEXTURE ,
7231 WINED3DSAMP_ELEMENTINDEX
7234 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7235 WINED3DRS_AMBIENT ,
7236 WINED3DRS_AMBIENTMATERIALSOURCE ,
7237 WINED3DRS_CLIPPING ,
7238 WINED3DRS_CLIPPLANEENABLE ,
7239 WINED3DRS_COLORVERTEX ,
7240 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7241 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7242 WINED3DRS_FOGDENSITY ,
7243 WINED3DRS_FOGEND ,
7244 WINED3DRS_FOGSTART ,
7245 WINED3DRS_FOGTABLEMODE ,
7246 WINED3DRS_FOGVERTEXMODE ,
7247 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7248 WINED3DRS_LIGHTING ,
7249 WINED3DRS_LOCALVIEWER ,
7250 WINED3DRS_MULTISAMPLEANTIALIAS ,
7251 WINED3DRS_MULTISAMPLEMASK ,
7252 WINED3DRS_NORMALIZENORMALS ,
7253 WINED3DRS_PATCHEDGESTYLE ,
7254 WINED3DRS_POINTSCALE_A ,
7255 WINED3DRS_POINTSCALE_B ,
7256 WINED3DRS_POINTSCALE_C ,
7257 WINED3DRS_POINTSCALEENABLE ,
7258 WINED3DRS_POINTSIZE ,
7259 WINED3DRS_POINTSIZE_MAX ,
7260 WINED3DRS_POINTSIZE_MIN ,
7261 WINED3DRS_POINTSPRITEENABLE ,
7262 WINED3DRS_RANGEFOGENABLE ,
7263 WINED3DRS_SPECULARMATERIALSOURCE ,
7264 WINED3DRS_TWEENFACTOR ,
7265 WINED3DRS_VERTEXBLEND ,
7266 WINED3DRS_CULLMODE ,
7267 WINED3DRS_FOGCOLOR
7270 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7271 WINED3DTSS_TEXCOORDINDEX ,
7272 WINED3DTSS_TEXTURETRANSFORMFLAGS
7275 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7276 WINED3DSAMP_DMAPOFFSET
7279 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7280 DWORD rep = StateTable[state].representative;
7281 DWORD idx;
7282 BYTE shift;
7283 UINT i;
7284 WineD3DContext *context;
7286 if(!rep) return;
7287 for(i = 0; i < This->numContexts; i++) {
7288 context = This->contexts[i];
7289 if(isStateDirty(context, rep)) continue;
7291 context->dirtyArray[context->numDirtyEntries++] = rep;
7292 idx = rep >> 5;
7293 shift = rep & 0x1f;
7294 context->isStateDirty[idx] |= (1 << shift);