wined3d: Support event queries using GL_NV_fence.
[wine/wine64.git] / dlls / wined3d / device.c
blob3ab1279c473c3772169c3a22c25375568c5037db
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 Stefan Dösinger for CodeWeavers
10 * Copyright 2006 Henri Verbeet
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include <stdio.h>
29 #ifdef HAVE_FLOAT_H
30 # include <float.h>
31 #endif
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
35 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
37 /* Define the default light parameters as specified by MSDN */
38 const WINED3DLIGHT WINED3D_default_light = {
40 WINED3DLIGHT_DIRECTIONAL, /* Type */
41 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
42 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
44 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
45 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
46 0.0, /* Range */
47 0.0, /* Falloff */
48 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
49 0.0, /* Theta */
50 0.0 /* Phi */
53 /* x11drv GDI escapes */
54 #define X11DRV_ESCAPE 6789
55 enum x11drv_escape_codes
57 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
58 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
59 X11DRV_GET_FONT, /* get current X font for a DC */
62 /* retrieve the X display to use on a given DC */
63 inline static Display *get_display( HDC hdc )
65 Display *display;
66 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
68 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
69 sizeof(display), (LPSTR)&display )) display = NULL;
70 return display;
73 /* allocate one pbuffer per surface */
74 BOOL pbuffer_per_surface = FALSE;
76 /* static function declarations */
77 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
79 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil);
81 /* helper macros */
82 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
84 #define D3DCREATEOBJECTINSTANCE(object, type) { \
85 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
86 D3DMEMCHECK(object, pp##type); \
87 object->lpVtbl = &IWineD3D##type##_Vtbl; \
88 object->wineD3DDevice = This; \
89 object->parent = parent; \
90 object->ref = 1; \
91 *pp##type = (IWineD3D##type *) object; \
94 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
95 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
96 D3DMEMCHECK(object, pp##type); \
97 object->lpVtbl = &IWineD3D##type##_Vtbl; \
98 object->parent = parent; \
99 object->ref = 1; \
100 object->baseShader.device = (IWineD3DDevice*) This; \
101 list_init(&object->baseShader.linked_programs); \
102 *pp##type = (IWineD3D##type *) object; \
105 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
106 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
107 D3DMEMCHECK(object, pp##type); \
108 object->lpVtbl = &IWineD3D##type##_Vtbl; \
109 object->resource.wineD3DDevice = This; \
110 object->resource.parent = parent; \
111 object->resource.resourceType = d3dtype; \
112 object->resource.ref = 1; \
113 object->resource.pool = Pool; \
114 object->resource.format = Format; \
115 object->resource.usage = Usage; \
116 object->resource.size = _size; \
117 /* Check that we have enough video ram left */ \
118 if (Pool == WINED3DPOOL_DEFAULT) { \
119 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
120 WARN("Out of 'bogus' video memory\n"); \
121 HeapFree(GetProcessHeap(), 0, object); \
122 *pp##type = NULL; \
123 return WINED3DERR_OUTOFVIDEOMEMORY; \
125 globalChangeGlRam(_size); \
127 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
128 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
129 FIXME("Out of memory!\n"); \
130 HeapFree(GetProcessHeap(), 0, object); \
131 *pp##type = NULL; \
132 return WINED3DERR_OUTOFVIDEOMEMORY; \
134 *pp##type = (IWineD3D##type *) object; \
135 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
136 TRACE("(%p) : Created resource %p\n", This, object); \
139 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
140 _basetexture.levels = Levels; \
141 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
142 _basetexture.LOD = 0; \
143 _basetexture.dirty = TRUE; \
146 /**********************************************************
147 * Global variable / Constants follow
148 **********************************************************/
149 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
151 /**********************************************************
152 * IUnknown parts follows
153 **********************************************************/
155 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
159 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
160 if (IsEqualGUID(riid, &IID_IUnknown)
161 || IsEqualGUID(riid, &IID_IWineD3DBase)
162 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
163 IUnknown_AddRef(iface);
164 *ppobj = This;
165 return S_OK;
167 *ppobj = NULL;
168 return E_NOINTERFACE;
171 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
173 ULONG refCount = InterlockedIncrement(&This->ref);
175 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
176 return refCount;
179 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
181 ULONG refCount = InterlockedDecrement(&This->ref);
183 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
185 if (!refCount) {
186 if (This->fbo) {
187 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
190 HeapFree(GetProcessHeap(), 0, This->render_targets);
192 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
194 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
196 /* TODO: Clean up all the surfaces and textures! */
197 /* NOTE: You must release the parent if the object was created via a callback
198 ** ***************************/
200 /* Release the update stateblock */
201 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
202 if(This->updateStateBlock != This->stateBlock)
203 FIXME("(%p) Something's still holding the Update stateblock\n",This);
205 This->updateStateBlock = NULL;
206 { /* because were not doing proper internal refcounts releasing the primary state block
207 causes recursion with the extra checks in ResourceReleased, to avoid this we have
208 to set this->stateBlock = NULL; first */
209 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
210 This->stateBlock = NULL;
212 /* Release the stateblock */
213 if(IWineD3DStateBlock_Release(stateBlock) > 0){
214 FIXME("(%p) Something's still holding the Update stateblock\n",This);
218 if (This->resources != NULL ) {
219 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
220 dumpResources(This->resources);
223 if(This->contexts) ERR("Context array not freed!\n");
225 IWineD3D_Release(This->wineD3D);
226 This->wineD3D = NULL;
227 HeapFree(GetProcessHeap(), 0, This);
228 TRACE("Freed device %p\n", This);
229 This = NULL;
231 return refCount;
234 /**********************************************************
235 * IWineD3DDevice implementation follows
236 **********************************************************/
237 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
238 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
239 *pParent = This->parent;
240 IUnknown_AddRef(This->parent);
241 return WINED3D_OK;
244 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
245 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
246 GLenum error, glUsage;
247 DWORD vboUsage = object->resource.usage;
248 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
249 WARN("Creating a vbo failed once, not trying again\n");
250 return;
253 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
255 ENTER_GL();
256 /* Make sure that the gl error is cleared. Do not use checkGLcall
257 * here because checkGLcall just prints a fixme and continues. However,
258 * if an error during VBO creation occurs we can fall back to non-vbo operation
259 * with full functionality(but performance loss)
261 while(glGetError() != GL_NO_ERROR);
263 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
264 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
265 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
266 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
267 * to check if the rhw and color values are in the correct format.
270 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
271 error = glGetError();
272 if(object->vbo == 0 || error != GL_NO_ERROR) {
273 WARN("Failed to create a VBO with error %d\n", error);
274 goto error;
277 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
278 error = glGetError();
279 if(error != GL_NO_ERROR) {
280 WARN("Failed to bind the VBO, error %d\n", error);
281 goto error;
284 /* Don't use static, because dx apps tend to update the buffer
285 * quite often even if they specify 0 usage. Because we always keep the local copy
286 * we never read from the vbo and can create a write only opengl buffer.
288 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
289 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
290 case WINED3DUSAGE_DYNAMIC:
291 TRACE("Gl usage = GL_STREAM_DRAW\n");
292 glUsage = GL_STREAM_DRAW_ARB;
293 break;
294 case WINED3DUSAGE_WRITEONLY:
295 default:
296 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
297 glUsage = GL_DYNAMIC_DRAW_ARB;
298 break;
301 /* Reserve memory for the buffer. The amount of data won't change
302 * so we are safe with calling glBufferData once with a NULL ptr and
303 * calling glBufferSubData on updates
305 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
306 error = glGetError();
307 if(error != GL_NO_ERROR) {
308 WARN("glBufferDataARB failed with error %d\n", error);
309 goto error;
312 LEAVE_GL();
314 return;
315 error:
316 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
317 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
318 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
319 object->vbo = 0;
320 object->Flags |= VBFLAG_VBOCREATEFAIL;
321 LEAVE_GL();
322 return;
325 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
326 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
327 IUnknown *parent) {
328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
329 IWineD3DVertexBufferImpl *object;
330 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
331 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
332 BOOL conv;
334 if(Size == 0) {
335 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
336 *ppVertexBuffer = NULL;
337 return WINED3DERR_INVALIDCALL;
340 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
342 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
343 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
345 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
346 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
348 object->fvf = FVF;
350 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
351 * drawStridedFast (half-life 2).
353 * Basically converting the vertices in the buffer is quite expensive, and observations
354 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
355 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
357 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
358 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
359 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
360 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
361 * dx7 apps.
362 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
363 * more. In this call we can convert dx7 buffers too.
365 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
366 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
367 (dxVersion > 7 || !conv) ) {
368 CreateVBO(object);
370 return WINED3D_OK;
373 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
374 GLenum error, glUsage;
375 TRACE("Creating VBO for Index Buffer %p\n", object);
377 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
378 * restored on the next draw
380 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
382 ENTER_GL();
383 while(glGetError());
385 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
386 error = glGetError();
387 if(error != GL_NO_ERROR || object->vbo == 0) {
388 ERR("Creating a vbo failed, continueing without vbo for this buffer\n");
389 goto out;
392 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
393 error = glGetError();
394 if(error != GL_NO_ERROR) {
395 ERR("Failed to bind index buffer, continueing without vbo for this buffer\n");
396 goto out;
399 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
400 * copy no readback will be needed
402 glUsage = GL_STATIC_DRAW_ARB;
403 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
404 error = glGetError();
405 if(error != GL_NO_ERROR) {
406 ERR("Failed to initialize the index buffer\n");
407 goto out;
409 LEAVE_GL();
410 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
411 return;
413 out:
414 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
415 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
416 LEAVE_GL();
417 object->vbo = 0;
420 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
421 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
422 HANDLE *sharedHandle, IUnknown *parent) {
423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
424 IWineD3DIndexBufferImpl *object;
425 TRACE("(%p) Creating index buffer\n", This);
427 /* Allocate the storage for the device */
428 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
430 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
431 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
434 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
435 CreateIndexBufferVBO(This, object);
438 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
439 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
440 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
442 return WINED3D_OK;
445 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
448 IWineD3DStateBlockImpl *object;
449 int i, j;
450 HRESULT temp_result;
452 D3DCREATEOBJECTINSTANCE(object, StateBlock)
453 object->blockType = Type;
455 for(i = 0; i < LIGHTMAP_SIZE; i++) {
456 list_init(&object->lightMap[i]);
459 /* Special case - Used during initialization to produce a placeholder stateblock
460 so other functions called can update a state block */
461 if (Type == WINED3DSBT_INIT) {
462 /* Don't bother increasing the reference count otherwise a device will never
463 be freed due to circular dependencies */
464 return WINED3D_OK;
467 temp_result = allocate_shader_constants(object);
468 if (WINED3D_OK != temp_result)
469 return temp_result;
471 /* Otherwise, might as well set the whole state block to the appropriate values */
472 if (This->stateBlock != NULL)
473 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
474 else
475 memset(object->streamFreq, 1, sizeof(object->streamFreq));
477 /* Reset the ref and type after kludging it */
478 object->wineD3DDevice = This;
479 object->ref = 1;
480 object->blockType = Type;
482 TRACE("Updating changed flags appropriate for type %d\n", Type);
484 if (Type == WINED3DSBT_ALL) {
486 TRACE("ALL => Pretend everything has changed\n");
487 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
489 /* Lights are not part of the changed / set structure */
490 for(j = 0; j < LIGHTMAP_SIZE; j++) {
491 struct list *e;
492 LIST_FOR_EACH(e, &object->lightMap[j]) {
493 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
494 light->changed = TRUE;
495 light->enabledChanged = TRUE;
498 } else if (Type == WINED3DSBT_PIXELSTATE) {
500 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
501 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
503 object->changed.pixelShader = TRUE;
505 /* Pixel Shader Constants */
506 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
507 object->changed.pixelShaderConstantsF[i] = TRUE;
508 for (i = 0; i < MAX_CONST_B; ++i)
509 object->changed.pixelShaderConstantsB[i] = TRUE;
510 for (i = 0; i < MAX_CONST_I; ++i)
511 object->changed.pixelShaderConstantsI[i] = TRUE;
513 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
514 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
516 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
517 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
518 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
521 for (j = 0 ; j < 16; j++) {
522 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
524 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
528 } else if (Type == WINED3DSBT_VERTEXSTATE) {
530 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
531 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
533 object->changed.vertexShader = TRUE;
535 /* Vertex Shader Constants */
536 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
537 object->changed.vertexShaderConstantsF[i] = TRUE;
538 for (i = 0; i < MAX_CONST_B; ++i)
539 object->changed.vertexShaderConstantsB[i] = TRUE;
540 for (i = 0; i < MAX_CONST_I; ++i)
541 object->changed.vertexShaderConstantsI[i] = TRUE;
543 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
544 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
546 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
547 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
548 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
551 for (j = 0 ; j < 16; j++){
552 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
553 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
557 for(j = 0; j < LIGHTMAP_SIZE; j++) {
558 struct list *e;
559 LIST_FOR_EACH(e, &object->lightMap[j]) {
560 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
561 light->changed = TRUE;
562 light->enabledChanged = TRUE;
565 } else {
566 FIXME("Unrecognized state block type %d\n", Type);
569 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
570 return WINED3D_OK;
574 /* ************************************
575 MSDN:
576 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
578 Discard
579 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
581 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
583 ******************************** */
585 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
587 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
588 unsigned int pow2Width, pow2Height;
589 unsigned int Size = 1;
590 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
591 TRACE("(%p) Create surface\n",This);
593 /** FIXME: Check ranges on the inputs are valid
594 * MSDN
595 * MultisampleQuality
596 * [in] Quality level. The valid range is between zero and one less than the level
597 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
598 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
599 * values of paired render targets, depth stencil surfaces, and the MultiSample type
600 * must all match.
601 *******************************/
605 * TODO: Discard MSDN
606 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
608 * If this flag is set, the contents of the depth stencil buffer will be
609 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
610 * with a different depth surface.
612 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
613 ***************************/
615 if(MultisampleQuality < 0) {
616 FIXME("Invalid multisample level %d\n", MultisampleQuality);
617 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
620 if(MultisampleQuality > 0) {
621 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
622 MultisampleQuality=0;
625 /** FIXME: Check that the format is supported
626 * by the device.
627 *******************************/
629 /* Non-power2 support */
630 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
631 pow2Width = Width;
632 pow2Height = Height;
633 } else {
634 /* Find the nearest pow2 match */
635 pow2Width = pow2Height = 1;
636 while (pow2Width < Width) pow2Width <<= 1;
637 while (pow2Height < Height) pow2Height <<= 1;
640 if (pow2Width > Width || pow2Height > Height) {
641 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
642 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
643 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
644 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
645 This, Width, Height);
646 return WINED3DERR_NOTAVAILABLE;
650 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
651 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
652 * space!
653 *********************************/
654 if (WINED3DFMT_UNKNOWN == Format) {
655 Size = 0;
656 } else if (Format == WINED3DFMT_DXT1) {
657 /* DXT1 is half byte per pixel */
658 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
660 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
661 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
662 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
663 } else {
664 /* The pitch is a multiple of 4 bytes */
665 Size = ((Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
666 Size *= Height;
669 /** Create and initialise the surface resource **/
670 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
671 /* "Standalone" surface */
672 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
674 object->currentDesc.Width = Width;
675 object->currentDesc.Height = Height;
676 object->currentDesc.MultiSampleType = MultiSample;
677 object->currentDesc.MultiSampleQuality = MultisampleQuality;
679 /* Setup some glformat defaults */
680 object->glDescription.glFormat = tableEntry->glFormat;
681 object->glDescription.glFormatInternal = tableEntry->glInternal;
682 object->glDescription.glType = tableEntry->glType;
684 object->glDescription.textureName = 0;
685 object->glDescription.level = Level;
686 object->glDescription.target = GL_TEXTURE_2D;
688 /* Internal data */
689 object->pow2Width = pow2Width;
690 object->pow2Height = pow2Height;
692 /* Flags */
693 object->Flags = 0; /* We start without flags set */
694 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
695 object->Flags |= Discard ? SFLAG_DISCARD : 0;
696 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
697 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
700 if (WINED3DFMT_UNKNOWN != Format) {
701 object->bytesPerPixel = tableEntry->bpp;
702 } else {
703 object->bytesPerPixel = 0;
706 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
708 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
710 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
711 * this function is too deep to need to care about things like this.
712 * Levels need to be checked too, and possibly Type since they all affect what can be done.
713 * ****************************************/
714 switch(Pool) {
715 case WINED3DPOOL_SCRATCH:
716 if(!Lockable)
717 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
718 "which are mutually exclusive, setting lockable to TRUE\n");
719 Lockable = TRUE;
720 break;
721 case WINED3DPOOL_SYSTEMMEM:
722 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
723 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
724 case WINED3DPOOL_MANAGED:
725 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
726 "Usage of DYNAMIC which are mutually exclusive, not doing "
727 "anything just telling you.\n");
728 break;
729 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
730 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
731 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
732 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
733 break;
734 default:
735 FIXME("(%p) Unknown pool %d\n", This, Pool);
736 break;
739 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
740 FIXME("Trying to create a render target that isn't in the default pool\n");
743 /* mark the texture as dirty so that it gets loaded first time around*/
744 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
745 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
746 This, Width, Height, Format, debug_d3dformat(Format),
747 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
749 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
750 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
751 This->ddraw_primary = (IWineD3DSurface *) object;
753 /* Look at the implementation and set the correct Vtable */
754 switch(Impl) {
755 case SURFACE_OPENGL:
756 /* Nothing to do, it's set already */
757 break;
759 case SURFACE_GDI:
760 object->lpVtbl = &IWineGDISurface_Vtbl;
761 break;
763 default:
764 /* To be sure to catch this */
765 ERR("Unknown requested surface implementation %d!\n", Impl);
766 IWineD3DSurface_Release((IWineD3DSurface *) object);
767 return WINED3DERR_INVALIDCALL;
770 /* Call the private setup routine */
771 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
775 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
776 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
777 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
778 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
781 IWineD3DTextureImpl *object;
782 unsigned int i;
783 UINT tmpW;
784 UINT tmpH;
785 HRESULT hr;
786 unsigned int pow2Width;
787 unsigned int pow2Height;
790 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
791 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
792 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
794 /* TODO: It should only be possible to create textures for formats
795 that are reported as supported */
796 if (WINED3DFMT_UNKNOWN >= Format) {
797 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
798 return WINED3DERR_INVALIDCALL;
801 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
802 D3DINITIALIZEBASETEXTURE(object->baseTexture);
803 object->width = Width;
804 object->height = Height;
806 /** Non-power2 support **/
807 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
808 pow2Width = Width;
809 pow2Height = Height;
810 } else {
811 /* Find the nearest pow2 match */
812 pow2Width = pow2Height = 1;
813 while (pow2Width < Width) pow2Width <<= 1;
814 while (pow2Height < Height) pow2Height <<= 1;
817 /** FIXME: add support for real non-power-two if it's provided by the video card **/
818 /* Precalculated scaling for 'faked' non power of two texture coords */
819 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
820 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
821 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
823 /* Calculate levels for mip mapping */
824 if (Levels == 0) {
825 TRACE("calculating levels %d\n", object->baseTexture.levels);
826 object->baseTexture.levels++;
827 tmpW = Width;
828 tmpH = Height;
829 while (tmpW > 1 || tmpH > 1) {
830 tmpW = max(1, tmpW >> 1);
831 tmpH = max(1, tmpH >> 1);
832 object->baseTexture.levels++;
834 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
837 /* Generate all the surfaces */
838 tmpW = Width;
839 tmpH = Height;
840 for (i = 0; i < object->baseTexture.levels; i++)
842 /* use the callback to create the texture surface */
843 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
844 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
845 FIXME("Failed to create surface %p\n", object);
846 /* clean up */
847 object->surfaces[i] = NULL;
848 IWineD3DTexture_Release((IWineD3DTexture *)object);
850 *ppTexture = NULL;
851 return hr;
854 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
855 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
856 /* calculate the next mipmap level */
857 tmpW = max(1, tmpW >> 1);
858 tmpH = max(1, tmpH >> 1);
861 TRACE("(%p) : Created texture %p\n", This, object);
862 return WINED3D_OK;
865 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
866 UINT Width, UINT Height, UINT Depth,
867 UINT Levels, DWORD Usage,
868 WINED3DFORMAT Format, WINED3DPOOL Pool,
869 IWineD3DVolumeTexture **ppVolumeTexture,
870 HANDLE *pSharedHandle, IUnknown *parent,
871 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
874 IWineD3DVolumeTextureImpl *object;
875 unsigned int i;
876 UINT tmpW;
877 UINT tmpH;
878 UINT tmpD;
880 /* TODO: It should only be possible to create textures for formats
881 that are reported as supported */
882 if (WINED3DFMT_UNKNOWN >= Format) {
883 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
884 return WINED3DERR_INVALIDCALL;
887 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
888 D3DINITIALIZEBASETEXTURE(object->baseTexture);
890 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
891 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
893 object->width = Width;
894 object->height = Height;
895 object->depth = Depth;
897 /* Calculate levels for mip mapping */
898 if (Levels == 0) {
899 object->baseTexture.levels++;
900 tmpW = Width;
901 tmpH = Height;
902 tmpD = Depth;
903 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
904 tmpW = max(1, tmpW >> 1);
905 tmpH = max(1, tmpH >> 1);
906 tmpD = max(1, tmpD >> 1);
907 object->baseTexture.levels++;
909 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
912 /* Generate all the surfaces */
913 tmpW = Width;
914 tmpH = Height;
915 tmpD = Depth;
917 for (i = 0; i < object->baseTexture.levels; i++)
919 HRESULT hr;
920 /* Create the volume */
921 hr = D3DCB_CreateVolume(This->parent, parent, Width, Height, Depth, Format, Pool, Usage,
922 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
924 if(FAILED(hr)) {
925 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
926 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
927 *ppVolumeTexture = NULL;
928 return hr;
931 /* Set its container to this object */
932 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
934 /* calcualte the next mipmap level */
935 tmpW = max(1, tmpW >> 1);
936 tmpH = max(1, tmpH >> 1);
937 tmpD = max(1, tmpD >> 1);
940 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
941 TRACE("(%p) : Created volume texture %p\n", This, object);
942 return WINED3D_OK;
945 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
946 UINT Width, UINT Height, UINT Depth,
947 DWORD Usage,
948 WINED3DFORMAT Format, WINED3DPOOL Pool,
949 IWineD3DVolume** ppVolume,
950 HANDLE* pSharedHandle, IUnknown *parent) {
952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
953 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
954 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
956 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
958 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
959 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
961 object->currentDesc.Width = Width;
962 object->currentDesc.Height = Height;
963 object->currentDesc.Depth = Depth;
964 object->bytesPerPixel = formatDesc->bpp;
966 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
967 object->lockable = TRUE;
968 object->locked = FALSE;
969 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
970 object->dirty = TRUE;
972 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
975 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
976 UINT Levels, DWORD Usage,
977 WINED3DFORMAT Format, WINED3DPOOL Pool,
978 IWineD3DCubeTexture **ppCubeTexture,
979 HANDLE *pSharedHandle, IUnknown *parent,
980 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
983 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
984 unsigned int i, j;
985 UINT tmpW;
986 HRESULT hr;
987 unsigned int pow2EdgeLength = EdgeLength;
989 /* TODO: It should only be possible to create textures for formats
990 that are reported as supported */
991 if (WINED3DFMT_UNKNOWN >= Format) {
992 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
993 return WINED3DERR_INVALIDCALL;
996 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
997 D3DINITIALIZEBASETEXTURE(object->baseTexture);
999 TRACE("(%p) Create Cube Texture\n", This);
1001 /** Non-power2 support **/
1003 /* Find the nearest pow2 match */
1004 pow2EdgeLength = 1;
1005 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1007 object->edgeLength = EdgeLength;
1008 /* TODO: support for native non-power 2 */
1009 /* Precalculated scaling for 'faked' non power of two texture coords */
1010 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1012 /* Calculate levels for mip mapping */
1013 if (Levels == 0) {
1014 object->baseTexture.levels++;
1015 tmpW = EdgeLength;
1016 while (tmpW > 1) {
1017 tmpW = max(1, tmpW >> 1);
1018 object->baseTexture.levels++;
1020 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1023 /* Generate all the surfaces */
1024 tmpW = EdgeLength;
1025 for (i = 0; i < object->baseTexture.levels; i++) {
1027 /* Create the 6 faces */
1028 for (j = 0; j < 6; j++) {
1030 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1031 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1033 if(hr!= WINED3D_OK) {
1034 /* clean up */
1035 int k;
1036 int l;
1037 for (l = 0; l < j; l++) {
1038 IWineD3DSurface_Release(object->surfaces[j][i]);
1040 for (k = 0; k < i; k++) {
1041 for (l = 0; l < 6; l++) {
1042 IWineD3DSurface_Release(object->surfaces[l][j]);
1046 FIXME("(%p) Failed to create surface\n",object);
1047 HeapFree(GetProcessHeap(),0,object);
1048 *ppCubeTexture = NULL;
1049 return hr;
1051 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1052 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1054 tmpW = max(1, tmpW >> 1);
1057 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1058 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1059 return WINED3D_OK;
1062 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1064 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1065 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1067 /* Just a check to see if we support this type of query */
1068 switch(Type) {
1069 case WINED3DQUERYTYPE_OCCLUSION:
1070 TRACE("(%p) occlusion query\n", This);
1071 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1072 hr = WINED3D_OK;
1073 else
1074 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1075 break;
1077 case WINED3DQUERYTYPE_EVENT:
1078 if(!GL_SUPPORT(NV_FENCE)) {
1079 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1080 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1082 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1084 hr = WINED3D_OK;
1085 break;
1087 case WINED3DQUERYTYPE_VCACHE:
1088 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1089 case WINED3DQUERYTYPE_VERTEXSTATS:
1090 case WINED3DQUERYTYPE_TIMESTAMP:
1091 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1092 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1093 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1094 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1095 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1096 case WINED3DQUERYTYPE_PIXELTIMINGS:
1097 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1098 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1099 default:
1100 FIXME("(%p) Unhandled query type %d\n", This, Type);
1102 if(NULL == ppQuery || hr != WINED3D_OK) {
1103 return hr;
1106 D3DCREATEOBJECTINSTANCE(object, Query)
1107 object->type = Type;
1108 /* allocated the 'extended' data based on the type of query requested */
1109 switch(Type){
1110 case WINED3DQUERYTYPE_OCCLUSION:
1111 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1112 TRACE("(%p) Allocating data for an occlusion query\n", This);
1113 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1114 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1115 break;
1117 case WINED3DQUERYTYPE_EVENT:
1118 /* TODO: GL_APPLE_fence */
1119 if(GL_SUPPORT(NV_FENCE)) {
1120 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1121 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1122 checkGLcall("glGenFencesNV");
1124 break;
1126 case WINED3DQUERYTYPE_VCACHE:
1127 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1128 case WINED3DQUERYTYPE_VERTEXSTATS:
1129 case WINED3DQUERYTYPE_TIMESTAMP:
1130 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1131 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1132 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1133 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1134 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1135 case WINED3DQUERYTYPE_PIXELTIMINGS:
1136 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1137 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1138 default:
1139 object->extendedData = 0;
1140 FIXME("(%p) Unhandled query type %d\n",This , Type);
1142 TRACE("(%p) : Created Query %p\n", This, object);
1143 return WINED3D_OK;
1146 /*****************************************************************************
1147 * IWineD3DDeviceImpl_SetupFullscreenWindow
1149 * Helper function that modifies a HWND's Style and ExStyle for proper
1150 * fullscreen use.
1152 * Params:
1153 * iface: Pointer to the IWineD3DDevice interface
1154 * window: Window to setup
1156 *****************************************************************************/
1157 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1160 LONG style, exStyle;
1161 /* Don't do anything if an original style is stored.
1162 * That shouldn't happen
1164 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1165 if (This->style || This->exStyle) {
1166 ERR("(%p): Want to change the window parameters of HWND %p, but "
1167 "another style is stored for restoration afterwards\n", This, window);
1170 /* Get the parameters and save them */
1171 style = GetWindowLongW(window, GWL_STYLE);
1172 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1173 This->style = style;
1174 This->exStyle = exStyle;
1176 /* Filter out window decorations */
1177 style &= ~WS_CAPTION;
1178 style &= ~WS_THICKFRAME;
1179 exStyle &= ~WS_EX_WINDOWEDGE;
1180 exStyle &= ~WS_EX_CLIENTEDGE;
1182 /* Make sure the window is managed, otherwise we won't get keyboard input */
1183 style |= WS_POPUP | WS_SYSMENU;
1185 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1186 This->style, This->exStyle, style, exStyle);
1188 SetWindowLongW(window, GWL_STYLE, style);
1189 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1191 /* Inform the window about the update. */
1192 SetWindowPos(window, HWND_TOP, 0, 0,
1193 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1194 ShowWindow(window, SW_NORMAL);
1197 /*****************************************************************************
1198 * IWineD3DDeviceImpl_RestoreWindow
1200 * Helper function that restores a windows' properties when taking it out
1201 * of fullscreen mode
1203 * Params:
1204 * iface: Pointer to the IWineD3DDevice interface
1205 * window: Window to setup
1207 *****************************************************************************/
1208 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1211 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1212 * switch, do nothing
1214 if (!This->style && !This->exStyle) return;
1216 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1217 This, window, This->style, This->exStyle);
1219 SetWindowLongW(window, GWL_STYLE, This->style);
1220 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1222 /* Delete the old values */
1223 This->style = 0;
1224 This->exStyle = 0;
1226 /* Inform the window about the update */
1227 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1228 0, 0, 0, 0, /* Pos, Size, ignored */
1229 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1232 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1233 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1234 IUnknown* parent,
1235 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1236 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1239 HDC hDc;
1240 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1241 HRESULT hr = WINED3D_OK;
1242 IUnknown *bufferParent;
1243 Display *display;
1245 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1247 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1248 * does a device hold a reference to a swap chain giving them a lifetime of the device
1249 * or does the swap chain notify the device of its destruction.
1250 *******************************/
1252 /* Check the params */
1253 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1254 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1255 return WINED3DERR_INVALIDCALL;
1256 } else if (pPresentationParameters->BackBufferCount > 1) {
1257 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");
1260 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1262 /*********************
1263 * Lookup the window Handle and the relating X window handle
1264 ********************/
1266 /* Setup hwnd we are using, plus which display this equates to */
1267 object->win_handle = pPresentationParameters->hDeviceWindow;
1268 if (!object->win_handle) {
1269 object->win_handle = This->createParms.hFocusWindow;
1272 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1273 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1274 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1275 return WINED3DERR_NOTAVAILABLE;
1277 hDc = GetDC(object->win_handle);
1278 display = get_display(hDc);
1279 ReleaseDC(object->win_handle, hDc);
1280 TRACE("Using a display of %p %p\n", display, hDc);
1282 if (NULL == display || NULL == hDc) {
1283 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1284 return WINED3DERR_NOTAVAILABLE;
1287 if (object->win == 0) {
1288 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1289 return WINED3DERR_NOTAVAILABLE;
1292 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1293 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1294 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1296 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1297 * then the corresponding dimension of the client area of the hDeviceWindow
1298 * (or the focus window, if hDeviceWindow is NULL) is taken.
1299 **********************/
1301 if (pPresentationParameters->Windowed &&
1302 ((pPresentationParameters->BackBufferWidth == 0) ||
1303 (pPresentationParameters->BackBufferHeight == 0))) {
1305 RECT Rect;
1306 GetClientRect(object->win_handle, &Rect);
1308 if (pPresentationParameters->BackBufferWidth == 0) {
1309 pPresentationParameters->BackBufferWidth = Rect.right;
1310 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1312 if (pPresentationParameters->BackBufferHeight == 0) {
1313 pPresentationParameters->BackBufferHeight = Rect.bottom;
1314 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1318 /* Put the correct figures in the presentation parameters */
1319 TRACE("Copying across presentation parameters\n");
1320 object->presentParms = *pPresentationParameters;
1322 TRACE("calling rendertarget CB\n");
1323 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1324 parent,
1325 object->presentParms.BackBufferWidth,
1326 object->presentParms.BackBufferHeight,
1327 object->presentParms.BackBufferFormat,
1328 object->presentParms.MultiSampleType,
1329 object->presentParms.MultiSampleQuality,
1330 TRUE /* Lockable */,
1331 &object->frontBuffer,
1332 NULL /* pShared (always null)*/);
1333 if (object->frontBuffer != NULL) {
1334 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1335 } else {
1336 ERR("Failed to create the front buffer\n");
1337 goto error;
1341 * Create an opengl context for the display visual
1342 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1343 * use different properties after that point in time. FIXME: How to handle when requested format
1344 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1345 * it chooses is identical to the one already being used!
1346 **********************************/
1348 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1349 ENTER_GL();
1350 object->context = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1351 LEAVE_GL();
1353 if (!object->context) {
1354 ERR("Failed to create a new context\n");
1355 hr = WINED3DERR_NOTAVAILABLE;
1356 goto error;
1357 } else {
1358 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1359 object->win_handle, object->context->glCtx, object->win);
1362 /*********************
1363 * Windowed / Fullscreen
1364 *******************/
1367 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1368 * so we should really check to see if there is a fullscreen swapchain already
1369 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1370 **************************************/
1372 if (!pPresentationParameters->Windowed) {
1374 DEVMODEW devmode;
1375 HDC hdc;
1376 int bpp = 0;
1377 RECT clip_rc;
1379 /* Get info on the current display setup */
1380 hdc = GetDC(0);
1381 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1382 ReleaseDC(0, hdc);
1384 /* Change the display settings */
1385 memset(&devmode, 0, sizeof(DEVMODEW));
1386 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1387 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1388 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1389 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1390 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1391 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1393 /* For GetDisplayMode */
1394 This->ddraw_width = devmode.dmPelsWidth;
1395 This->ddraw_height = devmode.dmPelsHeight;
1396 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1398 IWineD3DDevice_SetFullscreen(iface, TRUE);
1400 /* And finally clip mouse to our screen */
1401 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1402 ClipCursor(&clip_rc);
1405 /*********************
1406 * Create the back, front and stencil buffers
1407 *******************/
1408 if(object->presentParms.BackBufferCount > 0) {
1409 int i;
1411 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1412 if(!object->backBuffer) {
1413 ERR("Out of memory\n");
1414 hr = E_OUTOFMEMORY;
1415 goto error;
1418 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1419 TRACE("calling rendertarget CB\n");
1420 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1421 parent,
1422 object->presentParms.BackBufferWidth,
1423 object->presentParms.BackBufferHeight,
1424 object->presentParms.BackBufferFormat,
1425 object->presentParms.MultiSampleType,
1426 object->presentParms.MultiSampleQuality,
1427 TRUE /* Lockable */,
1428 &object->backBuffer[i],
1429 NULL /* pShared (always null)*/);
1430 if(hr == WINED3D_OK && object->backBuffer[i]) {
1431 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1432 } else {
1433 ERR("Cannot create new back buffer\n");
1434 goto error;
1436 ENTER_GL();
1437 glDrawBuffer(GL_BACK);
1438 checkGLcall("glDrawBuffer(GL_BACK)");
1439 LEAVE_GL();
1441 } else {
1442 object->backBuffer = NULL;
1444 /* Single buffering - draw to front buffer */
1445 ENTER_GL();
1446 glDrawBuffer(GL_FRONT);
1447 checkGLcall("glDrawBuffer(GL_FRONT)");
1448 LEAVE_GL();
1451 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1452 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1453 TRACE("Creating depth stencil buffer\n");
1454 if (This->depthStencilBuffer == NULL ) {
1455 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1456 parent,
1457 object->presentParms.BackBufferWidth,
1458 object->presentParms.BackBufferHeight,
1459 object->presentParms.AutoDepthStencilFormat,
1460 object->presentParms.MultiSampleType,
1461 object->presentParms.MultiSampleQuality,
1462 FALSE /* FIXME: Discard */,
1463 &This->depthStencilBuffer,
1464 NULL /* pShared (always null)*/ );
1465 if (This->depthStencilBuffer != NULL)
1466 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1469 /** TODO: A check on width, height and multisample types
1470 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1471 ****************************/
1472 object->wantsDepthStencilBuffer = TRUE;
1473 } else {
1474 object->wantsDepthStencilBuffer = FALSE;
1477 TRACE("Created swapchain %p\n", object);
1478 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1479 return WINED3D_OK;
1481 error:
1482 if (object->backBuffer) {
1483 int i;
1484 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1485 if(object->backBuffer[i]) {
1486 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1487 IUnknown_Release(bufferParent); /* once for the get parent */
1488 if (IUnknown_Release(bufferParent) > 0) {
1489 FIXME("(%p) Something's still holding the back buffer\n",This);
1493 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1494 object->backBuffer = NULL;
1496 if(object->context) {
1497 DestroyContext(This, object->context);
1499 if(object->frontBuffer) {
1500 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1501 IUnknown_Release(bufferParent); /* once for the get parent */
1502 if (IUnknown_Release(bufferParent) > 0) {
1503 FIXME("(%p) Something's still holding the front buffer\n",This);
1506 if(object) HeapFree(GetProcessHeap(), 0, object);
1507 return hr;
1510 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1511 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1513 TRACE("(%p)\n", This);
1515 return This->NumberOfSwapChains;
1518 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1520 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1522 if(iSwapChain < This->NumberOfSwapChains) {
1523 *pSwapChain = This->swapchains[iSwapChain];
1524 IWineD3DSwapChain_AddRef(*pSwapChain);
1525 TRACE("(%p) returning %p\n", This, *pSwapChain);
1526 return WINED3D_OK;
1527 } else {
1528 TRACE("Swapchain out of range\n");
1529 *pSwapChain = NULL;
1530 return WINED3DERR_INVALIDCALL;
1534 /*****
1535 * Vertex Declaration
1536 *****/
1537 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1538 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1540 IWineD3DVertexDeclarationImpl *object = NULL;
1541 HRESULT hr = WINED3D_OK;
1543 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1544 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1546 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1547 object->allFVF = 0;
1549 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1551 return hr;
1554 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1555 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1557 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1558 HRESULT hr = WINED3D_OK;
1559 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1560 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1562 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1564 if (vertex_declaration) {
1565 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1568 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1570 if (WINED3D_OK != hr) {
1571 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1572 IWineD3DVertexShader_Release(*ppVertexShader);
1573 return WINED3DERR_INVALIDCALL;
1576 return WINED3D_OK;
1579 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1581 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1582 HRESULT hr = WINED3D_OK;
1584 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1585 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1586 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1587 if (WINED3D_OK == hr) {
1588 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1589 } else {
1590 WARN("(%p) : Failed to create pixel shader\n", This);
1593 return hr;
1596 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1598 IWineD3DPaletteImpl *object;
1599 HRESULT hr;
1600 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1602 /* Create the new object */
1603 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1604 if(!object) {
1605 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1606 return E_OUTOFMEMORY;
1609 object->lpVtbl = &IWineD3DPalette_Vtbl;
1610 object->ref = 1;
1611 object->Flags = Flags;
1612 object->parent = Parent;
1613 object->wineD3DDevice = This;
1614 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1616 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1618 if(!object->hpal) {
1619 HeapFree( GetProcessHeap(), 0, object);
1620 return E_OUTOFMEMORY;
1623 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1624 if(FAILED(hr)) {
1625 IWineD3DPalette_Release((IWineD3DPalette *) object);
1626 return hr;
1629 *Palette = (IWineD3DPalette *) object;
1631 return WINED3D_OK;
1634 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1636 IWineD3DSwapChainImpl *swapchain;
1637 DWORD state;
1639 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1640 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1642 /* TODO: Test if OpenGL is compiled in and loaded */
1644 /* Initialize the texture unit mapping to a 1:1 mapping */
1645 for(state = 0; state < MAX_SAMPLERS; state++) {
1646 This->texUnitMap[state] = state;
1648 This->oneToOneTexUnitMap = TRUE;
1650 /* Setup the implicit swapchain */
1651 TRACE("Creating implicit swapchain\n");
1652 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain)) || !swapchain) {
1653 WARN("Failed to create implicit swapchain\n");
1654 return WINED3DERR_INVALIDCALL;
1657 This->NumberOfSwapChains = 1;
1658 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1659 if(!This->swapchains) {
1660 ERR("Out of memory!\n");
1661 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1662 return E_OUTOFMEMORY;
1664 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1666 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1668 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1669 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1670 This->render_targets[0] = swapchain->backBuffer[0];
1671 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1673 else {
1674 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1675 This->render_targets[0] = swapchain->frontBuffer;
1676 This->lastActiveRenderTarget = swapchain->frontBuffer;
1678 IWineD3DSurface_AddRef(This->render_targets[0]);
1679 This->activeContext = swapchain->context;
1681 /* Depth Stencil support */
1682 This->stencilBufferTarget = This->depthStencilBuffer;
1683 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1684 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
1686 if (NULL != This->stencilBufferTarget) {
1687 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1690 /* Set up some starting GL setup */
1691 ENTER_GL();
1693 * Initialize openGL extension related variables
1694 * with Default values
1697 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->context->display);
1698 /* Setup all the devices defaults */
1699 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1700 #if 0
1701 IWineD3DImpl_CheckGraphicsMemory();
1702 #endif
1704 { /* Set a default viewport */
1705 WINED3DVIEWPORT vp;
1706 vp.X = 0;
1707 vp.Y = 0;
1708 vp.Width = pPresentationParameters->BackBufferWidth;
1709 vp.Height = pPresentationParameters->BackBufferHeight;
1710 vp.MinZ = 0.0f;
1711 vp.MaxZ = 1.0f;
1712 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1715 /* Initialize the current view state */
1716 This->view_ident = 1;
1717 This->contexts[0]->last_was_rhw = 0;
1718 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1719 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1721 switch(wined3d_settings.offscreen_rendering_mode) {
1722 case ORM_FBO:
1723 case ORM_PBUFFER:
1724 This->offscreenBuffer = GL_BACK;
1725 break;
1727 case ORM_BACKBUFFER:
1729 GLint auxBuffers;
1730 glGetIntegerv(GL_AUX_BUFFERS, &auxBuffers);
1731 TRACE("Got %d aux buffers\n", auxBuffers);
1732 if(auxBuffers > 0) {
1733 TRACE("Using auxilliary buffer for offscreen rendering\n");
1734 This->offscreenBuffer = GL_AUX0;
1735 } else {
1736 TRACE("Using back buffer for offscreen rendering\n");
1737 This->offscreenBuffer = GL_BACK;
1742 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1743 LEAVE_GL();
1745 /* Clear the screen */
1746 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
1748 This->d3d_initialized = TRUE;
1749 return WINED3D_OK;
1752 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1754 int sampler;
1755 uint i;
1756 TRACE("(%p)\n", This);
1758 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1760 /* Delete the pbuffer context if there is any */
1761 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1763 /* Delete the mouse cursor texture */
1764 if(This->cursorTexture) {
1765 ENTER_GL();
1766 glDeleteTextures(1, &This->cursorTexture);
1767 LEAVE_GL();
1768 This->cursorTexture = 0;
1771 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1772 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1775 /* Release the buffers (with sanity checks)*/
1776 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1777 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1778 if(This->depthStencilBuffer != This->stencilBufferTarget)
1779 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1781 This->stencilBufferTarget = NULL;
1783 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1784 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1785 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1787 TRACE("Setting rendertarget to NULL\n");
1788 This->render_targets[0] = NULL;
1790 if (This->depthStencilBuffer) {
1791 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1792 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1794 This->depthStencilBuffer = NULL;
1797 for(i=0; i < This->NumberOfSwapChains; i++) {
1798 TRACE("Releasing the implicit swapchain %d\n", i);
1799 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1800 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1804 HeapFree(GetProcessHeap(), 0, This->swapchains);
1805 This->swapchains = NULL;
1806 This->NumberOfSwapChains = 0;
1808 This->d3d_initialized = FALSE;
1809 return WINED3D_OK;
1812 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1814 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1816 /* Setup the window for fullscreen mode */
1817 if(fullscreen && !This->ddraw_fullscreen) {
1818 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1819 } else if(!fullscreen && This->ddraw_fullscreen) {
1820 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1823 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1824 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1825 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1826 * separately.
1828 This->ddraw_fullscreen = fullscreen;
1831 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
1832 DEVMODEW devmode;
1833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1834 LONG ret;
1835 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
1836 RECT clip_rc;
1838 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1840 /* Resize the screen even without a window:
1841 * The app could have unset it with SetCooperativeLevel, but not called
1842 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1843 * but we don't have any hwnd
1846 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1847 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1848 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
1849 devmode.dmPelsWidth = pMode->Width;
1850 devmode.dmPelsHeight = pMode->Height;
1852 devmode.dmDisplayFrequency = pMode->RefreshRate;
1853 if (pMode->RefreshRate != 0) {
1854 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1857 /* Only change the mode if necessary */
1858 if( (This->ddraw_width == pMode->Width) &&
1859 (This->ddraw_height == pMode->Height) &&
1860 (This->ddraw_format == pMode->Format) &&
1861 (pMode->RefreshRate == 0) ) {
1862 return WINED3D_OK;
1865 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1866 if (ret != DISP_CHANGE_SUCCESSFUL) {
1867 if(devmode.dmDisplayFrequency != 0) {
1868 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1869 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1870 devmode.dmDisplayFrequency = 0;
1871 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1873 if(ret != DISP_CHANGE_SUCCESSFUL) {
1874 return DDERR_INVALIDMODE;
1878 /* Store the new values */
1879 This->ddraw_width = pMode->Width;
1880 This->ddraw_height = pMode->Height;
1881 This->ddraw_format = pMode->Format;
1883 /* Only do this with a window of course */
1884 if(This->ddraw_window)
1885 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
1887 /* And finally clip mouse to our screen */
1888 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1889 ClipCursor(&clip_rc);
1891 return WINED3D_OK;
1894 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1896 *ppD3D= This->wineD3D;
1897 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
1898 IWineD3D_AddRef(*ppD3D);
1899 return WINED3D_OK;
1902 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1903 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
1904 * into the video ram as possible and seeing how many fit
1905 * you can also get the correct initial value from nvidia and ATI's driver via X
1906 * texture memory is video memory + AGP memory
1907 *******************/
1908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1909 static BOOL showfixmes = TRUE;
1910 if (showfixmes) {
1911 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
1912 (wined3d_settings.emulated_textureram/(1024*1024)),
1913 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1914 showfixmes = FALSE;
1916 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1917 (wined3d_settings.emulated_textureram/(1024*1024)),
1918 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1919 /* return simulated texture memory left */
1920 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
1925 /*****
1926 * Get / Set FVF
1927 *****/
1928 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
1929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1931 /* Update the current state block */
1932 This->updateStateBlock->changed.fvf = TRUE;
1933 This->updateStateBlock->set.fvf = TRUE;
1935 if(This->updateStateBlock->fvf == fvf) {
1936 TRACE("Application is setting the old fvf over, nothing to do\n");
1937 return WINED3D_OK;
1940 This->updateStateBlock->fvf = fvf;
1941 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
1942 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
1943 return WINED3D_OK;
1947 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
1948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1949 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
1950 *pfvf = This->stateBlock->fvf;
1951 return WINED3D_OK;
1954 /*****
1955 * Get / Set Stream Source
1956 *****/
1957 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
1958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1959 IWineD3DVertexBuffer *oldSrc;
1961 if (StreamNumber >= MAX_STREAMS) {
1962 WARN("Stream out of range %d\n", StreamNumber);
1963 return WINED3DERR_INVALIDCALL;
1966 oldSrc = This->stateBlock->streamSource[StreamNumber];
1967 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
1969 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
1970 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
1972 if(oldSrc == pStreamData &&
1973 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
1974 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
1975 TRACE("Application is setting the old values over, nothing to do\n");
1976 return WINED3D_OK;
1979 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
1980 if (pStreamData) {
1981 This->updateStateBlock->streamStride[StreamNumber] = Stride;
1982 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
1985 /* Handle recording of state blocks */
1986 if (This->isRecordingState) {
1987 TRACE("Recording... not performing anything\n");
1988 return WINED3D_OK;
1991 /* Need to do a getParent and pass the reffs up */
1992 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
1993 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
1994 so for now, just count internally */
1995 if (pStreamData != NULL) {
1996 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
1997 InterlockedIncrement(&vbImpl->bindCount);
1999 if (oldSrc != NULL) {
2000 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2003 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2005 return WINED3D_OK;
2008 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2011 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2012 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2014 if (StreamNumber >= MAX_STREAMS) {
2015 WARN("Stream out of range %d\n", StreamNumber);
2016 return WINED3DERR_INVALIDCALL;
2018 *pStream = This->stateBlock->streamSource[StreamNumber];
2019 *pStride = This->stateBlock->streamStride[StreamNumber];
2020 if (pOffset) {
2021 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2024 if (*pStream != NULL) {
2025 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2027 return WINED3D_OK;
2030 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2032 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2033 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2035 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2036 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2038 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2039 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2040 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2042 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2043 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2044 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2047 return WINED3D_OK;
2050 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2053 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2054 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2056 TRACE("(%p) : returning %d\n", This, *Divider);
2058 return WINED3D_OK;
2061 /*****
2062 * Get / Set & Multiply Transform
2063 *****/
2064 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2067 /* Most of this routine, comments included copied from ddraw tree initially: */
2068 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2070 /* Handle recording of state blocks */
2071 if (This->isRecordingState) {
2072 TRACE("Recording... not performing anything\n");
2073 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2074 This->updateStateBlock->set.transform[d3dts] = TRUE;
2075 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2076 return WINED3D_OK;
2080 * If the new matrix is the same as the current one,
2081 * we cut off any further processing. this seems to be a reasonable
2082 * optimization because as was noticed, some apps (warcraft3 for example)
2083 * tend towards setting the same matrix repeatedly for some reason.
2085 * From here on we assume that the new matrix is different, wherever it matters.
2087 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2088 TRACE("The app is setting the same matrix over again\n");
2089 return WINED3D_OK;
2090 } else {
2091 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2095 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2096 where ViewMat = Camera space, WorldMat = world space.
2098 In OpenGL, camera and world space is combined into GL_MODELVIEW
2099 matrix. The Projection matrix stay projection matrix.
2102 /* Capture the times we can just ignore the change for now */
2103 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2104 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2105 /* Handled by the state manager */
2108 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2109 return WINED3D_OK;
2112 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2114 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2115 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2116 return WINED3D_OK;
2119 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2120 WINED3DMATRIX *mat = NULL;
2121 WINED3DMATRIX temp;
2123 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2124 * below means it will be recorded in a state block change, but it
2125 * works regardless where it is recorded.
2126 * If this is found to be wrong, change to StateBlock.
2128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2129 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2131 if (State < HIGHEST_TRANSFORMSTATE)
2133 mat = &This->updateStateBlock->transforms[State];
2134 } else {
2135 FIXME("Unhandled transform state!!\n");
2138 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2140 /* Apply change via set transform - will reapply to eg. lights this way */
2141 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2144 /*****
2145 * Get / Set Light
2146 *****/
2147 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2148 you can reference any indexes you want as long as that number max are enabled at any
2149 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2150 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2151 but when recording, just build a chain pretty much of commands to be replayed. */
2153 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2154 float rho;
2155 PLIGHTINFOEL *object = NULL;
2156 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2157 struct list *e;
2159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2160 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2162 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2163 * the gl driver.
2165 if(!pLight) {
2166 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2167 return WINED3DERR_INVALIDCALL;
2170 switch(pLight->Type) {
2171 case WINED3DLIGHT_POINT:
2172 case WINED3DLIGHT_SPOT:
2173 case WINED3DLIGHT_PARALLELPOINT:
2174 case WINED3DLIGHT_GLSPOT:
2175 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2176 * most wanted
2178 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2179 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2180 return WINED3DERR_INVALIDCALL;
2182 break;
2184 case WINED3DLIGHT_DIRECTIONAL:
2185 /* Ignores attenuation */
2186 break;
2188 default:
2189 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2190 return WINED3DERR_INVALIDCALL;
2193 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2194 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2195 if(object->OriginalIndex == Index) break;
2196 object = NULL;
2199 if(!object) {
2200 TRACE("Adding new light\n");
2201 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2202 if(!object) {
2203 ERR("Out of memory error when allocating a light\n");
2204 return E_OUTOFMEMORY;
2206 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2207 object->glIndex = -1;
2208 object->OriginalIndex = Index;
2209 object->changed = TRUE;
2212 /* Initialize the object */
2213 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,
2214 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2215 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2216 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2217 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2218 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2219 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2221 /* Save away the information */
2222 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2224 switch (pLight->Type) {
2225 case WINED3DLIGHT_POINT:
2226 /* Position */
2227 object->lightPosn[0] = pLight->Position.x;
2228 object->lightPosn[1] = pLight->Position.y;
2229 object->lightPosn[2] = pLight->Position.z;
2230 object->lightPosn[3] = 1.0f;
2231 object->cutoff = 180.0f;
2232 /* FIXME: Range */
2233 break;
2235 case WINED3DLIGHT_DIRECTIONAL:
2236 /* Direction */
2237 object->lightPosn[0] = -pLight->Direction.x;
2238 object->lightPosn[1] = -pLight->Direction.y;
2239 object->lightPosn[2] = -pLight->Direction.z;
2240 object->lightPosn[3] = 0.0;
2241 object->exponent = 0.0f;
2242 object->cutoff = 180.0f;
2243 break;
2245 case WINED3DLIGHT_SPOT:
2246 /* Position */
2247 object->lightPosn[0] = pLight->Position.x;
2248 object->lightPosn[1] = pLight->Position.y;
2249 object->lightPosn[2] = pLight->Position.z;
2250 object->lightPosn[3] = 1.0;
2252 /* Direction */
2253 object->lightDirn[0] = pLight->Direction.x;
2254 object->lightDirn[1] = pLight->Direction.y;
2255 object->lightDirn[2] = pLight->Direction.z;
2256 object->lightDirn[3] = 1.0;
2259 * opengl-ish and d3d-ish spot lights use too different models for the
2260 * light "intensity" as a function of the angle towards the main light direction,
2261 * so we only can approximate very roughly.
2262 * however spot lights are rather rarely used in games (if ever used at all).
2263 * furthermore if still used, probably nobody pays attention to such details.
2265 if (pLight->Falloff == 0) {
2266 rho = 6.28f;
2267 } else {
2268 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2270 if (rho < 0.0001) rho = 0.0001f;
2271 object->exponent = -0.3/log(cos(rho/2));
2272 if (object->exponent > 128.0) {
2273 object->exponent = 128.0;
2275 object->cutoff = pLight->Phi*90/M_PI;
2277 /* FIXME: Range */
2278 break;
2280 default:
2281 FIXME("Unrecognized light type %d\n", pLight->Type);
2284 /* Update the live definitions if the light is currently assigned a glIndex */
2285 if (object->glIndex != -1 && !This->isRecordingState) {
2286 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2288 return WINED3D_OK;
2291 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2292 PLIGHTINFOEL *lightInfo = NULL;
2293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2294 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2295 struct list *e;
2296 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2298 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2299 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2300 if(lightInfo->OriginalIndex == Index) break;
2301 lightInfo = NULL;
2304 if (lightInfo == NULL) {
2305 TRACE("Light information requested but light not defined\n");
2306 return WINED3DERR_INVALIDCALL;
2309 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2310 return WINED3D_OK;
2313 /*****
2314 * Get / Set Light Enable
2315 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2316 *****/
2317 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2318 PLIGHTINFOEL *lightInfo = NULL;
2319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2320 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2321 struct list *e;
2322 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2324 /* Tests show true = 128...not clear why */
2325 Enable = Enable? 128: 0;
2327 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2328 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2329 if(lightInfo->OriginalIndex == Index) break;
2330 lightInfo = NULL;
2332 TRACE("Found light: %p\n", lightInfo);
2334 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2335 if (lightInfo == NULL) {
2337 TRACE("Light enabled requested but light not defined, so defining one!\n");
2338 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2340 /* Search for it again! Should be fairly quick as near head of list */
2341 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2342 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2343 if(lightInfo->OriginalIndex == Index) break;
2344 lightInfo = NULL;
2346 if (lightInfo == NULL) {
2347 FIXME("Adding default lights has failed dismally\n");
2348 return WINED3DERR_INVALIDCALL;
2352 lightInfo->enabledChanged = TRUE;
2353 if(!Enable) {
2354 if(lightInfo->glIndex != -1) {
2355 if(!This->isRecordingState) {
2356 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2359 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2360 lightInfo->glIndex = -1;
2361 } else {
2362 TRACE("Light already disabled, nothing to do\n");
2364 } else {
2365 if (lightInfo->glIndex != -1) {
2366 /* nop */
2367 TRACE("Nothing to do as light was enabled\n");
2368 } else {
2369 int i;
2370 /* Find a free gl light */
2371 for(i = 0; i < This->maxConcurrentLights; i++) {
2372 if(This->stateBlock->activeLights[i] == NULL) {
2373 This->stateBlock->activeLights[i] = lightInfo;
2374 lightInfo->glIndex = i;
2375 break;
2378 if(lightInfo->glIndex == -1) {
2379 ERR("Too many concurrently active lights\n");
2380 return WINED3DERR_INVALIDCALL;
2383 /* i == lightInfo->glIndex */
2384 if(!This->isRecordingState) {
2385 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2390 return WINED3D_OK;
2393 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2395 PLIGHTINFOEL *lightInfo = NULL;
2396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2397 struct list *e;
2398 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2399 TRACE("(%p) : for idx(%d)\n", This, Index);
2401 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2402 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2403 if(lightInfo->OriginalIndex == Index) break;
2404 lightInfo = NULL;
2407 if (lightInfo == NULL) {
2408 TRACE("Light enabled state requested but light not defined\n");
2409 return WINED3DERR_INVALIDCALL;
2411 /* true is 128 according to SetLightEnable */
2412 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2413 return WINED3D_OK;
2416 /*****
2417 * Get / Set Clip Planes
2418 *****/
2419 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2421 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2423 /* Validate Index */
2424 if (Index >= GL_LIMITS(clipplanes)) {
2425 TRACE("Application has requested clipplane this device doesn't support\n");
2426 return WINED3DERR_INVALIDCALL;
2429 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2430 This->updateStateBlock->set.clipplane[Index] = TRUE;
2432 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2433 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2434 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2435 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2436 TRACE("Application is setting old values over, nothing to do\n");
2437 return WINED3D_OK;
2440 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2441 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2442 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2443 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2445 /* Handle recording of state blocks */
2446 if (This->isRecordingState) {
2447 TRACE("Recording... not performing anything\n");
2448 return WINED3D_OK;
2451 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2453 return WINED3D_OK;
2456 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2458 TRACE("(%p) : for idx %d\n", This, Index);
2460 /* Validate Index */
2461 if (Index >= GL_LIMITS(clipplanes)) {
2462 TRACE("Application has requested clipplane this device doesn't support\n");
2463 return WINED3DERR_INVALIDCALL;
2466 pPlane[0] = This->stateBlock->clipplane[Index][0];
2467 pPlane[1] = This->stateBlock->clipplane[Index][1];
2468 pPlane[2] = This->stateBlock->clipplane[Index][2];
2469 pPlane[3] = This->stateBlock->clipplane[Index][3];
2470 return WINED3D_OK;
2473 /*****
2474 * Get / Set Clip Plane Status
2475 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2476 *****/
2477 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2479 FIXME("(%p) : stub\n", This);
2480 if (NULL == pClipStatus) {
2481 return WINED3DERR_INVALIDCALL;
2483 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2484 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2485 return WINED3D_OK;
2488 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2490 FIXME("(%p) : stub\n", This);
2491 if (NULL == pClipStatus) {
2492 return WINED3DERR_INVALIDCALL;
2494 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2495 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2496 return WINED3D_OK;
2499 /*****
2500 * Get / Set Material
2501 *****/
2502 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2505 This->updateStateBlock->changed.material = TRUE;
2506 This->updateStateBlock->set.material = TRUE;
2507 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2509 /* Handle recording of state blocks */
2510 if (This->isRecordingState) {
2511 TRACE("Recording... not performing anything\n");
2512 return WINED3D_OK;
2515 ENTER_GL();
2516 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2517 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2518 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2519 pMaterial->Ambient.b, pMaterial->Ambient.a);
2520 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2521 pMaterial->Specular.b, pMaterial->Specular.a);
2522 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2523 pMaterial->Emissive.b, pMaterial->Emissive.a);
2524 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2526 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2527 checkGLcall("glMaterialfv(GL_AMBIENT)");
2528 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2529 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2531 /* Only change material color if specular is enabled, otherwise it is set to black */
2532 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2533 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2534 checkGLcall("glMaterialfv(GL_SPECULAR");
2535 } else {
2536 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2537 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2538 checkGLcall("glMaterialfv(GL_SPECULAR");
2540 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2541 checkGLcall("glMaterialfv(GL_EMISSION)");
2542 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2543 checkGLcall("glMaterialf(GL_SHININESS");
2545 LEAVE_GL();
2546 return WINED3D_OK;
2549 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2551 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2552 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2553 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2554 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2555 pMaterial->Ambient.b, pMaterial->Ambient.a);
2556 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2557 pMaterial->Specular.b, pMaterial->Specular.a);
2558 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2559 pMaterial->Emissive.b, pMaterial->Emissive.a);
2560 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2562 return WINED3D_OK;
2565 /*****
2566 * Get / Set Indices
2567 *****/
2568 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2569 UINT BaseVertexIndex) {
2570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2571 IWineD3DIndexBuffer *oldIdxs;
2572 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2574 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2575 oldIdxs = This->updateStateBlock->pIndexData;
2577 This->updateStateBlock->changed.indices = TRUE;
2578 This->updateStateBlock->set.indices = TRUE;
2579 This->updateStateBlock->pIndexData = pIndexData;
2580 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2582 /* Handle recording of state blocks */
2583 if (This->isRecordingState) {
2584 TRACE("Recording... not performing anything\n");
2585 return WINED3D_OK;
2588 /* The base vertex index affects the stream sources, while
2589 * The index buffer is a seperate index buffer state
2591 if(BaseVertexIndex != oldBaseIndex) {
2592 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2594 if(oldIdxs != pIndexData) {
2595 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2597 return WINED3D_OK;
2600 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2603 *ppIndexData = This->stateBlock->pIndexData;
2605 /* up ref count on ppindexdata */
2606 if (*ppIndexData) {
2607 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2608 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2609 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2610 }else{
2611 TRACE("(%p) No index data set\n", This);
2613 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2615 return WINED3D_OK;
2618 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2619 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2621 TRACE("(%p)->(%d)\n", This, BaseIndex);
2623 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2624 TRACE("Application is setting the old value over, nothing to do\n");
2625 return WINED3D_OK;
2628 This->updateStateBlock->baseVertexIndex = BaseIndex;
2630 if (This->isRecordingState) {
2631 TRACE("Recording... not performing anything\n");
2632 return WINED3D_OK;
2634 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2635 return WINED3D_OK;
2638 /*****
2639 * Get / Set Viewports
2640 *****/
2641 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2644 TRACE("(%p)\n", This);
2645 This->updateStateBlock->changed.viewport = TRUE;
2646 This->updateStateBlock->set.viewport = TRUE;
2647 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2649 /* Handle recording of state blocks */
2650 if (This->isRecordingState) {
2651 TRACE("Recording... not performing anything\n");
2652 return WINED3D_OK;
2655 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2656 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2658 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2659 return WINED3D_OK;
2663 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2665 TRACE("(%p)\n", This);
2666 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2667 return WINED3D_OK;
2670 /*****
2671 * Get / Set Render States
2672 * TODO: Verify against dx9 definitions
2673 *****/
2674 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2677 DWORD oldValue = This->stateBlock->renderState[State];
2679 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2681 This->updateStateBlock->changed.renderState[State] = TRUE;
2682 This->updateStateBlock->set.renderState[State] = TRUE;
2683 This->updateStateBlock->renderState[State] = Value;
2685 /* Handle recording of state blocks */
2686 if (This->isRecordingState) {
2687 TRACE("Recording... not performing anything\n");
2688 return WINED3D_OK;
2691 /* Compared here and not before the assignment to allow proper stateblock recording */
2692 if(Value == oldValue) {
2693 TRACE("Application is setting the old value over, nothing to do\n");
2694 } else {
2695 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2698 return WINED3D_OK;
2701 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2703 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2704 *pValue = This->stateBlock->renderState[State];
2705 return WINED3D_OK;
2708 /*****
2709 * Get / Set Sampler States
2710 * TODO: Verify against dx9 definitions
2711 *****/
2713 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2715 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2718 * SetSampler is designed to allow for more than the standard up to 8 textures
2719 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2720 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2722 * http://developer.nvidia.com/object/General_FAQ.html#t6
2724 * There are two new settings for GForce
2725 * the sampler one:
2726 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2727 * and the texture one:
2728 * GL_MAX_TEXTURE_COORDS_ARB.
2729 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2730 ******************/
2732 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2733 debug_d3dsamplerstate(Type), Type, Value);
2734 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2735 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2736 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2738 /* Handle recording of state blocks */
2739 if (This->isRecordingState) {
2740 TRACE("Recording... not performing anything\n");
2741 return WINED3D_OK;
2744 if(oldValue == Value) {
2745 TRACE("Application is setting the old value over, nothing to do\n");
2746 return WINED3D_OK;
2749 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2751 return WINED3D_OK;
2754 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2756 *Value = This->stateBlock->samplerState[Sampler][Type];
2757 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2759 return WINED3D_OK;
2762 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2765 This->updateStateBlock->set.scissorRect = TRUE;
2766 This->updateStateBlock->changed.scissorRect = TRUE;
2767 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2768 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2769 return WINED3D_OK;
2771 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2773 if(This->isRecordingState) {
2774 TRACE("Recording... not performing anything\n");
2775 return WINED3D_OK;
2778 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2780 return WINED3D_OK;
2783 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2786 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2787 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2788 return WINED3D_OK;
2791 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2793 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2795 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2797 This->updateStateBlock->vertexDecl = pDecl;
2798 This->updateStateBlock->changed.vertexDecl = TRUE;
2799 This->updateStateBlock->set.vertexDecl = TRUE;
2801 if (This->isRecordingState) {
2802 TRACE("Recording... not performing anything\n");
2803 return WINED3D_OK;
2804 } else if(pDecl == oldDecl) {
2805 /* Checked after the assignment to allow proper stateblock recording */
2806 TRACE("Application is setting the old declaration over, nothing to do\n");
2807 return WINED3D_OK;
2810 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2811 return WINED3D_OK;
2814 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2817 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2819 *ppDecl = This->stateBlock->vertexDecl;
2820 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2821 return WINED3D_OK;
2824 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2826 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2828 This->updateStateBlock->vertexShader = pShader;
2829 This->updateStateBlock->changed.vertexShader = TRUE;
2830 This->updateStateBlock->set.vertexShader = TRUE;
2832 if (This->isRecordingState) {
2833 TRACE("Recording... not performing anything\n");
2834 return WINED3D_OK;
2835 } else if(oldShader == pShader) {
2836 /* Checked here to allow proper stateblock recording */
2837 TRACE("App is setting the old shader over, nothing to do\n");
2838 return WINED3D_OK;
2841 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2843 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2845 return WINED3D_OK;
2848 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2851 if (NULL == ppShader) {
2852 return WINED3DERR_INVALIDCALL;
2854 *ppShader = This->stateBlock->vertexShader;
2855 if( NULL != *ppShader)
2856 IWineD3DVertexShader_AddRef(*ppShader);
2858 TRACE("(%p) : returning %p\n", This, *ppShader);
2859 return WINED3D_OK;
2862 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2863 IWineD3DDevice *iface,
2864 UINT start,
2865 CONST BOOL *srcData,
2866 UINT count) {
2868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2869 int i, cnt = min(count, MAX_CONST_B - start);
2871 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2872 iface, srcData, start, count);
2874 if (srcData == NULL || cnt < 0)
2875 return WINED3DERR_INVALIDCALL;
2877 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2878 for (i = 0; i < cnt; i++)
2879 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2881 for (i = start; i < cnt + start; ++i) {
2882 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
2883 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
2886 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2888 return WINED3D_OK;
2891 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2892 IWineD3DDevice *iface,
2893 UINT start,
2894 BOOL *dstData,
2895 UINT count) {
2897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2898 int cnt = min(count, MAX_CONST_B - start);
2900 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2901 iface, dstData, start, count);
2903 if (dstData == NULL || cnt < 0)
2904 return WINED3DERR_INVALIDCALL;
2906 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2907 return WINED3D_OK;
2910 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2911 IWineD3DDevice *iface,
2912 UINT start,
2913 CONST int *srcData,
2914 UINT count) {
2916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2917 int i, cnt = min(count, MAX_CONST_I - start);
2919 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2920 iface, srcData, start, count);
2922 if (srcData == NULL || cnt < 0)
2923 return WINED3DERR_INVALIDCALL;
2925 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2926 for (i = 0; i < cnt; i++)
2927 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2928 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2930 for (i = start; i < cnt + start; ++i) {
2931 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
2932 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
2935 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2937 return WINED3D_OK;
2940 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2941 IWineD3DDevice *iface,
2942 UINT start,
2943 int *dstData,
2944 UINT count) {
2946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2947 int cnt = min(count, MAX_CONST_I - start);
2949 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2950 iface, dstData, start, count);
2952 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2953 return WINED3DERR_INVALIDCALL;
2955 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2956 return WINED3D_OK;
2959 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
2960 IWineD3DDevice *iface,
2961 UINT start,
2962 CONST float *srcData,
2963 UINT count) {
2965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2966 int i;
2968 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2969 iface, srcData, start, count);
2971 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
2972 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
2973 return WINED3DERR_INVALIDCALL;
2975 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
2976 if(TRACE_ON(d3d)) {
2977 for (i = 0; i < count; i++)
2978 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
2979 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2982 for (i = start; i < count + start; ++i) {
2983 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
2984 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
2985 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
2986 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
2987 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
2989 ptr->idx[ptr->count++] = i;
2990 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
2992 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
2995 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2997 return WINED3D_OK;
3000 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3001 IWineD3DDevice *iface,
3002 UINT start,
3003 float *dstData,
3004 UINT count) {
3006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3007 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3009 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3010 iface, dstData, start, count);
3012 if (dstData == NULL || cnt < 0)
3013 return WINED3DERR_INVALIDCALL;
3015 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3016 return WINED3D_OK;
3019 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3020 DWORD i;
3021 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3022 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3026 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3027 DWORD i, tex;
3028 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3029 * it is never called.
3031 * Rules are:
3032 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3033 * that would be really messy and require shader recompilation
3034 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3035 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3036 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3037 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3039 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3040 if(This->oneToOneTexUnitMap) {
3041 TRACE("Not touching 1:1 map\n");
3042 return;
3044 TRACE("Restoring 1:1 texture unit mapping\n");
3045 /* Restore a 1:1 mapping */
3046 for(i = 0; i < MAX_SAMPLERS; i++) {
3047 if(This->texUnitMap[i] != i) {
3048 This->texUnitMap[i] = i;
3049 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3050 markTextureStagesDirty(This, i);
3053 This->oneToOneTexUnitMap = TRUE;
3054 return;
3055 } else {
3056 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3057 * First, see if we can succeed at all
3059 tex = 0;
3060 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3061 if(This->stateBlock->textures[i] == NULL) tex++;
3064 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3065 FIXME("Too many bound textures to support the combiner settings\n");
3066 return;
3069 /* Now work out the mapping */
3070 tex = 0;
3071 This->oneToOneTexUnitMap = FALSE;
3072 WARN("Non 1:1 mapping UNTESTED!\n");
3073 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3074 /* Skip NULL textures */
3075 if (!This->stateBlock->textures[i]) {
3076 /* Map to -1, so the check below doesn't fail if a non-NULL
3077 * texture is set on this stage */
3078 TRACE("Mapping texture stage %d to -1\n", i);
3079 This->texUnitMap[i] = -1;
3081 continue;
3084 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3085 if(This->texUnitMap[i] != tex) {
3086 This->texUnitMap[i] = tex;
3087 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3088 markTextureStagesDirty(This, i);
3091 ++tex;
3096 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3098 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3099 This->updateStateBlock->pixelShader = pShader;
3100 This->updateStateBlock->changed.pixelShader = TRUE;
3101 This->updateStateBlock->set.pixelShader = TRUE;
3103 /* Handle recording of state blocks */
3104 if (This->isRecordingState) {
3105 TRACE("Recording... not performing anything\n");
3108 if (This->isRecordingState) {
3109 TRACE("Recording... not performing anything\n");
3110 return WINED3D_OK;
3113 if(pShader == oldShader) {
3114 TRACE("App is setting the old pixel shader over, nothing to do\n");
3115 return WINED3D_OK;
3118 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3119 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3121 /* Rebuild the texture unit mapping if nvrc's are supported */
3122 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3123 IWineD3DDeviceImpl_FindTexUnitMap(This);
3126 return WINED3D_OK;
3129 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3132 if (NULL == ppShader) {
3133 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3134 return WINED3DERR_INVALIDCALL;
3137 *ppShader = This->stateBlock->pixelShader;
3138 if (NULL != *ppShader) {
3139 IWineD3DPixelShader_AddRef(*ppShader);
3141 TRACE("(%p) : returning %p\n", This, *ppShader);
3142 return WINED3D_OK;
3145 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3146 IWineD3DDevice *iface,
3147 UINT start,
3148 CONST BOOL *srcData,
3149 UINT count) {
3151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3152 int i, cnt = min(count, MAX_CONST_B - start);
3154 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3155 iface, srcData, start, count);
3157 if (srcData == NULL || cnt < 0)
3158 return WINED3DERR_INVALIDCALL;
3160 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3161 for (i = 0; i < cnt; i++)
3162 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3164 for (i = start; i < cnt + start; ++i) {
3165 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3166 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3169 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3171 return WINED3D_OK;
3174 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3175 IWineD3DDevice *iface,
3176 UINT start,
3177 BOOL *dstData,
3178 UINT count) {
3180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3181 int cnt = min(count, MAX_CONST_B - start);
3183 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3184 iface, dstData, start, count);
3186 if (dstData == NULL || cnt < 0)
3187 return WINED3DERR_INVALIDCALL;
3189 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3190 return WINED3D_OK;
3193 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3194 IWineD3DDevice *iface,
3195 UINT start,
3196 CONST int *srcData,
3197 UINT count) {
3199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3200 int i, cnt = min(count, MAX_CONST_I - start);
3202 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3203 iface, srcData, start, count);
3205 if (srcData == NULL || cnt < 0)
3206 return WINED3DERR_INVALIDCALL;
3208 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3209 for (i = 0; i < cnt; i++)
3210 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3211 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3213 for (i = start; i < cnt + start; ++i) {
3214 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3215 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3218 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3220 return WINED3D_OK;
3223 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3224 IWineD3DDevice *iface,
3225 UINT start,
3226 int *dstData,
3227 UINT count) {
3229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3230 int cnt = min(count, MAX_CONST_I - start);
3232 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3233 iface, dstData, start, count);
3235 if (dstData == NULL || cnt < 0)
3236 return WINED3DERR_INVALIDCALL;
3238 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3239 return WINED3D_OK;
3242 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3243 IWineD3DDevice *iface,
3244 UINT start,
3245 CONST float *srcData,
3246 UINT count) {
3248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3249 int i;
3251 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3252 iface, srcData, start, count);
3254 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3255 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3256 return WINED3DERR_INVALIDCALL;
3258 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3259 if(TRACE_ON(d3d)) {
3260 for (i = 0; i < count; i++)
3261 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3262 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3265 for (i = start; i < count + start; ++i) {
3266 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3267 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3268 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3269 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3270 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3272 ptr->idx[ptr->count++] = i;
3273 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3275 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3278 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3280 return WINED3D_OK;
3283 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3284 IWineD3DDevice *iface,
3285 UINT start,
3286 float *dstData,
3287 UINT count) {
3289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3290 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3292 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3293 iface, dstData, start, count);
3295 if (dstData == NULL || cnt < 0)
3296 return WINED3DERR_INVALIDCALL;
3298 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3299 return WINED3D_OK;
3302 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3303 static HRESULT
3304 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3305 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3306 unsigned int i;
3307 DWORD DestFVF = dest->fvf;
3308 WINED3DVIEWPORT vp;
3309 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3310 BOOL doClip;
3311 int numTextures;
3313 if (SrcFVF & WINED3DFVF_NORMAL) {
3314 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3317 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3318 ERR("Source has no position mask\n");
3319 return WINED3DERR_INVALIDCALL;
3322 /* We might access VBOs from this code, so hold the lock */
3323 ENTER_GL();
3325 if (dest->resource.allocatedMemory == NULL) {
3326 /* This may happen if we do direct locking into a vbo. Unlikely,
3327 * but theoretically possible(ddraw processvertices test)
3329 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3330 if(!dest->resource.allocatedMemory) {
3331 LEAVE_GL();
3332 ERR("Out of memory\n");
3333 return E_OUTOFMEMORY;
3335 if(dest->vbo) {
3336 void *src;
3337 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3338 checkGLcall("glBindBufferARB");
3339 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3340 if(src) {
3341 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3343 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3344 checkGLcall("glUnmapBufferARB");
3348 /* Get a pointer into the destination vbo(create one if none exists) and
3349 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3351 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3352 CreateVBO(dest);
3355 if(dest->vbo) {
3356 dest_conv_addr = HeapAlloc(GetProcessHeap(), 0, dwCount * get_flexible_vertex_size(DestFVF));
3357 if(!dest_conv_addr) {
3358 ERR("Out of memory\n");
3359 /* Continue without storing converted vertices */
3361 dest_conv = dest_conv_addr;
3364 /* Should I clip?
3365 * a) WINED3DRS_CLIPPING is enabled
3366 * b) WINED3DVOP_CLIP is passed
3368 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3369 static BOOL warned = FALSE;
3371 * The clipping code is not quite correct. Some things need
3372 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3373 * so disable clipping for now.
3374 * (The graphics in Half-Life are broken, and my processvertices
3375 * test crashes with IDirect3DDevice3)
3376 doClip = TRUE;
3378 doClip = FALSE;
3379 if(!warned) {
3380 warned = TRUE;
3381 FIXME("Clipping is broken and disabled for now\n");
3383 } else doClip = FALSE;
3384 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3386 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3387 WINED3DTS_VIEW,
3388 &view_mat);
3389 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3390 WINED3DTS_PROJECTION,
3391 &proj_mat);
3392 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3393 WINED3DTS_WORLDMATRIX(0),
3394 &world_mat);
3396 TRACE("View mat:\n");
3397 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);
3398 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);
3399 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);
3400 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);
3402 TRACE("Proj mat:\n");
3403 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);
3404 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);
3405 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);
3406 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);
3408 TRACE("World mat:\n");
3409 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);
3410 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);
3411 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);
3412 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);
3414 /* Get the viewport */
3415 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3416 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3417 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3419 multiply_matrix(&mat,&view_mat,&world_mat);
3420 multiply_matrix(&mat,&proj_mat,&mat);
3422 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3424 for (i = 0; i < dwCount; i+= 1) {
3425 unsigned int tex_index;
3427 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3428 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3429 /* The position first */
3430 float *p =
3431 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3432 float x, y, z, rhw;
3433 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3435 /* Multiplication with world, view and projection matrix */
3436 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);
3437 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);
3438 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);
3439 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);
3441 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3443 /* WARNING: The following things are taken from d3d7 and were not yet checked
3444 * against d3d8 or d3d9!
3447 /* Clipping conditions: From
3448 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3450 * A vertex is clipped if it does not match the following requirements
3451 * -rhw < x <= rhw
3452 * -rhw < y <= rhw
3453 * 0 < z <= rhw
3454 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3456 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3457 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3461 if( !doClip ||
3462 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3463 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3464 ( rhw > eps ) ) ) {
3466 /* "Normal" viewport transformation (not clipped)
3467 * 1) The values are divided by rhw
3468 * 2) The y axis is negative, so multiply it with -1
3469 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3470 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3471 * 4) Multiply x with Width/2 and add Width/2
3472 * 5) The same for the height
3473 * 6) Add the viewpoint X and Y to the 2D coordinates and
3474 * The minimum Z value to z
3475 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3477 * Well, basically it's simply a linear transformation into viewport
3478 * coordinates
3481 x /= rhw;
3482 y /= rhw;
3483 z /= rhw;
3485 y *= -1;
3487 x *= vp.Width / 2;
3488 y *= vp.Height / 2;
3489 z *= vp.MaxZ - vp.MinZ;
3491 x += vp.Width / 2 + vp.X;
3492 y += vp.Height / 2 + vp.Y;
3493 z += vp.MinZ;
3495 rhw = 1 / rhw;
3496 } else {
3497 /* That vertex got clipped
3498 * Contrary to OpenGL it is not dropped completely, it just
3499 * undergoes a different calculation.
3501 TRACE("Vertex got clipped\n");
3502 x += rhw;
3503 y += rhw;
3505 x /= 2;
3506 y /= 2;
3508 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3509 * outside of the main vertex buffer memory. That needs some more
3510 * investigation...
3514 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3517 ( (float *) dest_ptr)[0] = x;
3518 ( (float *) dest_ptr)[1] = y;
3519 ( (float *) dest_ptr)[2] = z;
3520 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3522 dest_ptr += 3 * sizeof(float);
3524 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3525 dest_ptr += sizeof(float);
3528 if(dest_conv) {
3529 float w = 1 / rhw;
3530 ( (float *) dest_conv)[0] = x * w;
3531 ( (float *) dest_conv)[1] = y * w;
3532 ( (float *) dest_conv)[2] = z * w;
3533 ( (float *) dest_conv)[3] = w;
3535 dest_conv += 3 * sizeof(float);
3537 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3538 dest_conv += sizeof(float);
3542 if (DestFVF & WINED3DFVF_PSIZE) {
3543 dest_ptr += sizeof(DWORD);
3544 if(dest_conv) dest_conv += sizeof(DWORD);
3546 if (DestFVF & WINED3DFVF_NORMAL) {
3547 float *normal =
3548 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3549 /* AFAIK this should go into the lighting information */
3550 FIXME("Didn't expect the destination to have a normal\n");
3551 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3552 if(dest_conv) {
3553 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3557 if (DestFVF & WINED3DFVF_DIFFUSE) {
3558 DWORD *color_d =
3559 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3560 if(!color_d) {
3561 static BOOL warned = FALSE;
3563 if(!warned) {
3564 ERR("No diffuse color in source, but destination has one\n");
3565 warned = TRUE;
3568 *( (DWORD *) dest_ptr) = 0xffffffff;
3569 dest_ptr += sizeof(DWORD);
3571 if(dest_conv) {
3572 *( (DWORD *) dest_conv) = 0xffffffff;
3573 dest_conv += sizeof(DWORD);
3576 else {
3577 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3578 if(dest_conv) {
3579 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3580 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3581 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3582 dest_conv += sizeof(DWORD);
3587 if (DestFVF & WINED3DFVF_SPECULAR) {
3588 /* What's the color value in the feedback buffer? */
3589 DWORD *color_s =
3590 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3591 if(!color_s) {
3592 static BOOL warned = FALSE;
3594 if(!warned) {
3595 ERR("No specular color in source, but destination has one\n");
3596 warned = TRUE;
3599 *( (DWORD *) dest_ptr) = 0xFF000000;
3600 dest_ptr += sizeof(DWORD);
3602 if(dest_conv) {
3603 *( (DWORD *) dest_conv) = 0xFF000000;
3604 dest_conv += sizeof(DWORD);
3607 else {
3608 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3609 if(dest_conv) {
3610 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3611 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3612 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3613 dest_conv += sizeof(DWORD);
3618 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3619 float *tex_coord =
3620 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3621 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3622 if(!tex_coord) {
3623 ERR("No source texture, but destination requests one\n");
3624 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3625 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3627 else {
3628 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3629 if(dest_conv) {
3630 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3636 if(dest_conv) {
3637 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3638 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3639 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3640 dwCount * get_flexible_vertex_size(DestFVF),
3641 dest_conv_addr));
3642 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3643 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3646 LEAVE_GL();
3648 return WINED3D_OK;
3650 #undef copy_and_next
3652 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
3653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3654 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
3655 WineDirect3DVertexStridedData strided;
3656 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3658 if (!SrcImpl) {
3659 WARN("NULL source vertex buffer\n");
3660 return WINED3DERR_INVALIDCALL;
3662 /* We don't need the source vbo because this buffer is only used as
3663 * a source for ProcessVertices. Avoid wasting resources by converting the
3664 * buffer and loading the VBO
3666 if(SrcImpl->vbo) {
3667 TRACE("Releasing the source vbo, it won't be needed\n");
3669 if(!SrcImpl->resource.allocatedMemory) {
3670 /* Rescue the data from the buffer */
3671 void *src;
3672 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
3673 if(!SrcImpl->resource.allocatedMemory) {
3674 ERR("Out of memory\n");
3675 return E_OUTOFMEMORY;
3678 ENTER_GL();
3679 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
3680 checkGLcall("glBindBufferARB");
3682 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3683 if(src) {
3684 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
3687 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3688 checkGLcall("glUnmapBufferARB");
3689 } else {
3690 ENTER_GL();
3693 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
3694 checkGLcall("glBindBufferARB");
3695 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
3696 checkGLcall("glDeleteBuffersARB");
3697 LEAVE_GL();
3699 SrcImpl->vbo = 0;
3702 memset(&strided, 0, sizeof(strided));
3703 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0, 0);
3705 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3708 /*****
3709 * Get / Set Texture Stage States
3710 * TODO: Verify against dx9 definitions
3711 *****/
3712 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3714 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3716 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3718 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3720 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3721 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3722 This->updateStateBlock->textureState[Stage][Type] = Value;
3724 if (This->isRecordingState) {
3725 TRACE("Recording... not performing anything\n");
3726 return WINED3D_OK;
3729 /* Checked after the assignments to allow proper stateblock recording */
3730 if(oldValue == Value) {
3731 TRACE("App is setting the old value over, nothing to do\n");
3732 return WINED3D_OK;
3735 if(Stage > This->stateBlock->lowest_disabled_stage &&
3736 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3737 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3738 * Changes in other states are important on disabled stages too
3740 return WINED3D_OK;
3743 if(Type == WINED3DTSS_COLOROP) {
3744 int i;
3746 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3747 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3748 * they have to be disabled
3750 * The current stage is dirtified below.
3752 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3753 TRACE("Additionally dirtifying stage %d\n", i);
3754 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3756 This->stateBlock->lowest_disabled_stage = Stage;
3757 TRACE("New lowest disabled: %d\n", Stage);
3758 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3759 /* Previously disabled stage enabled. Stages above it may need enabling
3760 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3761 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3763 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3766 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3767 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3768 break;
3770 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3771 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3773 This->stateBlock->lowest_disabled_stage = i;
3774 TRACE("New lowest disabled: %d\n", i);
3776 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3777 /* TODO: Built a stage -> texture unit mapping for register combiners */
3781 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3783 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3784 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3785 * will call FindTexUnitMap too.
3787 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3788 IWineD3DDeviceImpl_FindTexUnitMap(This);
3790 return WINED3D_OK;
3793 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3795 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3796 *pValue = This->updateStateBlock->textureState[Stage][Type];
3797 return WINED3D_OK;
3800 /*****
3801 * Get / Set Texture
3802 *****/
3803 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
3805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3806 IWineD3DBaseTexture *oldTexture;
3808 oldTexture = This->updateStateBlock->textures[Stage];
3809 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
3811 #if 0 /* TODO: check so vertex textures */
3812 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
3813 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
3814 return WINED3D_OK;
3816 #endif
3818 if(pTexture != NULL) {
3819 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
3821 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
3822 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
3823 return WINED3DERR_INVALIDCALL;
3825 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
3828 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
3829 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
3831 This->updateStateBlock->set.textures[Stage] = TRUE;
3832 This->updateStateBlock->changed.textures[Stage] = TRUE;
3833 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
3834 This->updateStateBlock->textures[Stage] = pTexture;
3836 /* Handle recording of state blocks */
3837 if (This->isRecordingState) {
3838 TRACE("Recording... not performing anything\n");
3839 return WINED3D_OK;
3842 if(oldTexture == pTexture) {
3843 TRACE("App is setting the same texture again, nothing to do\n");
3844 return WINED3D_OK;
3847 /** NOTE: MSDN says that setTexture increases the reference count,
3848 * and the the application nust set the texture back to null (or have a leaky application),
3849 * This means we should pass the refcount up to the parent
3850 *******************************/
3851 if (NULL != This->updateStateBlock->textures[Stage]) {
3852 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
3853 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
3855 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
3856 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
3857 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
3858 * so the COLOROP and ALPHAOP have to be dirtified.
3860 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3861 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3863 if(bindCount == 1) {
3864 new->baseTexture.sampler = Stage;
3866 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
3870 if (NULL != oldTexture) {
3871 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
3872 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
3874 IWineD3DBaseTexture_Release(oldTexture);
3875 if(pTexture == NULL && Stage < MAX_TEXTURES) {
3876 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3877 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3880 if(bindCount && old->baseTexture.sampler == Stage) {
3881 int i;
3882 /* Have to do a search for the other sampler(s) where the texture is bound to
3883 * Shouldn't happen as long as apps bind a texture only to one stage
3885 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
3886 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
3887 if(This->updateStateBlock->textures[i] == oldTexture) {
3888 old->baseTexture.sampler = i;
3889 break;
3895 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
3897 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
3898 * pixel shader is used
3900 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3901 IWineD3DDeviceImpl_FindTexUnitMap(This);
3904 return WINED3D_OK;
3907 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3909 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
3911 *ppTexture=This->stateBlock->textures[Stage];
3912 if (*ppTexture)
3913 IWineD3DBaseTexture_AddRef(*ppTexture);
3915 return WINED3D_OK;
3918 /*****
3919 * Get Back Buffer
3920 *****/
3921 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
3922 IWineD3DSurface **ppBackBuffer) {
3923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3924 IWineD3DSwapChain *swapChain;
3925 HRESULT hr;
3927 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
3929 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
3930 if (hr == WINED3D_OK) {
3931 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
3932 IWineD3DSwapChain_Release(swapChain);
3933 } else {
3934 *ppBackBuffer = NULL;
3936 return hr;
3939 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
3940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3941 WARN("(%p) : stub, calling idirect3d for now\n", This);
3942 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
3945 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
3946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3947 IWineD3DSwapChain *swapChain;
3948 HRESULT hr;
3950 if(iSwapChain > 0) {
3951 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
3952 if (hr == WINED3D_OK) {
3953 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
3954 IWineD3DSwapChain_Release(swapChain);
3955 } else {
3956 FIXME("(%p) Error getting display mode\n", This);
3958 } else {
3959 /* Don't read the real display mode,
3960 but return the stored mode instead. X11 can't change the color
3961 depth, and some apps are pretty angry if they SetDisplayMode from
3962 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
3964 Also don't relay to the swapchain because with ddraw it's possible
3965 that there isn't a swapchain at all */
3966 pMode->Width = This->ddraw_width;
3967 pMode->Height = This->ddraw_height;
3968 pMode->Format = This->ddraw_format;
3969 pMode->RefreshRate = 0;
3970 hr = WINED3D_OK;
3973 return hr;
3976 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
3977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3978 TRACE("(%p)->(%p)\n", This, hWnd);
3980 if(This->ddraw_fullscreen) {
3981 if(This->ddraw_window && This->ddraw_window != hWnd) {
3982 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
3984 if(hWnd && This->ddraw_window != hWnd) {
3985 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
3989 This->ddraw_window = hWnd;
3990 return WINED3D_OK;
3993 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
3994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3995 TRACE("(%p)->(%p)\n", This, hWnd);
3997 *hWnd = This->ddraw_window;
3998 return WINED3D_OK;
4001 /*****
4002 * Stateblock related functions
4003 *****/
4005 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4007 IWineD3DStateBlockImpl *object;
4008 HRESULT temp_result;
4009 int i;
4011 TRACE("(%p)\n", This);
4013 if (This->isRecordingState) {
4014 return WINED3DERR_INVALIDCALL;
4017 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4018 if (NULL == object ) {
4019 FIXME("(%p)Error allocating memory for stateblock\n", This);
4020 return E_OUTOFMEMORY;
4022 TRACE("(%p) created object %p\n", This, object);
4023 object->wineD3DDevice= This;
4024 /** FIXME: object->parent = parent; **/
4025 object->parent = NULL;
4026 object->blockType = WINED3DSBT_ALL;
4027 object->ref = 1;
4028 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4030 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4031 list_init(&object->lightMap[i]);
4034 temp_result = allocate_shader_constants(object);
4035 if (WINED3D_OK != temp_result)
4036 return temp_result;
4038 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4039 This->updateStateBlock = object;
4040 This->isRecordingState = TRUE;
4042 TRACE("(%p) recording stateblock %p\n",This , object);
4043 return WINED3D_OK;
4046 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4049 if (!This->isRecordingState) {
4050 FIXME("(%p) not recording! returning error\n", This);
4051 *ppStateBlock = NULL;
4052 return WINED3DERR_INVALIDCALL;
4055 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4056 This->isRecordingState = FALSE;
4057 This->updateStateBlock = This->stateBlock;
4058 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4059 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4060 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4061 return WINED3D_OK;
4064 /*****
4065 * Scene related functions
4066 *****/
4067 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4068 /* At the moment we have no need for any functionality at the beginning
4069 of a scene */
4070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4071 TRACE("(%p)\n", This);
4073 if(This->inScene) {
4074 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4075 return WINED3DERR_INVALIDCALL;
4077 This->inScene = TRUE;
4078 return WINED3D_OK;
4081 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4083 TRACE("(%p)\n", This);
4085 if(!This->inScene) {
4086 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4087 return WINED3DERR_INVALIDCALL;
4090 ENTER_GL();
4091 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4092 glFlush();
4093 checkGLcall("glFlush");
4094 LEAVE_GL();
4096 This->inScene = FALSE;
4097 return WINED3D_OK;
4100 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4101 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4102 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4104 IWineD3DSwapChain *swapChain = NULL;
4105 int i;
4106 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4108 TRACE("(%p) Presenting the frame\n", This);
4110 for(i = 0 ; i < swapchains ; i ++) {
4112 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4113 TRACE("presentinng chain %d, %p\n", i, swapChain);
4114 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4115 IWineD3DSwapChain_Release(swapChain);
4118 return WINED3D_OK;
4121 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4122 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4125 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4126 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4127 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4128 GLbitfield glMask = 0;
4129 unsigned int i;
4130 CONST WINED3DRECT* curRect;
4132 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4133 Count, pRects, Flags, Z, Stencil);
4135 ENTER_GL();
4137 if(pRects) {
4138 glEnable(GL_SCISSOR_TEST);
4139 checkGLcall("glEnable GL_SCISSOR_TEST");
4140 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4141 } else {
4142 glDisable(GL_SCISSOR_TEST);
4143 checkGLcall("glEnable GL_SCISSOR_TEST");
4145 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4147 if (Count > 0 && pRects) {
4148 curRect = pRects;
4149 } else {
4150 curRect = NULL;
4153 /* Only set the values up once, as they are not changing */
4154 if (Flags & WINED3DCLEAR_STENCIL) {
4155 glClearStencil(Stencil);
4156 checkGLcall("glClearStencil");
4157 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4158 glStencilMask(0xFFFFFFFF);
4161 if (Flags & WINED3DCLEAR_ZBUFFER) {
4162 glDepthMask(GL_TRUE);
4163 glClearDepth(Z);
4164 checkGLcall("glClearDepth");
4165 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4166 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4169 if (Flags & WINED3DCLEAR_TARGET) {
4170 TRACE("Clearing screen with glClear to color %x\n", Color);
4171 glClearColor(D3DCOLOR_R(Color),
4172 D3DCOLOR_G(Color),
4173 D3DCOLOR_B(Color),
4174 D3DCOLOR_A(Color));
4175 checkGLcall("glClearColor");
4177 /* Clear ALL colors! */
4178 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4179 glMask = glMask | GL_COLOR_BUFFER_BIT;
4182 if (!curRect) {
4183 glClear(glMask);
4184 checkGLcall("glClear");
4185 } else {
4186 /* Now process each rect in turn */
4187 for (i = 0; i < Count; i++) {
4188 /* Note gl uses lower left, width/height */
4189 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4190 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4191 curRect[i].x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect[i].y2),
4192 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4194 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4195 * The rectangle is not cleared, no error is returned, but further rectanlges are
4196 * still cleared if they are valid
4198 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4199 TRACE("Rectangle with negative dimensions, ignoring\n");
4200 continue;
4203 glScissor(curRect[i].x1, ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect[i].y2,
4204 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4205 checkGLcall("glScissor");
4207 glClear(glMask);
4208 checkGLcall("glClear");
4212 /* Restore the old values (why..?) */
4213 if (Flags & WINED3DCLEAR_STENCIL) {
4214 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4216 if (Flags & WINED3DCLEAR_TARGET) {
4217 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4218 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4219 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4220 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4221 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4224 LEAVE_GL();
4226 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4227 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4229 ((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_GLDIRTY;
4230 return WINED3D_OK;
4233 /*****
4234 * Drawing functions
4235 *****/
4236 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4237 UINT PrimitiveCount) {
4239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4240 This->stateBlock->streamIsUP = FALSE;
4242 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4243 debug_d3dprimitivetype(PrimitiveType),
4244 StartVertex, PrimitiveCount);
4246 if(This->stateBlock->loadBaseVertexIndex != 0) {
4247 This->stateBlock->loadBaseVertexIndex = 0;
4248 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4250 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4251 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4252 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4253 return WINED3D_OK;
4256 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4257 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4258 WINED3DPRIMITIVETYPE PrimitiveType,
4259 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4262 UINT idxStride = 2;
4263 IWineD3DIndexBuffer *pIB;
4264 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4265 GLuint vbo;
4267 pIB = This->stateBlock->pIndexData;
4268 This->stateBlock->streamIsUP = FALSE;
4269 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4271 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4272 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4273 minIndex, NumVertices, startIndex, primCount);
4275 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4276 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4277 idxStride = 2;
4278 } else {
4279 idxStride = 4;
4282 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4283 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4284 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4287 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4288 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4290 return WINED3D_OK;
4293 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4294 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4295 UINT VertexStreamZeroStride) {
4296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4298 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4299 debug_d3dprimitivetype(PrimitiveType),
4300 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4302 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4303 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4304 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4305 This->stateBlock->streamIsUP = TRUE;
4306 This->stateBlock->loadBaseVertexIndex = 0;
4308 /* TODO: Only mark dirty if drawing from a different UP address */
4309 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4311 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4312 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4314 /* MSDN specifies stream zero settings must be set to NULL */
4315 This->stateBlock->streamStride[0] = 0;
4316 This->stateBlock->streamSource[0] = NULL;
4318 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4319 * the new stream sources or use UP drawing again
4321 return WINED3D_OK;
4324 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4325 UINT MinVertexIndex, UINT NumVertices,
4326 UINT PrimitiveCount, CONST void* pIndexData,
4327 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4328 UINT VertexStreamZeroStride) {
4329 int idxStride;
4330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4332 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4333 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4334 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4335 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4337 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4338 idxStride = 2;
4339 } else {
4340 idxStride = 4;
4343 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4344 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4345 This->stateBlock->streamIsUP = TRUE;
4346 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4348 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4349 This->stateBlock->baseVertexIndex = 0;
4350 This->stateBlock->loadBaseVertexIndex = 0;
4351 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4352 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4353 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4355 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4357 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4358 This->stateBlock->streamSource[0] = NULL;
4359 This->stateBlock->streamStride[0] = 0;
4360 This->stateBlock->pIndexData = NULL;
4361 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4362 * SetStreamSource to specify a vertex buffer
4365 return WINED3D_OK;
4368 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4371 /* Mark the state dirty until we have nicer tracking
4372 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4373 * that value.
4375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4376 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4377 This->stateBlock->baseVertexIndex = 0;
4378 This->up_strided = DrawPrimStrideData;
4379 This->stateBlock->streamIsUP = TRUE;
4380 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4381 This->up_strided = NULL;
4382 return WINED3D_OK;
4384 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4385 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4387 HRESULT hr = WINED3D_OK;
4388 WINED3DRESOURCETYPE sourceType;
4389 WINED3DRESOURCETYPE destinationType;
4390 int i ,levels;
4392 /* TODO: think about moving the code into IWineD3DBaseTexture */
4394 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4396 /* verify that the source and destination textures aren't NULL */
4397 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4398 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4399 This, pSourceTexture, pDestinationTexture);
4400 hr = WINED3DERR_INVALIDCALL;
4403 if (pSourceTexture == pDestinationTexture) {
4404 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4405 This, pSourceTexture, pDestinationTexture);
4406 hr = WINED3DERR_INVALIDCALL;
4408 /* Verify that the source and destination textures are the same type */
4409 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4410 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4412 if (sourceType != destinationType) {
4413 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4414 This);
4415 hr = WINED3DERR_INVALIDCALL;
4418 /* check that both textures have the identical numbers of levels */
4419 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4420 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4421 hr = WINED3DERR_INVALIDCALL;
4424 if (WINED3D_OK == hr) {
4426 /* Make sure that the destination texture is loaded */
4427 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4429 /* Update every surface level of the texture */
4430 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4432 switch (sourceType) {
4433 case WINED3DRTYPE_TEXTURE:
4435 IWineD3DSurface *srcSurface;
4436 IWineD3DSurface *destSurface;
4438 for (i = 0 ; i < levels ; ++i) {
4439 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4440 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4441 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4442 IWineD3DSurface_Release(srcSurface);
4443 IWineD3DSurface_Release(destSurface);
4444 if (WINED3D_OK != hr) {
4445 WARN("(%p) : Call to update surface failed\n", This);
4446 return hr;
4450 break;
4451 case WINED3DRTYPE_CUBETEXTURE:
4453 IWineD3DSurface *srcSurface;
4454 IWineD3DSurface *destSurface;
4455 WINED3DCUBEMAP_FACES faceType;
4457 for (i = 0 ; i < levels ; ++i) {
4458 /* Update each cube face */
4459 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4460 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4461 if (WINED3D_OK != hr) {
4462 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4463 } else {
4464 TRACE("Got srcSurface %p\n", srcSurface);
4466 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4467 if (WINED3D_OK != hr) {
4468 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4469 } else {
4470 TRACE("Got desrSurface %p\n", destSurface);
4472 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4473 IWineD3DSurface_Release(srcSurface);
4474 IWineD3DSurface_Release(destSurface);
4475 if (WINED3D_OK != hr) {
4476 WARN("(%p) : Call to update surface failed\n", This);
4477 return hr;
4482 break;
4483 #if 0 /* TODO: Add support for volume textures */
4484 case WINED3DRTYPE_VOLUMETEXTURE:
4486 IWineD3DVolume srcVolume = NULL;
4487 IWineD3DSurface destVolume = NULL;
4489 for (i = 0 ; i < levels ; ++i) {
4490 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4491 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4492 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4493 IWineD3DVolume_Release(srcSurface);
4494 IWineD3DVolume_Release(destSurface);
4495 if (WINED3D_OK != hr) {
4496 WARN("(%p) : Call to update volume failed\n", This);
4497 return hr;
4501 break;
4502 #endif
4503 default:
4504 FIXME("(%p) : Unsupported source and destination type\n", This);
4505 hr = WINED3DERR_INVALIDCALL;
4509 return hr;
4512 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4513 IWineD3DSwapChain *swapChain;
4514 HRESULT hr;
4515 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4516 if(hr == WINED3D_OK) {
4517 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4518 IWineD3DSwapChain_Release(swapChain);
4520 return hr;
4523 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4525 /* return a sensible default */
4526 *pNumPasses = 1;
4527 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4528 FIXME("(%p) : stub\n", This);
4529 return WINED3D_OK;
4532 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4534 int j;
4535 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4536 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4537 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4538 return WINED3DERR_INVALIDCALL;
4540 for (j = 0; j < 256; ++j) {
4541 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4542 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4543 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4544 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4546 TRACE("(%p) : returning\n", This);
4547 return WINED3D_OK;
4550 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4552 int j;
4553 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4554 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4555 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4556 return WINED3DERR_INVALIDCALL;
4558 for (j = 0; j < 256; ++j) {
4559 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4560 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4561 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4562 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4564 TRACE("(%p) : returning\n", This);
4565 return WINED3D_OK;
4568 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4570 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4571 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4572 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4573 return WINED3DERR_INVALIDCALL;
4575 /*TODO: stateblocks */
4576 This->currentPalette = PaletteNumber;
4577 TRACE("(%p) : returning\n", This);
4578 return WINED3D_OK;
4581 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4583 if (PaletteNumber == NULL) {
4584 WARN("(%p) : returning Invalid Call\n", This);
4585 return WINED3DERR_INVALIDCALL;
4587 /*TODO: stateblocks */
4588 *PaletteNumber = This->currentPalette;
4589 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4590 return WINED3D_OK;
4593 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4595 static BOOL showFixmes = TRUE;
4596 if (showFixmes) {
4597 FIXME("(%p) : stub\n", This);
4598 showFixmes = FALSE;
4601 This->softwareVertexProcessing = bSoftware;
4602 return WINED3D_OK;
4606 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4608 static BOOL showFixmes = TRUE;
4609 if (showFixmes) {
4610 FIXME("(%p) : stub\n", This);
4611 showFixmes = FALSE;
4613 return This->softwareVertexProcessing;
4617 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4619 IWineD3DSwapChain *swapChain;
4620 HRESULT hr;
4622 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4624 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4625 if(hr == WINED3D_OK){
4626 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4627 IWineD3DSwapChain_Release(swapChain);
4628 }else{
4629 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4631 return hr;
4635 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4637 static BOOL showfixmes = TRUE;
4638 if(nSegments != 0.0f) {
4639 if( showfixmes) {
4640 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4641 showfixmes = FALSE;
4644 return WINED3D_OK;
4647 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4649 static BOOL showfixmes = TRUE;
4650 if( showfixmes) {
4651 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4652 showfixmes = FALSE;
4654 return 0.0f;
4657 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4659 /** TODO: remove casts to IWineD3DSurfaceImpl
4660 * NOTE: move code to surface to accomplish this
4661 ****************************************/
4662 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4663 int srcWidth, srcHeight;
4664 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4665 WINED3DFORMAT destFormat, srcFormat;
4666 UINT destSize;
4667 int srcLeft, destLeft, destTop;
4668 WINED3DPOOL srcPool, destPool;
4669 int offset = 0;
4670 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4671 glDescriptor *glDescription = NULL;
4673 WINED3DSURFACE_DESC winedesc;
4675 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4676 memset(&winedesc, 0, sizeof(winedesc));
4677 winedesc.Width = &srcSurfaceWidth;
4678 winedesc.Height = &srcSurfaceHeight;
4679 winedesc.Pool = &srcPool;
4680 winedesc.Format = &srcFormat;
4682 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4684 winedesc.Width = &destSurfaceWidth;
4685 winedesc.Height = &destSurfaceHeight;
4686 winedesc.Pool = &destPool;
4687 winedesc.Format = &destFormat;
4688 winedesc.Size = &destSize;
4690 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4692 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4693 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4694 return WINED3DERR_INVALIDCALL;
4697 if (destFormat == WINED3DFMT_UNKNOWN) {
4698 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4699 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4701 /* Get the update surface description */
4702 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4705 ENTER_GL();
4706 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
4707 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4708 checkGLcall("glActiveTextureARB");
4711 /* Make sure the surface is loaded and up to date */
4712 IWineD3DSurface_PreLoad(pDestinationSurface);
4714 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4716 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4717 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4718 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
4719 srcLeft = pSourceRect ? pSourceRect->left : 0;
4720 destLeft = pDestPoint ? pDestPoint->x : 0;
4721 destTop = pDestPoint ? pDestPoint->y : 0;
4724 /* This function doesn't support compressed textures
4725 the pitch is just bytesPerPixel * width */
4726 if(srcWidth != srcSurfaceWidth || srcLeft ){
4727 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
4728 offset += srcLeft * pSrcSurface->bytesPerPixel;
4729 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4731 /* TODO DXT formats */
4733 if(pSourceRect != NULL && pSourceRect->top != 0){
4734 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
4736 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4737 ,This
4738 ,glDescription->level
4739 ,destLeft
4740 ,destTop
4741 ,srcWidth
4742 ,srcHeight
4743 ,glDescription->glFormat
4744 ,glDescription->glType
4745 ,IWineD3DSurface_GetData(pSourceSurface)
4748 /* Sanity check */
4749 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
4751 /* need to lock the surface to get the data */
4752 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
4755 /* TODO: Cube and volume support */
4756 if(rowoffset != 0){
4757 /* not a whole row so we have to do it a line at a time */
4758 int j;
4760 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
4761 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
4763 for(j = destTop ; j < (srcHeight + destTop) ; j++){
4765 glTexSubImage2D(glDescription->target
4766 ,glDescription->level
4767 ,destLeft
4769 ,srcWidth
4771 ,glDescription->glFormat
4772 ,glDescription->glType
4773 ,data /* could be quicker using */
4775 data += rowoffset;
4778 } else { /* Full width, so just write out the whole texture */
4780 if (WINED3DFMT_DXT1 == destFormat ||
4781 WINED3DFMT_DXT2 == destFormat ||
4782 WINED3DFMT_DXT3 == destFormat ||
4783 WINED3DFMT_DXT4 == destFormat ||
4784 WINED3DFMT_DXT5 == destFormat) {
4785 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
4786 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
4787 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
4788 FIXME("Updating part of a compressed texture is not supported at the moment\n");
4789 } if (destFormat != srcFormat) {
4790 FIXME("Updating mixed format compressed texture is not curretly support\n");
4791 } else {
4792 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
4793 glDescription->level,
4794 glDescription->glFormatInternal,
4795 srcWidth,
4796 srcHeight,
4798 destSize,
4799 IWineD3DSurface_GetData(pSourceSurface));
4801 } else {
4802 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
4806 } else {
4807 glTexSubImage2D(glDescription->target
4808 ,glDescription->level
4809 ,destLeft
4810 ,destTop
4811 ,srcWidth
4812 ,srcHeight
4813 ,glDescription->glFormat
4814 ,glDescription->glType
4815 ,IWineD3DSurface_GetData(pSourceSurface)
4819 checkGLcall("glTexSubImage2D");
4821 LEAVE_GL();
4823 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
4824 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
4826 return WINED3D_OK;
4829 /* Implementation details at http://developer.nvidia.com/attach/6494
4831 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
4832 hmm.. no longer supported use
4833 OpenGL evaluators or tessellate surfaces within your application.
4836 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
4837 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
4838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4839 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
4840 FIXME("(%p) : Stub\n", This);
4841 return WINED3D_OK;
4845 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
4846 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
4847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4848 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
4849 FIXME("(%p) : Stub\n", This);
4850 return WINED3D_OK;
4853 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
4854 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4855 TRACE("(%p) Handle(%d)\n", This, Handle);
4856 FIXME("(%p) : Stub\n", This);
4857 return WINED3D_OK;
4860 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
4861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4862 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
4863 DDBLTFX BltFx;
4864 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
4866 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
4867 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
4868 return WINED3DERR_INVALIDCALL;
4871 /* Just forward this to the DirectDraw blitting engine */
4872 memset(&BltFx, 0, sizeof(BltFx));
4873 BltFx.dwSize = sizeof(BltFx);
4874 BltFx.u5.dwFillColor = color;
4875 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
4878 /* rendertarget and deptth stencil functions */
4879 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
4880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4882 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
4883 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
4884 return WINED3DERR_INVALIDCALL;
4887 *ppRenderTarget = This->render_targets[RenderTargetIndex];
4888 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
4889 /* Note inc ref on returned surface */
4890 if(*ppRenderTarget != NULL)
4891 IWineD3DSurface_AddRef(*ppRenderTarget);
4892 return WINED3D_OK;
4895 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
4896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4897 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
4898 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
4899 IWineD3DSwapChainImpl *Swapchain;
4900 HRESULT hr;
4902 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
4904 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
4905 if(hr != WINED3D_OK) {
4906 ERR("Can't get the swapchain\n");
4907 return hr;
4910 /* Make sure to release the swapchain */
4911 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
4913 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
4914 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4915 return WINED3DERR_INVALIDCALL;
4917 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
4918 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4919 return WINED3DERR_INVALIDCALL;
4922 if(Swapchain->frontBuffer != Front) {
4923 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
4925 if(Swapchain->frontBuffer)
4926 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
4927 Swapchain->frontBuffer = Front;
4929 if(Swapchain->frontBuffer) {
4930 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
4934 if(Back && !Swapchain->backBuffer) {
4935 /* We need memory for the back buffer array - only one back buffer this way */
4936 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
4937 if(!Swapchain->backBuffer) {
4938 ERR("Out of memory\n");
4939 return E_OUTOFMEMORY;
4943 if(Swapchain->backBuffer[0] != Back) {
4944 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
4945 ENTER_GL();
4946 if(!Swapchain->backBuffer[0]) {
4947 /* GL was told to draw to the front buffer at creation,
4948 * undo that
4950 glDrawBuffer(GL_BACK);
4951 checkGLcall("glDrawBuffer(GL_BACK)");
4952 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
4953 Swapchain->presentParms.BackBufferCount = 1;
4954 } else if (!Back) {
4955 /* That makes problems - disable for now */
4956 /* glDrawBuffer(GL_FRONT); */
4957 checkGLcall("glDrawBuffer(GL_FRONT)");
4958 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
4959 Swapchain->presentParms.BackBufferCount = 0;
4961 LEAVE_GL();
4963 if(Swapchain->backBuffer[0])
4964 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
4965 Swapchain->backBuffer[0] = Back;
4967 if(Swapchain->backBuffer[0]) {
4968 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
4969 } else {
4970 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
4975 return WINED3D_OK;
4978 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
4979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4980 *ppZStencilSurface = This->depthStencilBuffer;
4981 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
4983 if(*ppZStencilSurface != NULL) {
4984 /* Note inc ref on returned surface */
4985 IWineD3DSurface_AddRef(*ppZStencilSurface);
4987 return WINED3D_OK;
4990 static void bind_fbo(IWineD3DDevice *iface) {
4991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4993 if (!This->fbo) {
4994 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
4995 checkGLcall("glGenFramebuffersEXT()");
4997 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
4998 checkGLcall("glBindFramebuffer()");
5001 /* TODO: Handle stencil attachments */
5002 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5004 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5006 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5008 bind_fbo(iface);
5010 if (depth_stencil_impl) {
5011 GLenum texttarget, target;
5012 GLint old_binding = 0;
5014 IWineD3DSurface_PreLoad(depth_stencil);
5015 texttarget = depth_stencil_impl->glDescription.target;
5016 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5018 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5019 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5020 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5021 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5022 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5023 glBindTexture(target, old_binding);
5025 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5026 checkGLcall("glFramebufferTexture2DEXT()");
5027 } else {
5028 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5029 checkGLcall("glFramebufferTexture2DEXT()");
5032 if (!This->render_offscreen) {
5033 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5034 checkGLcall("glBindFramebuffer()");
5038 void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5040 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5042 if (idx >= GL_LIMITS(buffers)) {
5043 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5046 bind_fbo(iface);
5048 if (rtimpl) {
5049 GLenum texttarget, target;
5050 GLint old_binding = 0;
5052 IWineD3DSurface_PreLoad(render_target);
5053 texttarget = rtimpl->glDescription.target;
5054 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5056 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5057 glBindTexture(target, rtimpl->glDescription.textureName);
5058 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5059 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5060 glBindTexture(target, old_binding);
5062 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5063 checkGLcall("glFramebufferTexture2DEXT()");
5065 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5066 } else {
5067 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5068 checkGLcall("glFramebufferTexture2DEXT()");
5070 This->draw_buffers[idx] = GL_NONE;
5073 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5074 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5075 checkGLcall("glDrawBuffers()");
5078 if (!This->render_offscreen) {
5079 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5080 checkGLcall("glBindFramebuffer()");
5084 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5086 WINED3DVIEWPORT viewport;
5088 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5090 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5091 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5092 return WINED3DERR_INVALIDCALL;
5095 /* MSDN says that null disables the render target
5096 but a device must always be associated with a render target
5097 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5099 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5100 for more details
5102 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5103 FIXME("Trying to set render target 0 to NULL\n");
5104 return WINED3DERR_INVALIDCALL;
5106 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5107 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);
5108 return WINED3DERR_INVALIDCALL;
5111 /* If we are trying to set what we already have, don't bother */
5112 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5113 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5114 return WINED3D_OK;
5116 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5117 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5118 This->render_targets[RenderTargetIndex] = pRenderTarget;
5120 /* Render target 0 is special */
5121 if(RenderTargetIndex == 0) {
5122 /* Finally, reset the viewport as the MSDN states. */
5123 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5124 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5125 viewport.X = 0;
5126 viewport.Y = 0;
5127 viewport.MaxZ = 1.0f;
5128 viewport.MinZ = 0.0f;
5129 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5131 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5132 * ctx properly.
5133 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5134 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5136 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5137 } else {
5138 /* We only get more than 1 render target with fbos, so no need to check the offscreen rendering method */
5139 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5141 return WINED3D_OK;
5144 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5146 HRESULT hr = WINED3D_OK;
5147 IWineD3DSurface *tmp;
5149 TRACE("(%p) Swapping z-buffer\n",This);
5151 if (pNewZStencil == This->stencilBufferTarget) {
5152 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5153 } else {
5154 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5155 * depending on the renter target implementation being used.
5156 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5157 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5158 * stencil buffer and incure an extra memory overhead
5159 ******************************************************/
5162 tmp = This->stencilBufferTarget;
5163 This->stencilBufferTarget = pNewZStencil;
5164 /* should we be calling the parent or the wined3d surface? */
5165 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5166 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5167 hr = WINED3D_OK;
5168 /** TODO: glEnable/glDisable on depth/stencil depending on
5169 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5170 **********************************************************/
5171 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5172 set_depth_stencil_fbo(iface, pNewZStencil);
5176 return hr;
5179 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5180 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5182 /* TODO: the use of Impl is deprecated. */
5183 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5185 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5187 /* some basic validation checks */
5188 if(This->cursorTexture) {
5189 ENTER_GL();
5190 glDeleteTextures(1, &This->cursorTexture);
5191 LEAVE_GL();
5192 This->cursorTexture = 0;
5195 if(pCursorBitmap) {
5196 /* MSDN: Cursor must be A8R8G8B8 */
5197 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5198 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5199 return WINED3DERR_INVALIDCALL;
5202 /* MSDN: Cursor must be smaller than the display mode */
5203 if(pSur->currentDesc.Width > This->ddraw_width ||
5204 pSur->currentDesc.Height > This->ddraw_height) {
5205 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);
5206 return WINED3DERR_INVALIDCALL;
5209 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5210 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
5211 * Texture and Blitting code to draw the cursor
5213 pSur->Flags |= SFLAG_FORCELOAD;
5214 IWineD3DSurface_PreLoad(pCursorBitmap);
5215 pSur->Flags &= ~SFLAG_FORCELOAD;
5216 /* Do not store the surface's pointer because the application may release
5217 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5218 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5220 This->cursorTexture = pSur->glDescription.textureName;
5221 This->cursorWidth = pSur->currentDesc.Width;
5222 This->cursorHeight = pSur->currentDesc.Height;
5223 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
5226 This->xHotSpot = XHotSpot;
5227 This->yHotSpot = YHotSpot;
5228 return WINED3D_OK;
5231 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5233 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5235 This->xScreenSpace = XScreenSpace;
5236 This->yScreenSpace = YScreenSpace;
5238 return;
5242 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5244 BOOL oldVisible = This->bCursorVisible;
5245 TRACE("(%p) : visible(%d)\n", This, bShow);
5247 if(This->cursorTexture)
5248 This->bCursorVisible = bShow;
5250 return oldVisible;
5253 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5255 TRACE("(%p) : state (%u)\n", This, This->state);
5256 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5257 switch (This->state) {
5258 case WINED3D_OK:
5259 return WINED3D_OK;
5260 case WINED3DERR_DEVICELOST:
5262 ResourceList *resourceList = This->resources;
5263 while (NULL != resourceList) {
5264 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5265 return WINED3DERR_DEVICENOTRESET;
5266 resourceList = resourceList->next;
5268 return WINED3DERR_DEVICELOST;
5270 case WINED3DERR_DRIVERINTERNALERROR:
5271 return WINED3DERR_DRIVERINTERNALERROR;
5274 /* Unknown state */
5275 return WINED3DERR_DRIVERINTERNALERROR;
5279 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5281 /** FIXME: Resource tracking needs to be done,
5282 * The closes we can do to this is set the priorities of all managed textures low
5283 * and then reset them.
5284 ***********************************************************/
5285 FIXME("(%p) : stub\n", This);
5286 return WINED3D_OK;
5289 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5290 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5292 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5293 if(surface->Flags & SFLAG_DIBSECTION) {
5294 /* Release the DC */
5295 SelectObject(surface->hDC, surface->dib.holdbitmap);
5296 DeleteDC(surface->hDC);
5297 /* Release the DIB section */
5298 DeleteObject(surface->dib.DIBsection);
5299 surface->dib.bitmap_data = NULL;
5300 surface->resource.allocatedMemory = NULL;
5301 surface->Flags &= ~SFLAG_DIBSECTION;
5303 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5304 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5305 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5306 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5307 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5308 } else {
5309 surface->pow2Width = surface->pow2Height = 1;
5310 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5311 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5313 if(surface->glDescription.textureName) {
5314 ENTER_GL();
5315 glDeleteTextures(1, &surface->glDescription.textureName);
5316 LEAVE_GL();
5317 surface->glDescription.textureName = 0;
5319 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5320 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5321 surface->Flags |= SFLAG_NONPOW2;
5322 } else {
5323 surface->Flags &= ~SFLAG_NONPOW2;
5325 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5326 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5329 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5331 IWineD3DSwapChainImpl *swapchain;
5332 HRESULT hr;
5333 BOOL DisplayModeChanged = FALSE;
5334 WINED3DDISPLAYMODE mode;
5335 TRACE("(%p)\n", This);
5337 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5338 if(FAILED(hr)) {
5339 ERR("Failed to get the first implicit swapchain\n");
5340 return hr;
5343 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5344 * on an existing gl context, so there's no real need for recreation.
5346 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5348 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5350 TRACE("New params:\n");
5351 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5352 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5353 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5354 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5355 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
5356 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
5357 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
5358 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
5359 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
5360 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5361 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
5362 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
5363 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
5365 /* No special treatment of these parameters. Just store them */
5366 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
5367 swapchain->presentParms.Flags = pPresentationParameters->Flags;
5368 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
5369 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
5371 /* What to do about these? */
5372 if(pPresentationParameters->BackBufferCount != 0 &&
5373 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
5374 ERR("Cannot change the back buffer count yet\n");
5376 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5377 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5378 ERR("Cannot change the back buffer format yet\n");
5380 if(pPresentationParameters->hDeviceWindow != NULL &&
5381 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
5382 ERR("Cannot change the device window yet\n");
5384 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
5385 ERR("What do do about a changed auto depth stencil parameter?\n");
5388 if(pPresentationParameters->Windowed) {
5389 mode.Width = swapchain->orig_width;
5390 mode.Height = swapchain->orig_height;
5391 mode.RefreshRate = 0;
5392 mode.Format = swapchain->presentParms.BackBufferFormat;
5393 } else {
5394 mode.Width = pPresentationParameters->BackBufferWidth;
5395 mode.Height = pPresentationParameters->BackBufferHeight;
5396 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
5397 mode.Format = swapchain->presentParms.BackBufferFormat;
5400 /* Should Width == 800 && Height == 0 set 800x600? */
5401 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
5402 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
5403 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5405 WINED3DVIEWPORT vp;
5406 int i;
5408 vp.X = 0;
5409 vp.Y = 0;
5410 vp.Width = pPresentationParameters->BackBufferWidth;
5411 vp.Height = pPresentationParameters->BackBufferHeight;
5412 vp.MinZ = 0;
5413 vp.MaxZ = 1;
5415 if(!pPresentationParameters->Windowed) {
5416 DisplayModeChanged = TRUE;
5418 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
5419 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
5421 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
5422 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
5423 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
5426 /* Now set the new viewport */
5427 IWineD3DDevice_SetViewport(iface, &vp);
5430 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
5431 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
5432 DisplayModeChanged) {
5434 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
5435 if(!pPresentationParameters->Windowed) {
5436 IWineD3DDevice_SetFullscreen(iface, TRUE);
5439 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
5441 /* Switching out of fullscreen mode? First set the original res, then change the window */
5442 if(pPresentationParameters->Windowed) {
5443 IWineD3DDevice_SetFullscreen(iface, FALSE);
5445 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
5448 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5449 return WINED3D_OK;
5452 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
5453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5454 /** FIXME: always true at the moment **/
5455 if(!bEnableDialogs) {
5456 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
5458 return WINED3D_OK;
5462 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
5463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5464 TRACE("(%p) : pParameters %p\n", This, pParameters);
5466 *pParameters = This->createParms;
5467 return WINED3D_OK;
5470 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
5471 IWineD3DSwapChain *swapchain;
5472 HRESULT hrc = WINED3D_OK;
5474 TRACE("Relaying to swapchain\n");
5476 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5477 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
5478 IWineD3DSwapChain_Release(swapchain);
5480 return;
5483 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
5484 IWineD3DSwapChain *swapchain;
5485 HRESULT hrc = WINED3D_OK;
5487 TRACE("Relaying to swapchain\n");
5489 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5490 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
5491 IWineD3DSwapChain_Release(swapchain);
5493 return;
5497 /** ********************************************************
5498 * Notification functions
5499 ** ********************************************************/
5500 /** This function must be called in the release of a resource when ref == 0,
5501 * the contents of resource must still be correct,
5502 * any handels to other resource held by the caller must be closed
5503 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
5504 *****************************************************/
5505 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5507 ResourceList* resourceList;
5509 TRACE("(%p) : resource %p\n", This, resource);
5510 #if 0
5511 EnterCriticalSection(&resourceStoreCriticalSection);
5512 #endif
5513 /* add a new texture to the frot of the linked list */
5514 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
5515 resourceList->resource = resource;
5517 /* Get the old head */
5518 resourceList->next = This->resources;
5520 This->resources = resourceList;
5521 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
5523 #if 0
5524 LeaveCriticalSection(&resourceStoreCriticalSection);
5525 #endif
5526 return;
5529 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5531 ResourceList* resourceList = NULL;
5532 ResourceList* previousResourceList = NULL;
5534 TRACE("(%p) : resource %p\n", This, resource);
5536 #if 0
5537 EnterCriticalSection(&resourceStoreCriticalSection);
5538 #endif
5539 resourceList = This->resources;
5541 while (resourceList != NULL) {
5542 if(resourceList->resource == resource) break;
5543 previousResourceList = resourceList;
5544 resourceList = resourceList->next;
5547 if (resourceList == NULL) {
5548 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
5549 #if 0
5550 LeaveCriticalSection(&resourceStoreCriticalSection);
5551 #endif
5552 return;
5553 } else {
5554 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
5556 /* make sure we don't leave a hole in the list */
5557 if (previousResourceList != NULL) {
5558 previousResourceList->next = resourceList->next;
5559 } else {
5560 This->resources = resourceList->next;
5563 #if 0
5564 LeaveCriticalSection(&resourceStoreCriticalSection);
5565 #endif
5566 return;
5570 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
5571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5572 int counter;
5574 TRACE("(%p) : resource %p\n", This, resource);
5575 switch(IWineD3DResource_GetType(resource)){
5576 case WINED3DRTYPE_SURFACE:
5577 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
5578 break;
5579 case WINED3DRTYPE_TEXTURE:
5580 case WINED3DRTYPE_CUBETEXTURE:
5581 case WINED3DRTYPE_VOLUMETEXTURE:
5582 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
5583 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5584 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5585 This->stateBlock->textures[counter] = NULL;
5587 if (This->updateStateBlock != This->stateBlock ){
5588 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5589 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5590 This->updateStateBlock->textures[counter] = NULL;
5594 break;
5595 case WINED3DRTYPE_VOLUME:
5596 /* TODO: nothing really? */
5597 break;
5598 case WINED3DRTYPE_VERTEXBUFFER:
5599 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
5601 int streamNumber;
5602 TRACE("Cleaning up stream pointers\n");
5604 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
5605 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
5606 FINDOUT: should changes.streamSource[StreamNumber] be set ?
5608 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5609 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
5610 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5611 This->updateStateBlock->streamSource[streamNumber] = 0;
5612 /* Set changed flag? */
5615 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) */
5616 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
5617 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5618 This->stateBlock->streamSource[streamNumber] = 0;
5621 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
5622 else { /* This shouldn't happen */
5623 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
5625 #endif
5629 break;
5630 case WINED3DRTYPE_INDEXBUFFER:
5631 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
5632 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5633 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5634 This->updateStateBlock->pIndexData = NULL;
5637 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
5638 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5639 This->stateBlock->pIndexData = NULL;
5643 break;
5644 default:
5645 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
5646 break;
5650 /* Remove the resoruce from the resourceStore */
5651 IWineD3DDeviceImpl_RemoveResource(iface, resource);
5653 TRACE("Resource released\n");
5657 /**********************************************************
5658 * IWineD3DDevice VTbl follows
5659 **********************************************************/
5661 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
5663 /*** IUnknown methods ***/
5664 IWineD3DDeviceImpl_QueryInterface,
5665 IWineD3DDeviceImpl_AddRef,
5666 IWineD3DDeviceImpl_Release,
5667 /*** IWineD3DDevice methods ***/
5668 IWineD3DDeviceImpl_GetParent,
5669 /*** Creation methods**/
5670 IWineD3DDeviceImpl_CreateVertexBuffer,
5671 IWineD3DDeviceImpl_CreateIndexBuffer,
5672 IWineD3DDeviceImpl_CreateStateBlock,
5673 IWineD3DDeviceImpl_CreateSurface,
5674 IWineD3DDeviceImpl_CreateTexture,
5675 IWineD3DDeviceImpl_CreateVolumeTexture,
5676 IWineD3DDeviceImpl_CreateVolume,
5677 IWineD3DDeviceImpl_CreateCubeTexture,
5678 IWineD3DDeviceImpl_CreateQuery,
5679 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
5680 IWineD3DDeviceImpl_CreateVertexDeclaration,
5681 IWineD3DDeviceImpl_CreateVertexShader,
5682 IWineD3DDeviceImpl_CreatePixelShader,
5683 IWineD3DDeviceImpl_CreatePalette,
5684 /*** Odd functions **/
5685 IWineD3DDeviceImpl_Init3D,
5686 IWineD3DDeviceImpl_Uninit3D,
5687 IWineD3DDeviceImpl_SetFullscreen,
5688 IWineD3DDeviceImpl_EvictManagedResources,
5689 IWineD3DDeviceImpl_GetAvailableTextureMem,
5690 IWineD3DDeviceImpl_GetBackBuffer,
5691 IWineD3DDeviceImpl_GetCreationParameters,
5692 IWineD3DDeviceImpl_GetDeviceCaps,
5693 IWineD3DDeviceImpl_GetDirect3D,
5694 IWineD3DDeviceImpl_GetDisplayMode,
5695 IWineD3DDeviceImpl_SetDisplayMode,
5696 IWineD3DDeviceImpl_GetHWND,
5697 IWineD3DDeviceImpl_SetHWND,
5698 IWineD3DDeviceImpl_GetNumberOfSwapChains,
5699 IWineD3DDeviceImpl_GetRasterStatus,
5700 IWineD3DDeviceImpl_GetSwapChain,
5701 IWineD3DDeviceImpl_Reset,
5702 IWineD3DDeviceImpl_SetDialogBoxMode,
5703 IWineD3DDeviceImpl_SetCursorProperties,
5704 IWineD3DDeviceImpl_SetCursorPosition,
5705 IWineD3DDeviceImpl_ShowCursor,
5706 IWineD3DDeviceImpl_TestCooperativeLevel,
5707 /*** Getters and setters **/
5708 IWineD3DDeviceImpl_SetClipPlane,
5709 IWineD3DDeviceImpl_GetClipPlane,
5710 IWineD3DDeviceImpl_SetClipStatus,
5711 IWineD3DDeviceImpl_GetClipStatus,
5712 IWineD3DDeviceImpl_SetCurrentTexturePalette,
5713 IWineD3DDeviceImpl_GetCurrentTexturePalette,
5714 IWineD3DDeviceImpl_SetDepthStencilSurface,
5715 IWineD3DDeviceImpl_GetDepthStencilSurface,
5716 IWineD3DDeviceImpl_SetFVF,
5717 IWineD3DDeviceImpl_GetFVF,
5718 IWineD3DDeviceImpl_SetGammaRamp,
5719 IWineD3DDeviceImpl_GetGammaRamp,
5720 IWineD3DDeviceImpl_SetIndices,
5721 IWineD3DDeviceImpl_GetIndices,
5722 IWineD3DDeviceImpl_SetBasevertexIndex,
5723 IWineD3DDeviceImpl_SetLight,
5724 IWineD3DDeviceImpl_GetLight,
5725 IWineD3DDeviceImpl_SetLightEnable,
5726 IWineD3DDeviceImpl_GetLightEnable,
5727 IWineD3DDeviceImpl_SetMaterial,
5728 IWineD3DDeviceImpl_GetMaterial,
5729 IWineD3DDeviceImpl_SetNPatchMode,
5730 IWineD3DDeviceImpl_GetNPatchMode,
5731 IWineD3DDeviceImpl_SetPaletteEntries,
5732 IWineD3DDeviceImpl_GetPaletteEntries,
5733 IWineD3DDeviceImpl_SetPixelShader,
5734 IWineD3DDeviceImpl_GetPixelShader,
5735 IWineD3DDeviceImpl_SetPixelShaderConstantB,
5736 IWineD3DDeviceImpl_GetPixelShaderConstantB,
5737 IWineD3DDeviceImpl_SetPixelShaderConstantI,
5738 IWineD3DDeviceImpl_GetPixelShaderConstantI,
5739 IWineD3DDeviceImpl_SetPixelShaderConstantF,
5740 IWineD3DDeviceImpl_GetPixelShaderConstantF,
5741 IWineD3DDeviceImpl_SetRenderState,
5742 IWineD3DDeviceImpl_GetRenderState,
5743 IWineD3DDeviceImpl_SetRenderTarget,
5744 IWineD3DDeviceImpl_GetRenderTarget,
5745 IWineD3DDeviceImpl_SetFrontBackBuffers,
5746 IWineD3DDeviceImpl_SetSamplerState,
5747 IWineD3DDeviceImpl_GetSamplerState,
5748 IWineD3DDeviceImpl_SetScissorRect,
5749 IWineD3DDeviceImpl_GetScissorRect,
5750 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
5751 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
5752 IWineD3DDeviceImpl_SetStreamSource,
5753 IWineD3DDeviceImpl_GetStreamSource,
5754 IWineD3DDeviceImpl_SetStreamSourceFreq,
5755 IWineD3DDeviceImpl_GetStreamSourceFreq,
5756 IWineD3DDeviceImpl_SetTexture,
5757 IWineD3DDeviceImpl_GetTexture,
5758 IWineD3DDeviceImpl_SetTextureStageState,
5759 IWineD3DDeviceImpl_GetTextureStageState,
5760 IWineD3DDeviceImpl_SetTransform,
5761 IWineD3DDeviceImpl_GetTransform,
5762 IWineD3DDeviceImpl_SetVertexDeclaration,
5763 IWineD3DDeviceImpl_GetVertexDeclaration,
5764 IWineD3DDeviceImpl_SetVertexShader,
5765 IWineD3DDeviceImpl_GetVertexShader,
5766 IWineD3DDeviceImpl_SetVertexShaderConstantB,
5767 IWineD3DDeviceImpl_GetVertexShaderConstantB,
5768 IWineD3DDeviceImpl_SetVertexShaderConstantI,
5769 IWineD3DDeviceImpl_GetVertexShaderConstantI,
5770 IWineD3DDeviceImpl_SetVertexShaderConstantF,
5771 IWineD3DDeviceImpl_GetVertexShaderConstantF,
5772 IWineD3DDeviceImpl_SetViewport,
5773 IWineD3DDeviceImpl_GetViewport,
5774 IWineD3DDeviceImpl_MultiplyTransform,
5775 IWineD3DDeviceImpl_ValidateDevice,
5776 IWineD3DDeviceImpl_ProcessVertices,
5777 /*** State block ***/
5778 IWineD3DDeviceImpl_BeginStateBlock,
5779 IWineD3DDeviceImpl_EndStateBlock,
5780 /*** Scene management ***/
5781 IWineD3DDeviceImpl_BeginScene,
5782 IWineD3DDeviceImpl_EndScene,
5783 IWineD3DDeviceImpl_Present,
5784 IWineD3DDeviceImpl_Clear,
5785 /*** Drawing ***/
5786 IWineD3DDeviceImpl_DrawPrimitive,
5787 IWineD3DDeviceImpl_DrawIndexedPrimitive,
5788 IWineD3DDeviceImpl_DrawPrimitiveUP,
5789 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
5790 IWineD3DDeviceImpl_DrawPrimitiveStrided,
5791 IWineD3DDeviceImpl_DrawRectPatch,
5792 IWineD3DDeviceImpl_DrawTriPatch,
5793 IWineD3DDeviceImpl_DeletePatch,
5794 IWineD3DDeviceImpl_ColorFill,
5795 IWineD3DDeviceImpl_UpdateTexture,
5796 IWineD3DDeviceImpl_UpdateSurface,
5797 IWineD3DDeviceImpl_GetFrontBufferData,
5798 /*** object tracking ***/
5799 IWineD3DDeviceImpl_ResourceReleased
5803 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
5804 WINED3DRS_ALPHABLENDENABLE ,
5805 WINED3DRS_ALPHAFUNC ,
5806 WINED3DRS_ALPHAREF ,
5807 WINED3DRS_ALPHATESTENABLE ,
5808 WINED3DRS_BLENDOP ,
5809 WINED3DRS_COLORWRITEENABLE ,
5810 WINED3DRS_DESTBLEND ,
5811 WINED3DRS_DITHERENABLE ,
5812 WINED3DRS_FILLMODE ,
5813 WINED3DRS_FOGDENSITY ,
5814 WINED3DRS_FOGEND ,
5815 WINED3DRS_FOGSTART ,
5816 WINED3DRS_LASTPIXEL ,
5817 WINED3DRS_SHADEMODE ,
5818 WINED3DRS_SRCBLEND ,
5819 WINED3DRS_STENCILENABLE ,
5820 WINED3DRS_STENCILFAIL ,
5821 WINED3DRS_STENCILFUNC ,
5822 WINED3DRS_STENCILMASK ,
5823 WINED3DRS_STENCILPASS ,
5824 WINED3DRS_STENCILREF ,
5825 WINED3DRS_STENCILWRITEMASK ,
5826 WINED3DRS_STENCILZFAIL ,
5827 WINED3DRS_TEXTUREFACTOR ,
5828 WINED3DRS_WRAP0 ,
5829 WINED3DRS_WRAP1 ,
5830 WINED3DRS_WRAP2 ,
5831 WINED3DRS_WRAP3 ,
5832 WINED3DRS_WRAP4 ,
5833 WINED3DRS_WRAP5 ,
5834 WINED3DRS_WRAP6 ,
5835 WINED3DRS_WRAP7 ,
5836 WINED3DRS_ZENABLE ,
5837 WINED3DRS_ZFUNC ,
5838 WINED3DRS_ZWRITEENABLE
5841 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
5842 WINED3DTSS_ADDRESSW ,
5843 WINED3DTSS_ALPHAARG0 ,
5844 WINED3DTSS_ALPHAARG1 ,
5845 WINED3DTSS_ALPHAARG2 ,
5846 WINED3DTSS_ALPHAOP ,
5847 WINED3DTSS_BUMPENVLOFFSET ,
5848 WINED3DTSS_BUMPENVLSCALE ,
5849 WINED3DTSS_BUMPENVMAT00 ,
5850 WINED3DTSS_BUMPENVMAT01 ,
5851 WINED3DTSS_BUMPENVMAT10 ,
5852 WINED3DTSS_BUMPENVMAT11 ,
5853 WINED3DTSS_COLORARG0 ,
5854 WINED3DTSS_COLORARG1 ,
5855 WINED3DTSS_COLORARG2 ,
5856 WINED3DTSS_COLOROP ,
5857 WINED3DTSS_RESULTARG ,
5858 WINED3DTSS_TEXCOORDINDEX ,
5859 WINED3DTSS_TEXTURETRANSFORMFLAGS
5862 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
5863 WINED3DSAMP_ADDRESSU ,
5864 WINED3DSAMP_ADDRESSV ,
5865 WINED3DSAMP_ADDRESSW ,
5866 WINED3DSAMP_BORDERCOLOR ,
5867 WINED3DSAMP_MAGFILTER ,
5868 WINED3DSAMP_MINFILTER ,
5869 WINED3DSAMP_MIPFILTER ,
5870 WINED3DSAMP_MIPMAPLODBIAS ,
5871 WINED3DSAMP_MAXMIPLEVEL ,
5872 WINED3DSAMP_MAXANISOTROPY ,
5873 WINED3DSAMP_SRGBTEXTURE ,
5874 WINED3DSAMP_ELEMENTINDEX
5877 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
5878 WINED3DRS_AMBIENT ,
5879 WINED3DRS_AMBIENTMATERIALSOURCE ,
5880 WINED3DRS_CLIPPING ,
5881 WINED3DRS_CLIPPLANEENABLE ,
5882 WINED3DRS_COLORVERTEX ,
5883 WINED3DRS_DIFFUSEMATERIALSOURCE ,
5884 WINED3DRS_EMISSIVEMATERIALSOURCE ,
5885 WINED3DRS_FOGDENSITY ,
5886 WINED3DRS_FOGEND ,
5887 WINED3DRS_FOGSTART ,
5888 WINED3DRS_FOGTABLEMODE ,
5889 WINED3DRS_FOGVERTEXMODE ,
5890 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
5891 WINED3DRS_LIGHTING ,
5892 WINED3DRS_LOCALVIEWER ,
5893 WINED3DRS_MULTISAMPLEANTIALIAS ,
5894 WINED3DRS_MULTISAMPLEMASK ,
5895 WINED3DRS_NORMALIZENORMALS ,
5896 WINED3DRS_PATCHEDGESTYLE ,
5897 WINED3DRS_POINTSCALE_A ,
5898 WINED3DRS_POINTSCALE_B ,
5899 WINED3DRS_POINTSCALE_C ,
5900 WINED3DRS_POINTSCALEENABLE ,
5901 WINED3DRS_POINTSIZE ,
5902 WINED3DRS_POINTSIZE_MAX ,
5903 WINED3DRS_POINTSIZE_MIN ,
5904 WINED3DRS_POINTSPRITEENABLE ,
5905 WINED3DRS_RANGEFOGENABLE ,
5906 WINED3DRS_SPECULARMATERIALSOURCE ,
5907 WINED3DRS_TWEENFACTOR ,
5908 WINED3DRS_VERTEXBLEND
5911 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
5912 WINED3DTSS_TEXCOORDINDEX ,
5913 WINED3DTSS_TEXTURETRANSFORMFLAGS
5916 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
5917 WINED3DSAMP_DMAPOFFSET
5920 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
5921 DWORD rep = StateTable[state].representative;
5922 DWORD idx;
5923 BYTE shift;
5924 UINT i;
5925 WineD3DContext *context;
5927 if(!rep) return;
5928 for(i = 0; i < This->numContexts; i++) {
5929 context = This->contexts[i];
5930 if(isStateDirty(context, rep)) continue;
5932 context->dirtyArray[context->numDirtyEntries++] = rep;
5933 idx = rep >> 5;
5934 shift = rep & 0x1f;
5935 context->isStateDirty[idx] |= (1 << shift);