wined3d: Floating point shader constant setting.
[wine/wine64.git] / dlls / wined3d / device.c
blob08860aeb7df2718ec06c21f3ee586745aadb82e2
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 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
36 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
60 X11DRV_GET_FONT, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 inline static Display *get_display( HDC hdc )
66 Display *display;
67 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
69 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
70 sizeof(display), (LPSTR)&display )) display = NULL;
71 return display;
74 /* allocate one pbuffer per surface */
75 BOOL pbuffer_per_surface = FALSE;
77 /* static function declarations */
78 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
80 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil);
82 /* helper macros */
83 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
85 #define D3DCREATEOBJECTINSTANCE(object, type) { \
86 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
87 D3DMEMCHECK(object, pp##type); \
88 object->lpVtbl = &IWineD3D##type##_Vtbl; \
89 object->wineD3DDevice = This; \
90 object->parent = parent; \
91 object->ref = 1; \
92 *pp##type = (IWineD3D##type *) object; \
95 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
96 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
97 D3DMEMCHECK(object, pp##type); \
98 object->lpVtbl = &IWineD3D##type##_Vtbl; \
99 object->parent = parent; \
100 object->ref = 1; \
101 object->baseShader.device = (IWineD3DDevice*) This; \
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 * GLSL helper functions follow
153 **********************************************************/
155 /** Detach the GLSL pixel or vertex shader object from the shader program */
156 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
160 if (shaderObj != 0 && programId != 0) {
161 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
162 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
163 checkGLcall("glDetachObjectARB");
167 /** Delete a GLSL shader program */
168 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
172 if (obj != 0) {
173 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
174 GL_EXTCALL(glDeleteObjectARB(obj));
175 checkGLcall("glDeleteObjectARB");
179 /** Delete the list of linked programs this shader is associated with.
180 * Also at this point, check to see if there are any objects left attached
181 * to each GLSL program. If not, delete the GLSL program object.
182 * This will be run when a device is released. */
183 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
185 struct list *ptr = NULL;
186 struct glsl_shader_prog_link *curLink = NULL;
187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
189 int numAttached = 0;
190 int i;
191 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
192 (one pixel shader and one vertex shader at most) */
194 ptr = list_head( &This->glsl_shader_progs );
195 while (ptr) {
196 /* First, get the current item,
197 * save the link to the next pointer,
198 * detach and delete shader objects,
199 * then de-allocate the list item's memory */
200 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
201 ptr = list_next( &This->glsl_shader_progs, ptr );
203 /* See if this object is still attached to the program - it may have been detached already */
204 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
205 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
206 for (i = 0; i < numAttached; i++) {
207 detach_glsl_shader(iface, objList[i], curLink->programId);
210 delete_glsl_shader_program(iface, curLink->programId);
212 /* Free the uniform locations */
213 HeapFree(GetProcessHeap(), 0, curLink->vuniformF_locations);
214 HeapFree(GetProcessHeap(), 0, curLink->puniformF_locations);
216 /* Free the memory for this list item */
217 HeapFree(GetProcessHeap(), 0, curLink);
221 /**********************************************************
222 * IUnknown parts follows
223 **********************************************************/
225 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
229 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
230 if (IsEqualGUID(riid, &IID_IUnknown)
231 || IsEqualGUID(riid, &IID_IWineD3DBase)
232 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
233 IUnknown_AddRef(iface);
234 *ppobj = This;
235 return S_OK;
237 *ppobj = NULL;
238 return E_NOINTERFACE;
241 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
243 ULONG refCount = InterlockedIncrement(&This->ref);
245 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
246 return refCount;
249 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
251 ULONG refCount = InterlockedDecrement(&This->ref);
253 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
255 if (!refCount) {
256 if (This->fbo) {
257 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
260 HeapFree(GetProcessHeap(), 0, This->render_targets);
262 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
264 /* TODO: Clean up all the surfaces and textures! */
265 /* NOTE: You must release the parent if the object was created via a callback
266 ** ***************************/
268 /* Delete any GLSL shader programs that may exist */
269 if (This->vs_selected_mode == SHADER_GLSL ||
270 This->ps_selected_mode == SHADER_GLSL)
271 delete_glsl_shader_list(iface);
273 /* Release the update stateblock */
274 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
275 if(This->updateStateBlock != This->stateBlock)
276 FIXME("(%p) Something's still holding the Update stateblock\n",This);
278 This->updateStateBlock = NULL;
279 { /* because were not doing proper internal refcounts releasing the primary state block
280 causes recursion with the extra checks in ResourceReleased, to avoid this we have
281 to set this->stateBlock = NULL; first */
282 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
283 This->stateBlock = NULL;
285 /* Release the stateblock */
286 if(IWineD3DStateBlock_Release(stateBlock) > 0){
287 FIXME("(%p) Something's still holding the Update stateblock\n",This);
291 if (This->resources != NULL ) {
292 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
293 dumpResources(This->resources);
296 if(This->contexts) ERR("Context array not freed!\n");
298 IWineD3D_Release(This->wineD3D);
299 This->wineD3D = NULL;
300 HeapFree(GetProcessHeap(), 0, This);
301 TRACE("Freed device %p\n", This);
302 This = NULL;
304 return refCount;
307 /**********************************************************
308 * IWineD3DDevice implementation follows
309 **********************************************************/
310 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
312 *pParent = This->parent;
313 IUnknown_AddRef(This->parent);
314 return WINED3D_OK;
317 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
318 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
319 GLenum error, glUsage;
320 DWORD vboUsage = object->resource.usage;
321 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
322 WARN("Creating a vbo failed once, not trying again\n");
323 return;
326 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
328 ENTER_GL();
329 /* Make sure that the gl error is cleared. Do not use checkGLcall
330 * here because checkGLcall just prints a fixme and continues. However,
331 * if an error during VBO creation occurs we can fall back to non-vbo operation
332 * with full functionality(but performance loss)
334 while(glGetError() != GL_NO_ERROR);
336 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
337 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
338 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
339 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
340 * to check if the rhw and color values are in the correct format.
343 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
344 error = glGetError();
345 if(object->vbo == 0 || error != GL_NO_ERROR) {
346 WARN("Failed to create a VBO with error %d\n", error);
347 goto error;
350 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
351 error = glGetError();
352 if(error != GL_NO_ERROR) {
353 WARN("Failed to bind the VBO, error %d\n", error);
354 goto error;
357 /* Don't use static, because dx apps tend to update the buffer
358 * quite often even if they specify 0 usage. Because we always keep the local copy
359 * we never read from the vbo and can create a write only opengl buffer.
361 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
362 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
363 case WINED3DUSAGE_DYNAMIC:
364 TRACE("Gl usage = GL_STREAM_DRAW\n");
365 glUsage = GL_STREAM_DRAW_ARB;
366 break;
367 case WINED3DUSAGE_WRITEONLY:
368 default:
369 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
370 glUsage = GL_DYNAMIC_DRAW_ARB;
371 break;
374 /* Reserve memory for the buffer. The amount of data won't change
375 * so we are safe with calling glBufferData once with a NULL ptr and
376 * calling glBufferSubData on updates
378 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
379 error = glGetError();
380 if(error != GL_NO_ERROR) {
381 WARN("glBufferDataARB failed with error %d\n", error);
382 goto error;
385 LEAVE_GL();
387 return;
388 error:
389 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
390 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
391 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
392 object->vbo = 0;
393 object->Flags |= VBFLAG_VBOCREATEFAIL;
394 LEAVE_GL();
395 return;
398 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
399 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
400 IUnknown *parent) {
401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
402 IWineD3DVertexBufferImpl *object;
403 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
404 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
405 BOOL conv;
407 if(Size == 0) {
408 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
409 *ppVertexBuffer = NULL;
410 return WINED3DERR_INVALIDCALL;
413 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
415 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
416 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
418 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
419 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
421 object->fvf = FVF;
423 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
424 * drawStridedFast (half-life 2).
426 * Basically converting the vertices in the buffer is quite expensive, and observations
427 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
428 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
430 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
431 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
432 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
433 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
434 * dx7 apps.
435 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
436 * more. In this call we can convert dx7 buffers too.
438 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
439 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
440 (dxVersion > 7 || !conv) ) {
441 CreateVBO(object);
443 return WINED3D_OK;
446 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
447 GLenum error, glUsage;
448 TRACE("Creating VBO for Index Buffer %p\n", object);
450 ENTER_GL();
451 while(glGetError());
453 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
454 error = glGetError();
455 if(error != GL_NO_ERROR || object->vbo == 0) {
456 ERR("Creating a vbo failed, continueing without vbo for this buffer\n");
457 object->vbo = 0;
458 return;
461 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
462 error = glGetError();
463 if(error != GL_NO_ERROR) {
464 ERR("Failed to bind index buffer, continueing without vbo for this buffer\n");
465 goto out;
468 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
469 * copy no readback will be needed
471 glUsage = GL_STATIC_DRAW;
472 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
473 error = glGetError();
474 if(error != GL_NO_ERROR) {
475 ERR("Failed to initialize the index buffer\n");
476 goto out;
478 LEAVE_GL();
479 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
480 return;
482 out:
483 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
484 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
485 LEAVE_GL();
486 object->vbo = 0;
489 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
490 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
491 HANDLE *sharedHandle, IUnknown *parent) {
492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
493 IWineD3DIndexBufferImpl *object;
494 TRACE("(%p) Creating index buffer\n", This);
496 /* Allocate the storage for the device */
497 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
499 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
500 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
503 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
504 CreateIndexBufferVBO(This, object);
507 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
508 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
509 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
511 return WINED3D_OK;
514 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
517 IWineD3DStateBlockImpl *object;
518 int i, j;
519 HRESULT temp_result;
521 D3DCREATEOBJECTINSTANCE(object, StateBlock)
522 object->blockType = Type;
524 for(i = 0; i < LIGHTMAP_SIZE; i++) {
525 list_init(&object->lightMap[i]);
528 /* Special case - Used during initialization to produce a placeholder stateblock
529 so other functions called can update a state block */
530 if (Type == WINED3DSBT_INIT) {
531 /* Don't bother increasing the reference count otherwise a device will never
532 be freed due to circular dependencies */
533 return WINED3D_OK;
536 temp_result = allocate_shader_constants(object);
537 if (WINED3D_OK != temp_result)
538 return temp_result;
540 /* Otherwise, might as well set the whole state block to the appropriate values */
541 if (This->stateBlock != NULL)
542 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
543 else
544 memset(object->streamFreq, 1, sizeof(object->streamFreq));
546 /* Reset the ref and type after kludging it */
547 object->wineD3DDevice = This;
548 object->ref = 1;
549 object->blockType = Type;
551 TRACE("Updating changed flags appropriate for type %d\n", Type);
553 if (Type == WINED3DSBT_ALL) {
555 TRACE("ALL => Pretend everything has changed\n");
556 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
558 /* Lights are not part of the changed / set structure */
559 for(j = 0; j < LIGHTMAP_SIZE; j++) {
560 struct list *e;
561 LIST_FOR_EACH(e, &object->lightMap[j]) {
562 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
563 light->changed = TRUE;
564 light->enabledChanged = TRUE;
567 } else if (Type == WINED3DSBT_PIXELSTATE) {
569 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
570 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
572 object->changed.pixelShader = TRUE;
574 /* Pixel Shader Constants */
575 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
576 object->changed.pixelShaderConstantsF[i] = TRUE;
577 for (i = 0; i < MAX_CONST_B; ++i)
578 object->changed.pixelShaderConstantsB[i] = TRUE;
579 for (i = 0; i < MAX_CONST_I; ++i)
580 object->changed.pixelShaderConstantsI[i] = TRUE;
582 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
583 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
585 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
586 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
587 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
590 for (j = 0 ; j < 16; j++) {
591 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
593 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
597 } else if (Type == WINED3DSBT_VERTEXSTATE) {
599 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
600 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
602 object->changed.vertexShader = TRUE;
604 /* Vertex Shader Constants */
605 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
606 object->changed.vertexShaderConstantsF[i] = TRUE;
607 for (i = 0; i < MAX_CONST_B; ++i)
608 object->changed.vertexShaderConstantsB[i] = TRUE;
609 for (i = 0; i < MAX_CONST_I; ++i)
610 object->changed.vertexShaderConstantsI[i] = TRUE;
612 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
613 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
615 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
616 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
617 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
620 for (j = 0 ; j < 16; j++){
621 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
622 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
626 for(j = 0; j < LIGHTMAP_SIZE; j++) {
627 struct list *e;
628 LIST_FOR_EACH(e, &object->lightMap[j]) {
629 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
630 light->changed = TRUE;
631 light->enabledChanged = TRUE;
634 } else {
635 FIXME("Unrecognized state block type %d\n", Type);
638 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
639 return WINED3D_OK;
643 /* ************************************
644 MSDN:
645 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
647 Discard
648 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
650 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.
652 ******************************** */
654 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) {
655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
656 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
657 unsigned int pow2Width, pow2Height;
658 unsigned int Size = 1;
659 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
660 TRACE("(%p) Create surface\n",This);
662 /** FIXME: Check ranges on the inputs are valid
663 * MSDN
664 * MultisampleQuality
665 * [in] Quality level. The valid range is between zero and one less than the level
666 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
667 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
668 * values of paired render targets, depth stencil surfaces, and the MultiSample type
669 * must all match.
670 *******************************/
674 * TODO: Discard MSDN
675 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
677 * If this flag is set, the contents of the depth stencil buffer will be
678 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
679 * with a different depth surface.
681 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
682 ***************************/
684 if(MultisampleQuality < 0) {
685 FIXME("Invalid multisample level %d\n", MultisampleQuality);
686 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
689 if(MultisampleQuality > 0) {
690 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
691 MultisampleQuality=0;
694 /** FIXME: Check that the format is supported
695 * by the device.
696 *******************************/
698 /* Non-power2 support */
699 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
700 pow2Width = Width;
701 pow2Height = Height;
702 } else {
703 /* Find the nearest pow2 match */
704 pow2Width = pow2Height = 1;
705 while (pow2Width < Width) pow2Width <<= 1;
706 while (pow2Height < Height) pow2Height <<= 1;
709 if (pow2Width > Width || pow2Height > Height) {
710 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
711 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
712 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
713 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
714 This, Width, Height);
715 return WINED3DERR_NOTAVAILABLE;
719 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
720 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
721 * space!
722 *********************************/
723 if (WINED3DFMT_UNKNOWN == Format) {
724 Size = 0;
725 } else if (Format == WINED3DFMT_DXT1) {
726 /* DXT1 is half byte per pixel */
727 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
729 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
730 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
731 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
732 } else {
733 /* The pitch is a multiple of 4 bytes */
734 Size = ((Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
735 Size *= Height;
738 /** Create and initialise the surface resource **/
739 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
740 /* "Standalone" surface */
741 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
743 object->currentDesc.Width = Width;
744 object->currentDesc.Height = Height;
745 object->currentDesc.MultiSampleType = MultiSample;
746 object->currentDesc.MultiSampleQuality = MultisampleQuality;
748 /* Setup some glformat defaults */
749 object->glDescription.glFormat = tableEntry->glFormat;
750 object->glDescription.glFormatInternal = tableEntry->glInternal;
751 object->glDescription.glType = tableEntry->glType;
753 object->glDescription.textureName = 0;
754 object->glDescription.level = Level;
755 object->glDescription.target = GL_TEXTURE_2D;
757 /* Internal data */
758 object->pow2Width = pow2Width;
759 object->pow2Height = pow2Height;
761 /* Flags */
762 object->Flags = 0; /* We start without flags set */
763 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
764 object->Flags |= Discard ? SFLAG_DISCARD : 0;
765 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
766 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
769 if (WINED3DFMT_UNKNOWN != Format) {
770 object->bytesPerPixel = tableEntry->bpp;
771 } else {
772 object->bytesPerPixel = 0;
775 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
777 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
779 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
780 * this function is too deep to need to care about things like this.
781 * Levels need to be checked too, and possibly Type since they all affect what can be done.
782 * ****************************************/
783 switch(Pool) {
784 case WINED3DPOOL_SCRATCH:
785 if(!Lockable)
786 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
787 "which are mutually exclusive, setting lockable to TRUE\n");
788 Lockable = TRUE;
789 break;
790 case WINED3DPOOL_SYSTEMMEM:
791 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
792 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
793 case WINED3DPOOL_MANAGED:
794 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
795 "Usage of DYNAMIC which are mutually exclusive, not doing "
796 "anything just telling you.\n");
797 break;
798 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
799 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
800 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
801 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
802 break;
803 default:
804 FIXME("(%p) Unknown pool %d\n", This, Pool);
805 break;
808 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
809 FIXME("Trying to create a render target that isn't in the default pool\n");
812 /* mark the texture as dirty so that it gets loaded first time around*/
813 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
814 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
815 This, Width, Height, Format, debug_d3dformat(Format),
816 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
818 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
819 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
820 This->ddraw_primary = (IWineD3DSurface *) object;
822 /* Look at the implementation and set the correct Vtable */
823 switch(Impl) {
824 case SURFACE_OPENGL:
825 /* Nothing to do, it's set already */
826 break;
828 case SURFACE_GDI:
829 object->lpVtbl = &IWineGDISurface_Vtbl;
830 break;
832 default:
833 /* To be sure to catch this */
834 ERR("Unknown requested surface implementation %d!\n", Impl);
835 IWineD3DSurface_Release((IWineD3DSurface *) object);
836 return WINED3DERR_INVALIDCALL;
839 /* Call the private setup routine */
840 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
844 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
845 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
846 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
847 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
850 IWineD3DTextureImpl *object;
851 unsigned int i;
852 UINT tmpW;
853 UINT tmpH;
854 HRESULT hr;
855 unsigned int pow2Width;
856 unsigned int pow2Height;
859 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
860 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
861 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
863 /* TODO: It should only be possible to create textures for formats
864 that are reported as supported */
865 if (WINED3DFMT_UNKNOWN >= Format) {
866 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
867 return WINED3DERR_INVALIDCALL;
870 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
871 D3DINITIALIZEBASETEXTURE(object->baseTexture);
872 object->width = Width;
873 object->height = Height;
875 /** Non-power2 support **/
876 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
877 pow2Width = Width;
878 pow2Height = Height;
879 } else {
880 /* Find the nearest pow2 match */
881 pow2Width = pow2Height = 1;
882 while (pow2Width < Width) pow2Width <<= 1;
883 while (pow2Height < Height) pow2Height <<= 1;
886 /** FIXME: add support for real non-power-two if it's provided by the video card **/
887 /* Precalculated scaling for 'faked' non power of two texture coords */
888 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
889 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
890 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
892 /* Calculate levels for mip mapping */
893 if (Levels == 0) {
894 TRACE("calculating levels %d\n", object->baseTexture.levels);
895 object->baseTexture.levels++;
896 tmpW = Width;
897 tmpH = Height;
898 while (tmpW > 1 || tmpH > 1) {
899 tmpW = max(1, tmpW >> 1);
900 tmpH = max(1, tmpH >> 1);
901 object->baseTexture.levels++;
903 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
906 /* Generate all the surfaces */
907 tmpW = Width;
908 tmpH = Height;
909 for (i = 0; i < object->baseTexture.levels; i++)
911 /* use the callback to create the texture surface */
912 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
913 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
914 FIXME("Failed to create surface %p\n", object);
915 /* clean up */
916 object->surfaces[i] = NULL;
917 IWineD3DTexture_Release((IWineD3DTexture *)object);
919 *ppTexture = NULL;
920 return hr;
923 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
924 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
925 /* calculate the next mipmap level */
926 tmpW = max(1, tmpW >> 1);
927 tmpH = max(1, tmpH >> 1);
930 TRACE("(%p) : Created texture %p\n", This, object);
931 return WINED3D_OK;
934 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
935 UINT Width, UINT Height, UINT Depth,
936 UINT Levels, DWORD Usage,
937 WINED3DFORMAT Format, WINED3DPOOL Pool,
938 IWineD3DVolumeTexture **ppVolumeTexture,
939 HANDLE *pSharedHandle, IUnknown *parent,
940 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
943 IWineD3DVolumeTextureImpl *object;
944 unsigned int i;
945 UINT tmpW;
946 UINT tmpH;
947 UINT tmpD;
949 /* TODO: It should only be possible to create textures for formats
950 that are reported as supported */
951 if (WINED3DFMT_UNKNOWN >= Format) {
952 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
953 return WINED3DERR_INVALIDCALL;
956 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
957 D3DINITIALIZEBASETEXTURE(object->baseTexture);
959 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
960 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
962 object->width = Width;
963 object->height = Height;
964 object->depth = Depth;
966 /* Calculate levels for mip mapping */
967 if (Levels == 0) {
968 object->baseTexture.levels++;
969 tmpW = Width;
970 tmpH = Height;
971 tmpD = Depth;
972 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
973 tmpW = max(1, tmpW >> 1);
974 tmpH = max(1, tmpH >> 1);
975 tmpD = max(1, tmpD >> 1);
976 object->baseTexture.levels++;
978 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
981 /* Generate all the surfaces */
982 tmpW = Width;
983 tmpH = Height;
984 tmpD = Depth;
986 for (i = 0; i < object->baseTexture.levels; i++)
988 HRESULT hr;
989 /* Create the volume */
990 hr = D3DCB_CreateVolume(This->parent, parent, Width, Height, Depth, Format, Pool, Usage,
991 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
993 if(FAILED(hr)) {
994 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
995 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
996 *ppVolumeTexture = NULL;
997 return hr;
1000 /* Set its container to this object */
1001 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1003 /* calcualte the next mipmap level */
1004 tmpW = max(1, tmpW >> 1);
1005 tmpH = max(1, tmpH >> 1);
1006 tmpD = max(1, tmpD >> 1);
1009 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1010 TRACE("(%p) : Created volume texture %p\n", This, object);
1011 return WINED3D_OK;
1014 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1015 UINT Width, UINT Height, UINT Depth,
1016 DWORD Usage,
1017 WINED3DFORMAT Format, WINED3DPOOL Pool,
1018 IWineD3DVolume** ppVolume,
1019 HANDLE* pSharedHandle, IUnknown *parent) {
1021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1022 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1023 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1025 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1027 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1028 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1030 object->currentDesc.Width = Width;
1031 object->currentDesc.Height = Height;
1032 object->currentDesc.Depth = Depth;
1033 object->bytesPerPixel = formatDesc->bpp;
1035 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1036 object->lockable = TRUE;
1037 object->locked = FALSE;
1038 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1039 object->dirty = TRUE;
1041 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1044 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1045 UINT Levels, DWORD Usage,
1046 WINED3DFORMAT Format, WINED3DPOOL Pool,
1047 IWineD3DCubeTexture **ppCubeTexture,
1048 HANDLE *pSharedHandle, IUnknown *parent,
1049 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1052 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1053 unsigned int i, j;
1054 UINT tmpW;
1055 HRESULT hr;
1056 unsigned int pow2EdgeLength = EdgeLength;
1058 /* TODO: It should only be possible to create textures for formats
1059 that are reported as supported */
1060 if (WINED3DFMT_UNKNOWN >= Format) {
1061 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1062 return WINED3DERR_INVALIDCALL;
1065 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1066 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1068 TRACE("(%p) Create Cube Texture\n", This);
1070 /** Non-power2 support **/
1072 /* Find the nearest pow2 match */
1073 pow2EdgeLength = 1;
1074 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1076 object->edgeLength = EdgeLength;
1077 /* TODO: support for native non-power 2 */
1078 /* Precalculated scaling for 'faked' non power of two texture coords */
1079 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1081 /* Calculate levels for mip mapping */
1082 if (Levels == 0) {
1083 object->baseTexture.levels++;
1084 tmpW = EdgeLength;
1085 while (tmpW > 1) {
1086 tmpW = max(1, tmpW >> 1);
1087 object->baseTexture.levels++;
1089 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1092 /* Generate all the surfaces */
1093 tmpW = EdgeLength;
1094 for (i = 0; i < object->baseTexture.levels; i++) {
1096 /* Create the 6 faces */
1097 for (j = 0; j < 6; j++) {
1099 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1100 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1102 if(hr!= WINED3D_OK) {
1103 /* clean up */
1104 int k;
1105 int l;
1106 for (l = 0; l < j; l++) {
1107 IWineD3DSurface_Release(object->surfaces[j][i]);
1109 for (k = 0; k < i; k++) {
1110 for (l = 0; l < 6; l++) {
1111 IWineD3DSurface_Release(object->surfaces[l][j]);
1115 FIXME("(%p) Failed to create surface\n",object);
1116 HeapFree(GetProcessHeap(),0,object);
1117 *ppCubeTexture = NULL;
1118 return hr;
1120 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1121 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1123 tmpW = max(1, tmpW >> 1);
1126 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1127 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1128 return WINED3D_OK;
1131 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1133 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1134 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1136 /* Just a check to see if we support this type of query */
1137 switch(Type) {
1138 case WINED3DQUERYTYPE_OCCLUSION:
1139 TRACE("(%p) occlusion query\n", This);
1140 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1141 hr = WINED3D_OK;
1142 else
1143 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1144 break;
1146 case WINED3DQUERYTYPE_EVENT:
1147 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1148 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1150 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1151 hr = WINED3D_OK;
1152 break;
1154 case WINED3DQUERYTYPE_VCACHE:
1155 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1156 case WINED3DQUERYTYPE_VERTEXSTATS:
1157 case WINED3DQUERYTYPE_TIMESTAMP:
1158 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1159 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1160 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1161 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1162 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1163 case WINED3DQUERYTYPE_PIXELTIMINGS:
1164 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1165 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1166 default:
1167 FIXME("(%p) Unhandled query type %d\n", This, Type);
1169 if(NULL == ppQuery || hr != WINED3D_OK) {
1170 return hr;
1173 D3DCREATEOBJECTINSTANCE(object, Query)
1174 object->type = Type;
1175 /* allocated the 'extended' data based on the type of query requested */
1176 switch(Type){
1177 case WINED3DQUERYTYPE_OCCLUSION:
1178 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1179 TRACE("(%p) Allocating data for an occlusion query\n", This);
1180 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1181 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1182 break;
1184 case WINED3DQUERYTYPE_VCACHE:
1185 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1186 case WINED3DQUERYTYPE_VERTEXSTATS:
1187 case WINED3DQUERYTYPE_EVENT:
1188 case WINED3DQUERYTYPE_TIMESTAMP:
1189 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1190 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1191 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1192 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1193 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1194 case WINED3DQUERYTYPE_PIXELTIMINGS:
1195 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1196 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1197 default:
1198 object->extendedData = 0;
1199 FIXME("(%p) Unhandled query type %d\n",This , Type);
1201 TRACE("(%p) : Created Query %p\n", This, object);
1202 return WINED3D_OK;
1205 /*****************************************************************************
1206 * IWineD3DDeviceImpl_SetupFullscreenWindow
1208 * Helper function that modifies a HWND's Style and ExStyle for proper
1209 * fullscreen use.
1211 * Params:
1212 * iface: Pointer to the IWineD3DDevice interface
1213 * window: Window to setup
1215 *****************************************************************************/
1216 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1219 LONG style, exStyle;
1220 /* Don't do anything if an original style is stored.
1221 * That shouldn't happen
1223 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1224 if (This->style || This->exStyle) {
1225 ERR("(%p): Want to change the window parameters of HWND %p, but "
1226 "another style is stored for restoration afterwards\n", This, window);
1229 /* Get the parameters and save them */
1230 style = GetWindowLongW(window, GWL_STYLE);
1231 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1232 This->style = style;
1233 This->exStyle = exStyle;
1235 /* Filter out window decorations */
1236 style &= ~WS_CAPTION;
1237 style &= ~WS_THICKFRAME;
1238 exStyle &= ~WS_EX_WINDOWEDGE;
1239 exStyle &= ~WS_EX_CLIENTEDGE;
1241 /* Make sure the window is managed, otherwise we won't get keyboard input */
1242 style |= WS_POPUP | WS_SYSMENU;
1244 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1245 This->style, This->exStyle, style, exStyle);
1247 SetWindowLongW(window, GWL_STYLE, style);
1248 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1250 /* Inform the window about the update. */
1251 SetWindowPos(window, HWND_TOP, 0, 0,
1252 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1253 ShowWindow(window, TRUE);
1256 /*****************************************************************************
1257 * IWineD3DDeviceImpl_RestoreWindow
1259 * Helper function that restores a windows' properties when taking it out
1260 * of fullscreen mode
1262 * Params:
1263 * iface: Pointer to the IWineD3DDevice interface
1264 * window: Window to setup
1266 *****************************************************************************/
1267 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1270 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1271 * switch, do nothing
1273 if (!This->style && !This->exStyle) return;
1275 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1276 This, window, This->style, This->exStyle);
1278 SetWindowLongW(window, GWL_STYLE, This->style);
1279 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1281 /* Delete the old values */
1282 This->style = 0;
1283 This->exStyle = 0;
1285 /* Inform the window about the update */
1286 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1287 0, 0, 0, 0, /* Pos, Size, ignored */
1288 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1291 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1292 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1293 IUnknown* parent,
1294 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1295 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1298 HDC hDc;
1299 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1300 HRESULT hr = WINED3D_OK;
1301 IUnknown *bufferParent;
1302 Display *display;
1304 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1306 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1307 * does a device hold a reference to a swap chain giving them a lifetime of the device
1308 * or does the swap chain notify the device of its destruction.
1309 *******************************/
1311 /* Check the params */
1312 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1313 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1314 return WINED3DERR_INVALIDCALL;
1315 } else if (pPresentationParameters->BackBufferCount > 1) {
1316 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");
1319 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1321 /*********************
1322 * Lookup the window Handle and the relating X window handle
1323 ********************/
1325 /* Setup hwnd we are using, plus which display this equates to */
1326 object->win_handle = pPresentationParameters->hDeviceWindow;
1327 if (!object->win_handle) {
1328 object->win_handle = This->createParms.hFocusWindow;
1331 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1332 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1333 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1334 return WINED3DERR_NOTAVAILABLE;
1336 hDc = GetDC(object->win_handle);
1337 display = get_display(hDc);
1338 ReleaseDC(object->win_handle, hDc);
1339 TRACE("Using a display of %p %p\n", display, hDc);
1341 if (NULL == display || NULL == hDc) {
1342 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1343 return WINED3DERR_NOTAVAILABLE;
1346 if (object->win == 0) {
1347 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1348 return WINED3DERR_NOTAVAILABLE;
1351 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1352 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1353 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1355 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1356 * then the corresponding dimension of the client area of the hDeviceWindow
1357 * (or the focus window, if hDeviceWindow is NULL) is taken.
1358 **********************/
1360 if (pPresentationParameters->Windowed &&
1361 ((pPresentationParameters->BackBufferWidth == 0) ||
1362 (pPresentationParameters->BackBufferHeight == 0))) {
1364 RECT Rect;
1365 GetClientRect(object->win_handle, &Rect);
1367 if (pPresentationParameters->BackBufferWidth == 0) {
1368 pPresentationParameters->BackBufferWidth = Rect.right;
1369 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1371 if (pPresentationParameters->BackBufferHeight == 0) {
1372 pPresentationParameters->BackBufferHeight = Rect.bottom;
1373 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1377 /* Put the correct figures in the presentation parameters */
1378 TRACE("Copying across presentation parameters\n");
1379 object->presentParms = *pPresentationParameters;
1381 TRACE("calling rendertarget CB\n");
1382 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1383 parent,
1384 object->presentParms.BackBufferWidth,
1385 object->presentParms.BackBufferHeight,
1386 object->presentParms.BackBufferFormat,
1387 object->presentParms.MultiSampleType,
1388 object->presentParms.MultiSampleQuality,
1389 TRUE /* Lockable */,
1390 &object->frontBuffer,
1391 NULL /* pShared (always null)*/);
1392 if (object->frontBuffer != NULL) {
1393 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1394 } else {
1395 ERR("Failed to create the front buffer\n");
1396 goto error;
1400 * Create an opengl context for the display visual
1401 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1402 * use different properties after that point in time. FIXME: How to handle when requested format
1403 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1404 * it chooses is identical to the one already being used!
1405 **********************************/
1407 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1408 ENTER_GL();
1409 object->context = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1410 LEAVE_GL();
1412 if (!object->context) {
1413 ERR("Failed to create a new context\n");
1414 hr = WINED3DERR_NOTAVAILABLE;
1415 goto error;
1416 } else {
1417 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1418 object->win_handle, object->context->glCtx, object->win);
1421 /*********************
1422 * Windowed / Fullscreen
1423 *******************/
1426 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1427 * so we should really check to see if there is a fullscreen swapchain already
1428 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1429 **************************************/
1431 if (!pPresentationParameters->Windowed) {
1433 DEVMODEW devmode;
1434 HDC hdc;
1435 int bpp = 0;
1436 RECT clip_rc;
1438 /* Get info on the current display setup */
1439 hdc = GetDC(0);
1440 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1441 ReleaseDC(0, hdc);
1443 /* Change the display settings */
1444 memset(&devmode, 0, sizeof(DEVMODEW));
1445 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1446 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1447 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1448 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1449 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1450 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1452 /* For GetDisplayMode */
1453 This->ddraw_width = devmode.dmPelsWidth;
1454 This->ddraw_height = devmode.dmPelsHeight;
1455 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1457 IWineD3DDevice_SetFullscreen(iface, TRUE);
1459 /* And finally clip mouse to our screen */
1460 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1461 ClipCursor(&clip_rc);
1464 /*********************
1465 * Create the back, front and stencil buffers
1466 *******************/
1467 if(object->presentParms.BackBufferCount > 0) {
1468 int i;
1470 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1471 if(!object->backBuffer) {
1472 ERR("Out of memory\n");
1473 hr = E_OUTOFMEMORY;
1474 goto error;
1477 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1478 TRACE("calling rendertarget CB\n");
1479 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1480 parent,
1481 object->presentParms.BackBufferWidth,
1482 object->presentParms.BackBufferHeight,
1483 object->presentParms.BackBufferFormat,
1484 object->presentParms.MultiSampleType,
1485 object->presentParms.MultiSampleQuality,
1486 TRUE /* Lockable */,
1487 &object->backBuffer[i],
1488 NULL /* pShared (always null)*/);
1489 if(hr == WINED3D_OK && object->backBuffer[i]) {
1490 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1491 } else {
1492 ERR("Cannot create new back buffer\n");
1493 goto error;
1495 ENTER_GL();
1496 glDrawBuffer(GL_BACK);
1497 checkGLcall("glDrawBuffer(GL_BACK)");
1498 LEAVE_GL();
1500 } else {
1501 object->backBuffer = NULL;
1503 /* Single buffering - draw to front buffer */
1504 ENTER_GL();
1505 glDrawBuffer(GL_FRONT);
1506 checkGLcall("glDrawBuffer(GL_FRONT)");
1507 LEAVE_GL();
1510 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1511 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1512 TRACE("Creating depth stencil buffer\n");
1513 if (This->depthStencilBuffer == NULL ) {
1514 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1515 parent,
1516 object->presentParms.BackBufferWidth,
1517 object->presentParms.BackBufferHeight,
1518 object->presentParms.AutoDepthStencilFormat,
1519 object->presentParms.MultiSampleType,
1520 object->presentParms.MultiSampleQuality,
1521 FALSE /* FIXME: Discard */,
1522 &This->depthStencilBuffer,
1523 NULL /* pShared (always null)*/ );
1524 if (This->depthStencilBuffer != NULL)
1525 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1528 /** TODO: A check on width, height and multisample types
1529 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1530 ****************************/
1531 object->wantsDepthStencilBuffer = TRUE;
1532 } else {
1533 object->wantsDepthStencilBuffer = FALSE;
1536 TRACE("Created swapchain %p\n", object);
1537 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1538 return WINED3D_OK;
1540 error:
1541 if (object->backBuffer) {
1542 int i;
1543 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1544 if(object->backBuffer[i]) {
1545 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1546 IUnknown_Release(bufferParent); /* once for the get parent */
1547 if (IUnknown_Release(bufferParent) > 0) {
1548 FIXME("(%p) Something's still holding the back buffer\n",This);
1552 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1553 object->backBuffer = NULL;
1555 if(object->context) {
1556 DestroyContext(This, object->context);
1558 if(object->frontBuffer) {
1559 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1560 IUnknown_Release(bufferParent); /* once for the get parent */
1561 if (IUnknown_Release(bufferParent) > 0) {
1562 FIXME("(%p) Something's still holding the front buffer\n",This);
1565 if(object) HeapFree(GetProcessHeap(), 0, object);
1566 return hr;
1569 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1570 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1572 TRACE("(%p)\n", This);
1574 return This->NumberOfSwapChains;
1577 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1579 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1581 if(iSwapChain < This->NumberOfSwapChains) {
1582 *pSwapChain = This->swapchains[iSwapChain];
1583 IWineD3DSwapChain_AddRef(*pSwapChain);
1584 TRACE("(%p) returning %p\n", This, *pSwapChain);
1585 return WINED3D_OK;
1586 } else {
1587 TRACE("Swapchain out of range\n");
1588 *pSwapChain = NULL;
1589 return WINED3DERR_INVALIDCALL;
1593 /*****
1594 * Vertex Declaration
1595 *****/
1596 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1597 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1599 IWineD3DVertexDeclarationImpl *object = NULL;
1600 HRESULT hr = WINED3D_OK;
1602 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1603 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1605 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1606 object->allFVF = 0;
1608 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1610 return hr;
1613 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1614 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1616 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1617 HRESULT hr = WINED3D_OK;
1618 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1619 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1621 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1623 if (vertex_declaration) {
1624 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1627 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1629 if (WINED3D_OK != hr) {
1630 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1631 IWineD3DVertexShader_Release(*ppVertexShader);
1632 return WINED3DERR_INVALIDCALL;
1635 return WINED3D_OK;
1638 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1640 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1641 HRESULT hr = WINED3D_OK;
1643 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1644 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1645 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1646 if (WINED3D_OK == hr) {
1647 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1648 } else {
1649 WARN("(%p) : Failed to create pixel shader\n", This);
1652 return hr;
1655 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1657 IWineD3DPaletteImpl *object;
1658 HRESULT hr;
1659 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1661 /* Create the new object */
1662 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1663 if(!object) {
1664 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1665 return E_OUTOFMEMORY;
1668 object->lpVtbl = &IWineD3DPalette_Vtbl;
1669 object->ref = 1;
1670 object->Flags = Flags;
1671 object->parent = Parent;
1672 object->wineD3DDevice = This;
1673 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1675 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1677 if(!object->hpal) {
1678 HeapFree( GetProcessHeap(), 0, object);
1679 return E_OUTOFMEMORY;
1682 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1683 if(FAILED(hr)) {
1684 IWineD3DPalette_Release((IWineD3DPalette *) object);
1685 return hr;
1688 *Palette = (IWineD3DPalette *) object;
1690 return WINED3D_OK;
1693 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1695 IWineD3DSwapChainImpl *swapchain;
1696 DWORD state;
1698 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1699 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1701 /* TODO: Test if OpenGL is compiled in and loaded */
1703 /* Initialize the texture unit mapping to a 1:1 mapping */
1704 for(state = 0; state < MAX_SAMPLERS; state++) {
1705 This->texUnitMap[state] = state;
1707 This->oneToOneTexUnitMap = TRUE;
1709 /* Setup the implicit swapchain */
1710 TRACE("Creating implicit swapchain\n");
1711 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain)) || !swapchain) {
1712 WARN("Failed to create implicit swapchain\n");
1713 return WINED3DERR_INVALIDCALL;
1716 This->NumberOfSwapChains = 1;
1717 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1718 if(!This->swapchains) {
1719 ERR("Out of memory!\n");
1720 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1721 return E_OUTOFMEMORY;
1723 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1725 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1727 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1728 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1729 This->render_targets[0] = swapchain->backBuffer[0];
1730 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1732 else {
1733 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1734 This->render_targets[0] = swapchain->frontBuffer;
1735 This->lastActiveRenderTarget = swapchain->frontBuffer;
1737 IWineD3DSurface_AddRef(This->render_targets[0]);
1738 This->activeContext = swapchain->context;
1740 /* Depth Stencil support */
1741 This->stencilBufferTarget = This->depthStencilBuffer;
1742 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1743 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
1745 if (NULL != This->stencilBufferTarget) {
1746 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1749 /* Set up some starting GL setup */
1750 ENTER_GL();
1752 * Initialize openGL extension related variables
1753 * with Default values
1756 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->context->display);
1757 /* Setup all the devices defaults */
1758 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1759 #if 0
1760 IWineD3DImpl_CheckGraphicsMemory();
1761 #endif
1763 /* Initialize our list of GLSL programs */
1764 list_init(&This->glsl_shader_progs);
1766 { /* Set a default viewport */
1767 WINED3DVIEWPORT vp;
1768 vp.X = 0;
1769 vp.Y = 0;
1770 vp.Width = pPresentationParameters->BackBufferWidth;
1771 vp.Height = pPresentationParameters->BackBufferHeight;
1772 vp.MinZ = 0.0f;
1773 vp.MaxZ = 1.0f;
1774 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1777 /* Initialize the current view state */
1778 This->view_ident = 1;
1779 This->contexts[0]->last_was_rhw = 0;
1780 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1781 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1782 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1783 LEAVE_GL();
1785 /* Clear the screen */
1786 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
1788 This->d3d_initialized = TRUE;
1789 return WINED3D_OK;
1792 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1794 int sampler;
1795 uint i;
1796 TRACE("(%p)\n", This);
1798 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1800 /* Delete the pbuffer context if there is any */
1801 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1803 /* Delete the mouse cursor texture */
1804 if(This->cursorTexture) {
1805 ENTER_GL();
1806 glDeleteTextures(1, &This->cursorTexture);
1807 LEAVE_GL();
1808 This->cursorTexture = 0;
1811 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1812 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1815 /* Release the buffers (with sanity checks)*/
1816 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1817 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1818 if(This->depthStencilBuffer != This->stencilBufferTarget)
1819 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1821 This->stencilBufferTarget = NULL;
1823 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1824 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1825 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1827 TRACE("Setting rendertarget to NULL\n");
1828 This->render_targets[0] = NULL;
1830 if (This->depthStencilBuffer) {
1831 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1832 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1834 This->depthStencilBuffer = NULL;
1837 for(i=0; i < This->NumberOfSwapChains; i++) {
1838 TRACE("Releasing the implicit swapchain %d\n", i);
1839 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1840 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1844 HeapFree(GetProcessHeap(), 0, This->swapchains);
1845 This->swapchains = NULL;
1846 This->NumberOfSwapChains = 0;
1848 This->d3d_initialized = FALSE;
1849 return WINED3D_OK;
1852 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1854 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1856 /* Setup the window for fullscreen mode */
1857 if(fullscreen && !This->ddraw_fullscreen) {
1858 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1859 } else if(!fullscreen && This->ddraw_fullscreen) {
1860 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1863 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1864 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1865 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1866 * separately.
1868 This->ddraw_fullscreen = fullscreen;
1871 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
1872 DEVMODEW devmode;
1873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1874 LONG ret;
1875 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
1876 RECT clip_rc;
1878 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1880 /* Resize the screen even without a window:
1881 * The app could have unset it with SetCooperativeLevel, but not called
1882 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1883 * but we don't have any hwnd
1886 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1887 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1888 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
1889 devmode.dmPelsWidth = pMode->Width;
1890 devmode.dmPelsHeight = pMode->Height;
1892 devmode.dmDisplayFrequency = pMode->RefreshRate;
1893 if (pMode->RefreshRate != 0) {
1894 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1897 /* Only change the mode if necessary */
1898 if( (This->ddraw_width == pMode->Width) &&
1899 (This->ddraw_height == pMode->Height) &&
1900 (This->ddraw_format == pMode->Format) &&
1901 (pMode->RefreshRate == 0) ) {
1902 return WINED3D_OK;
1905 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1906 if (ret != DISP_CHANGE_SUCCESSFUL) {
1907 if(devmode.dmDisplayFrequency != 0) {
1908 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1909 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1910 devmode.dmDisplayFrequency = 0;
1911 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1913 if(ret != DISP_CHANGE_SUCCESSFUL) {
1914 return DDERR_INVALIDMODE;
1918 /* Store the new values */
1919 This->ddraw_width = pMode->Width;
1920 This->ddraw_height = pMode->Height;
1921 This->ddraw_format = pMode->Format;
1923 /* Only do this with a window of course */
1924 if(This->ddraw_window)
1925 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
1927 /* And finally clip mouse to our screen */
1928 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1929 ClipCursor(&clip_rc);
1931 return WINED3D_OK;
1934 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1936 *ppD3D= This->wineD3D;
1937 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
1938 IWineD3D_AddRef(*ppD3D);
1939 return WINED3D_OK;
1942 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1943 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
1944 * into the video ram as possible and seeing how many fit
1945 * you can also get the correct initial value from nvidia and ATI's driver via X
1946 * texture memory is video memory + AGP memory
1947 *******************/
1948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1949 static BOOL showfixmes = TRUE;
1950 if (showfixmes) {
1951 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
1952 (wined3d_settings.emulated_textureram/(1024*1024)),
1953 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1954 showfixmes = FALSE;
1956 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1957 (wined3d_settings.emulated_textureram/(1024*1024)),
1958 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1959 /* return simulated texture memory left */
1960 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
1965 /*****
1966 * Get / Set FVF
1967 *****/
1968 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
1969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1971 /* Update the current state block */
1972 This->updateStateBlock->changed.fvf = TRUE;
1973 This->updateStateBlock->set.fvf = TRUE;
1975 if(This->updateStateBlock->fvf == fvf) {
1976 TRACE("Application is setting the old fvf over, nothing to do\n");
1977 return WINED3D_OK;
1980 This->updateStateBlock->fvf = fvf;
1981 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
1982 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
1983 return WINED3D_OK;
1987 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
1988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1989 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
1990 *pfvf = This->stateBlock->fvf;
1991 return WINED3D_OK;
1994 /*****
1995 * Get / Set Stream Source
1996 *****/
1997 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
1998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1999 IWineD3DVertexBuffer *oldSrc;
2001 if (StreamNumber >= MAX_STREAMS) {
2002 WARN("Stream out of range %d\n", StreamNumber);
2003 return WINED3DERR_INVALIDCALL;
2006 oldSrc = This->stateBlock->streamSource[StreamNumber];
2007 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2009 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2010 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2012 if(oldSrc == pStreamData &&
2013 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2014 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2015 TRACE("Application is setting the old values over, nothing to do\n");
2016 return WINED3D_OK;
2019 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2020 if (pStreamData) {
2021 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2022 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2025 /* Handle recording of state blocks */
2026 if (This->isRecordingState) {
2027 TRACE("Recording... not performing anything\n");
2028 return WINED3D_OK;
2031 /* Need to do a getParent and pass the reffs up */
2032 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2033 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2034 so for now, just count internally */
2035 if (pStreamData != NULL) {
2036 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2037 InterlockedIncrement(&vbImpl->bindCount);
2039 if (oldSrc != NULL) {
2040 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2043 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2045 return WINED3D_OK;
2048 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2051 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2052 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2054 if (StreamNumber >= MAX_STREAMS) {
2055 WARN("Stream out of range %d\n", StreamNumber);
2056 return WINED3DERR_INVALIDCALL;
2058 *pStream = This->stateBlock->streamSource[StreamNumber];
2059 *pStride = This->stateBlock->streamStride[StreamNumber];
2060 if (pOffset) {
2061 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2064 if (*pStream != NULL) {
2065 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2067 return WINED3D_OK;
2070 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2072 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2073 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2075 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2076 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2078 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2079 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2080 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2082 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2083 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2084 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2087 return WINED3D_OK;
2090 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2093 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2094 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2096 TRACE("(%p) : returning %d\n", This, *Divider);
2098 return WINED3D_OK;
2101 /*****
2102 * Get / Set & Multiply Transform
2103 *****/
2104 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2107 /* Most of this routine, comments included copied from ddraw tree initially: */
2108 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2110 /* Handle recording of state blocks */
2111 if (This->isRecordingState) {
2112 TRACE("Recording... not performing anything\n");
2113 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2114 This->updateStateBlock->set.transform[d3dts] = TRUE;
2115 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2116 return WINED3D_OK;
2120 * If the new matrix is the same as the current one,
2121 * we cut off any further processing. this seems to be a reasonable
2122 * optimization because as was noticed, some apps (warcraft3 for example)
2123 * tend towards setting the same matrix repeatedly for some reason.
2125 * From here on we assume that the new matrix is different, wherever it matters.
2127 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2128 TRACE("The app is setting the same matrix over again\n");
2129 return WINED3D_OK;
2130 } else {
2131 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2135 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2136 where ViewMat = Camera space, WorldMat = world space.
2138 In OpenGL, camera and world space is combined into GL_MODELVIEW
2139 matrix. The Projection matrix stay projection matrix.
2142 /* Capture the times we can just ignore the change for now */
2143 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2144 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2145 /* Handled by the state manager */
2148 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2149 return WINED3D_OK;
2152 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2154 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2155 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2156 return WINED3D_OK;
2159 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2160 WINED3DMATRIX *mat = NULL;
2161 WINED3DMATRIX temp;
2163 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2164 * below means it will be recorded in a state block change, but it
2165 * works regardless where it is recorded.
2166 * If this is found to be wrong, change to StateBlock.
2168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2169 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2171 if (State < HIGHEST_TRANSFORMSTATE)
2173 mat = &This->updateStateBlock->transforms[State];
2174 } else {
2175 FIXME("Unhandled transform state!!\n");
2178 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2180 /* Apply change via set transform - will reapply to eg. lights this way */
2181 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2184 /*****
2185 * Get / Set Light
2186 *****/
2187 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2188 you can reference any indexes you want as long as that number max are enabled at any
2189 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2190 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2191 but when recording, just build a chain pretty much of commands to be replayed. */
2193 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2194 float rho;
2195 PLIGHTINFOEL *object = NULL;
2196 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2197 struct list *e;
2199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2200 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2202 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2203 * the gl driver.
2205 if(!pLight) {
2206 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2207 return WINED3DERR_INVALIDCALL;
2210 switch(pLight->Type) {
2211 case WINED3DLIGHT_POINT:
2212 case WINED3DLIGHT_SPOT:
2213 case WINED3DLIGHT_PARALLELPOINT:
2214 case WINED3DLIGHT_GLSPOT:
2215 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2216 * most wanted
2218 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2219 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2220 return WINED3DERR_INVALIDCALL;
2222 break;
2224 case WINED3DLIGHT_DIRECTIONAL:
2225 /* Ignores attenuation */
2226 break;
2228 default:
2229 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2230 return WINED3DERR_INVALIDCALL;
2233 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2234 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2235 if(object->OriginalIndex == Index) break;
2236 object = NULL;
2239 if(!object) {
2240 TRACE("Adding new light\n");
2241 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2242 if(!object) {
2243 ERR("Out of memory error when allocating a light\n");
2244 return E_OUTOFMEMORY;
2246 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2247 object->glIndex = -1;
2248 object->OriginalIndex = Index;
2249 object->changed = TRUE;
2252 /* Initialize the object */
2253 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,
2254 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2255 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2256 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2257 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2258 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2259 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2261 /* Save away the information */
2262 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2264 switch (pLight->Type) {
2265 case WINED3DLIGHT_POINT:
2266 /* Position */
2267 object->lightPosn[0] = pLight->Position.x;
2268 object->lightPosn[1] = pLight->Position.y;
2269 object->lightPosn[2] = pLight->Position.z;
2270 object->lightPosn[3] = 1.0f;
2271 object->cutoff = 180.0f;
2272 /* FIXME: Range */
2273 break;
2275 case WINED3DLIGHT_DIRECTIONAL:
2276 /* Direction */
2277 object->lightPosn[0] = -pLight->Direction.x;
2278 object->lightPosn[1] = -pLight->Direction.y;
2279 object->lightPosn[2] = -pLight->Direction.z;
2280 object->lightPosn[3] = 0.0;
2281 object->exponent = 0.0f;
2282 object->cutoff = 180.0f;
2283 break;
2285 case WINED3DLIGHT_SPOT:
2286 /* Position */
2287 object->lightPosn[0] = pLight->Position.x;
2288 object->lightPosn[1] = pLight->Position.y;
2289 object->lightPosn[2] = pLight->Position.z;
2290 object->lightPosn[3] = 1.0;
2292 /* Direction */
2293 object->lightDirn[0] = pLight->Direction.x;
2294 object->lightDirn[1] = pLight->Direction.y;
2295 object->lightDirn[2] = pLight->Direction.z;
2296 object->lightDirn[3] = 1.0;
2299 * opengl-ish and d3d-ish spot lights use too different models for the
2300 * light "intensity" as a function of the angle towards the main light direction,
2301 * so we only can approximate very roughly.
2302 * however spot lights are rather rarely used in games (if ever used at all).
2303 * furthermore if still used, probably nobody pays attention to such details.
2305 if (pLight->Falloff == 0) {
2306 rho = 6.28f;
2307 } else {
2308 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2310 if (rho < 0.0001) rho = 0.0001f;
2311 object->exponent = -0.3/log(cos(rho/2));
2312 if (object->exponent > 128.0) {
2313 object->exponent = 128.0;
2315 object->cutoff = pLight->Phi*90/M_PI;
2317 /* FIXME: Range */
2318 break;
2320 default:
2321 FIXME("Unrecognized light type %d\n", pLight->Type);
2324 /* Update the live definitions if the light is currently assigned a glIndex */
2325 if (object->glIndex != -1 && !This->isRecordingState) {
2326 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2328 return WINED3D_OK;
2331 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2332 PLIGHTINFOEL *lightInfo = NULL;
2333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2334 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2335 struct list *e;
2336 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2338 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2339 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2340 if(lightInfo->OriginalIndex == Index) break;
2341 lightInfo = NULL;
2344 if (lightInfo == NULL) {
2345 TRACE("Light information requested but light not defined\n");
2346 return WINED3DERR_INVALIDCALL;
2349 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2350 return WINED3D_OK;
2353 /*****
2354 * Get / Set Light Enable
2355 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2356 *****/
2357 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2358 PLIGHTINFOEL *lightInfo = NULL;
2359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2360 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2361 struct list *e;
2362 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2364 /* Tests show true = 128...not clear why */
2365 Enable = Enable? 128: 0;
2367 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2368 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2369 if(lightInfo->OriginalIndex == Index) break;
2370 lightInfo = NULL;
2372 TRACE("Found light: %p\n", lightInfo);
2374 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2375 if (lightInfo == NULL) {
2377 TRACE("Light enabled requested but light not defined, so defining one!\n");
2378 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2380 /* Search for it again! Should be fairly quick as near head of list */
2381 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2382 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2383 if(lightInfo->OriginalIndex == Index) break;
2384 lightInfo = NULL;
2386 if (lightInfo == NULL) {
2387 FIXME("Adding default lights has failed dismally\n");
2388 return WINED3DERR_INVALIDCALL;
2392 lightInfo->enabledChanged = TRUE;
2393 if(!Enable) {
2394 if(lightInfo->glIndex != -1) {
2395 if(!This->isRecordingState) {
2396 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2399 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2400 lightInfo->glIndex = -1;
2401 } else {
2402 TRACE("Light already disabled, nothing to do\n");
2404 } else {
2405 if (lightInfo->glIndex != -1) {
2406 /* nop */
2407 TRACE("Nothing to do as light was enabled\n");
2408 } else {
2409 int i;
2410 /* Find a free gl light */
2411 for(i = 0; i < This->maxConcurrentLights; i++) {
2412 if(This->stateBlock->activeLights[i] == NULL) {
2413 This->stateBlock->activeLights[i] = lightInfo;
2414 lightInfo->glIndex = i;
2415 break;
2418 if(lightInfo->glIndex == -1) {
2419 ERR("Too many concurrently active lights\n");
2420 return WINED3DERR_INVALIDCALL;
2423 /* i == lightInfo->glIndex */
2424 if(!This->isRecordingState) {
2425 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2430 return WINED3D_OK;
2433 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2435 PLIGHTINFOEL *lightInfo = NULL;
2436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2437 struct list *e;
2438 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2439 TRACE("(%p) : for idx(%d)\n", This, Index);
2441 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2442 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2443 if(lightInfo->OriginalIndex == Index) break;
2444 lightInfo = NULL;
2447 if (lightInfo == NULL) {
2448 TRACE("Light enabled state requested but light not defined\n");
2449 return WINED3DERR_INVALIDCALL;
2451 /* true is 128 according to SetLightEnable */
2452 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2453 return WINED3D_OK;
2456 /*****
2457 * Get / Set Clip Planes
2458 *****/
2459 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2461 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2463 /* Validate Index */
2464 if (Index >= GL_LIMITS(clipplanes)) {
2465 TRACE("Application has requested clipplane this device doesn't support\n");
2466 return WINED3DERR_INVALIDCALL;
2469 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2470 This->updateStateBlock->set.clipplane[Index] = TRUE;
2471 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2472 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2473 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2474 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2476 /* Handle recording of state blocks */
2477 if (This->isRecordingState) {
2478 TRACE("Recording... not performing anything\n");
2479 return WINED3D_OK;
2482 /* Apply it */
2484 ENTER_GL();
2486 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2487 glMatrixMode(GL_MODELVIEW);
2488 glPushMatrix();
2489 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
2491 TRACE("Clipplane [%f,%f,%f,%f]\n",
2492 This->updateStateBlock->clipplane[Index][0],
2493 This->updateStateBlock->clipplane[Index][1],
2494 This->updateStateBlock->clipplane[Index][2],
2495 This->updateStateBlock->clipplane[Index][3]);
2496 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
2497 checkGLcall("glClipPlane");
2499 glPopMatrix();
2500 LEAVE_GL();
2502 return WINED3D_OK;
2505 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2507 TRACE("(%p) : for idx %d\n", This, Index);
2509 /* Validate Index */
2510 if (Index >= GL_LIMITS(clipplanes)) {
2511 TRACE("Application has requested clipplane this device doesn't support\n");
2512 return WINED3DERR_INVALIDCALL;
2515 pPlane[0] = This->stateBlock->clipplane[Index][0];
2516 pPlane[1] = This->stateBlock->clipplane[Index][1];
2517 pPlane[2] = This->stateBlock->clipplane[Index][2];
2518 pPlane[3] = This->stateBlock->clipplane[Index][3];
2519 return WINED3D_OK;
2522 /*****
2523 * Get / Set Clip Plane Status
2524 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2525 *****/
2526 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2528 FIXME("(%p) : stub\n", This);
2529 if (NULL == pClipStatus) {
2530 return WINED3DERR_INVALIDCALL;
2532 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2533 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2534 return WINED3D_OK;
2537 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2539 FIXME("(%p) : stub\n", This);
2540 if (NULL == pClipStatus) {
2541 return WINED3DERR_INVALIDCALL;
2543 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2544 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2545 return WINED3D_OK;
2548 /*****
2549 * Get / Set Material
2550 *****/
2551 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2554 This->updateStateBlock->changed.material = TRUE;
2555 This->updateStateBlock->set.material = TRUE;
2556 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2558 /* Handle recording of state blocks */
2559 if (This->isRecordingState) {
2560 TRACE("Recording... not performing anything\n");
2561 return WINED3D_OK;
2564 ENTER_GL();
2565 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2566 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2567 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2568 pMaterial->Ambient.b, pMaterial->Ambient.a);
2569 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2570 pMaterial->Specular.b, pMaterial->Specular.a);
2571 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2572 pMaterial->Emissive.b, pMaterial->Emissive.a);
2573 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2575 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2576 checkGLcall("glMaterialfv(GL_AMBIENT)");
2577 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2578 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2580 /* Only change material color if specular is enabled, otherwise it is set to black */
2581 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2582 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2583 checkGLcall("glMaterialfv(GL_SPECULAR");
2584 } else {
2585 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2586 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2587 checkGLcall("glMaterialfv(GL_SPECULAR");
2589 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2590 checkGLcall("glMaterialfv(GL_EMISSION)");
2591 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2592 checkGLcall("glMaterialf(GL_SHININESS");
2594 LEAVE_GL();
2595 return WINED3D_OK;
2598 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2600 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2601 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2602 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2603 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2604 pMaterial->Ambient.b, pMaterial->Ambient.a);
2605 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2606 pMaterial->Specular.b, pMaterial->Specular.a);
2607 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2608 pMaterial->Emissive.b, pMaterial->Emissive.a);
2609 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2611 return WINED3D_OK;
2614 /*****
2615 * Get / Set Indices
2616 *****/
2617 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2618 UINT BaseVertexIndex) {
2619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2620 IWineD3DIndexBuffer *oldIdxs;
2621 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2623 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2624 oldIdxs = This->updateStateBlock->pIndexData;
2626 This->updateStateBlock->changed.indices = TRUE;
2627 This->updateStateBlock->set.indices = TRUE;
2628 This->updateStateBlock->pIndexData = pIndexData;
2629 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2631 /* Handle recording of state blocks */
2632 if (This->isRecordingState) {
2633 TRACE("Recording... not performing anything\n");
2634 return WINED3D_OK;
2637 /* The base vertex index affects the stream sources, while
2638 * The index buffer is a seperate index buffer state
2640 if(BaseVertexIndex != oldBaseIndex) {
2641 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2643 if(oldIdxs != pIndexData) {
2644 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2646 return WINED3D_OK;
2649 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2652 *ppIndexData = This->stateBlock->pIndexData;
2654 /* up ref count on ppindexdata */
2655 if (*ppIndexData) {
2656 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2657 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2658 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2659 }else{
2660 TRACE("(%p) No index data set\n", This);
2662 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2664 return WINED3D_OK;
2667 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2668 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2670 TRACE("(%p)->(%d)\n", This, BaseIndex);
2672 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2673 TRACE("Application is setting the old value over, nothing to do\n");
2674 return WINED3D_OK;
2677 This->updateStateBlock->baseVertexIndex = BaseIndex;
2679 if (This->isRecordingState) {
2680 TRACE("Recording... not performing anything\n");
2681 return WINED3D_OK;
2683 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2684 return WINED3D_OK;
2687 /*****
2688 * Get / Set Viewports
2689 *****/
2690 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2693 TRACE("(%p)\n", This);
2694 This->updateStateBlock->changed.viewport = TRUE;
2695 This->updateStateBlock->set.viewport = TRUE;
2696 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2698 /* Handle recording of state blocks */
2699 if (This->isRecordingState) {
2700 TRACE("Recording... not performing anything\n");
2701 return WINED3D_OK;
2704 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2705 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2707 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2708 return WINED3D_OK;
2712 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2714 TRACE("(%p)\n", This);
2715 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2716 return WINED3D_OK;
2719 /*****
2720 * Get / Set Render States
2721 * TODO: Verify against dx9 definitions
2722 *****/
2723 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2726 DWORD oldValue = This->stateBlock->renderState[State];
2728 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2730 This->updateStateBlock->changed.renderState[State] = TRUE;
2731 This->updateStateBlock->set.renderState[State] = TRUE;
2732 This->updateStateBlock->renderState[State] = Value;
2734 /* Handle recording of state blocks */
2735 if (This->isRecordingState) {
2736 TRACE("Recording... not performing anything\n");
2737 return WINED3D_OK;
2740 /* Compared here and not before the assignment to allow proper stateblock recording */
2741 if(Value == oldValue) {
2742 TRACE("Application is setting the old value over, nothing to do\n");
2743 } else {
2744 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2747 return WINED3D_OK;
2750 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2752 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2753 *pValue = This->stateBlock->renderState[State];
2754 return WINED3D_OK;
2757 /*****
2758 * Get / Set Sampler States
2759 * TODO: Verify against dx9 definitions
2760 *****/
2762 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2764 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2767 * SetSampler is designed to allow for more than the standard up to 8 textures
2768 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2769 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2771 * http://developer.nvidia.com/object/General_FAQ.html#t6
2773 * There are two new settings for GForce
2774 * the sampler one:
2775 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2776 * and the texture one:
2777 * GL_MAX_TEXTURE_COORDS_ARB.
2778 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2779 ******************/
2781 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2782 debug_d3dsamplerstate(Type), Type, Value);
2783 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2784 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2785 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2787 /* Handle recording of state blocks */
2788 if (This->isRecordingState) {
2789 TRACE("Recording... not performing anything\n");
2790 return WINED3D_OK;
2793 if(oldValue == Value) {
2794 TRACE("Application is setting the old value over, nothing to do\n");
2795 return WINED3D_OK;
2798 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2800 return WINED3D_OK;
2803 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2805 *Value = This->stateBlock->samplerState[Sampler][Type];
2806 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2808 return WINED3D_OK;
2811 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2814 This->updateStateBlock->set.scissorRect = TRUE;
2815 This->updateStateBlock->changed.scissorRect = TRUE;
2816 if(memcmp(&This->updateStateBlock->scissorRect, pRect, sizeof(*pRect)) == 0) {
2817 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2818 return WINED3D_OK;
2820 memcpy(&This->updateStateBlock->scissorRect, pRect, sizeof(*pRect));
2822 if(This->isRecordingState) {
2823 TRACE("Recording... not performing anything\n");
2824 return WINED3D_OK;
2827 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2829 return WINED3D_OK;
2832 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2835 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2836 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2837 return WINED3D_OK;
2840 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2842 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2844 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2846 This->updateStateBlock->vertexDecl = pDecl;
2847 This->updateStateBlock->changed.vertexDecl = TRUE;
2848 This->updateStateBlock->set.vertexDecl = TRUE;
2850 if (This->isRecordingState) {
2851 TRACE("Recording... not performing anything\n");
2852 return WINED3D_OK;
2853 } else if(pDecl == oldDecl) {
2854 /* Checked after the assignment to allow proper stateblock recording */
2855 TRACE("Application is setting the old declaration over, nothing to do\n");
2856 return WINED3D_OK;
2859 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2860 return WINED3D_OK;
2863 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2866 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2868 *ppDecl = This->stateBlock->vertexDecl;
2869 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2870 return WINED3D_OK;
2873 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2875 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2877 This->updateStateBlock->vertexShader = pShader;
2878 This->updateStateBlock->changed.vertexShader = TRUE;
2879 This->updateStateBlock->set.vertexShader = TRUE;
2881 if (This->isRecordingState) {
2882 TRACE("Recording... not performing anything\n");
2883 return WINED3D_OK;
2884 } else if(oldShader == pShader) {
2885 /* Checked here to allow proper stateblock recording */
2886 TRACE("App is setting the old shader over, nothing to do\n");
2887 return WINED3D_OK;
2890 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2892 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2894 return WINED3D_OK;
2897 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2900 if (NULL == ppShader) {
2901 return WINED3DERR_INVALIDCALL;
2903 *ppShader = This->stateBlock->vertexShader;
2904 if( NULL != *ppShader)
2905 IWineD3DVertexShader_AddRef(*ppShader);
2907 TRACE("(%p) : returning %p\n", This, *ppShader);
2908 return WINED3D_OK;
2911 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2912 IWineD3DDevice *iface,
2913 UINT start,
2914 CONST BOOL *srcData,
2915 UINT count) {
2917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2918 int i, cnt = min(count, MAX_CONST_B - start);
2920 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2921 iface, srcData, start, count);
2923 if (srcData == NULL || cnt < 0)
2924 return WINED3DERR_INVALIDCALL;
2926 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2927 for (i = 0; i < cnt; i++)
2928 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2930 for (i = start; i < cnt + start; ++i) {
2931 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
2932 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
2935 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2937 return WINED3D_OK;
2940 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2941 IWineD3DDevice *iface,
2942 UINT start,
2943 BOOL *dstData,
2944 UINT count) {
2946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2947 int cnt = min(count, MAX_CONST_B - start);
2949 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2950 iface, dstData, start, count);
2952 if (dstData == NULL || cnt < 0)
2953 return WINED3DERR_INVALIDCALL;
2955 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2956 return WINED3D_OK;
2959 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2960 IWineD3DDevice *iface,
2961 UINT start,
2962 CONST int *srcData,
2963 UINT count) {
2965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2966 int i, cnt = min(count, MAX_CONST_I - start);
2968 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2969 iface, srcData, start, count);
2971 if (srcData == NULL || cnt < 0)
2972 return WINED3DERR_INVALIDCALL;
2974 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2975 for (i = 0; i < cnt; i++)
2976 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2977 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2979 for (i = start; i < cnt + start; ++i) {
2980 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
2981 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
2984 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2986 return WINED3D_OK;
2989 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2990 IWineD3DDevice *iface,
2991 UINT start,
2992 int *dstData,
2993 UINT count) {
2995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2996 int cnt = min(count, MAX_CONST_I - start);
2998 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2999 iface, dstData, start, count);
3001 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3002 return WINED3DERR_INVALIDCALL;
3004 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3005 return WINED3D_OK;
3008 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3009 IWineD3DDevice *iface,
3010 UINT start,
3011 CONST float *srcData,
3012 UINT count) {
3014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3015 int i;
3017 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3018 iface, srcData, start, count);
3020 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3021 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3022 return WINED3DERR_INVALIDCALL;
3024 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3025 if(TRACE_ON(d3d)) {
3026 for (i = 0; i < count; i++)
3027 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3028 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3031 for (i = start; i < count + start; ++i) {
3032 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3033 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3034 ptr->idx = i;
3035 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3036 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3038 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3041 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3043 return WINED3D_OK;
3046 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3047 IWineD3DDevice *iface,
3048 UINT start,
3049 float *dstData,
3050 UINT count) {
3052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3053 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3055 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3056 iface, dstData, start, count);
3058 if (dstData == NULL || cnt < 0)
3059 return WINED3DERR_INVALIDCALL;
3061 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3062 return WINED3D_OK;
3065 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3066 DWORD i;
3067 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3068 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3072 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3073 DWORD i, tex;
3074 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3075 * it is never called.
3077 * Rules are:
3078 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3079 * that would be really messy and require shader recompilation
3080 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3081 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3082 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3083 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3085 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3086 if(This->oneToOneTexUnitMap) {
3087 TRACE("Not touching 1:1 map\n");
3088 return;
3090 TRACE("Restoring 1:1 texture unit mapping\n");
3091 /* Restore a 1:1 mapping */
3092 for(i = 0; i < MAX_SAMPLERS; i++) {
3093 if(This->texUnitMap[i] != i) {
3094 This->texUnitMap[i] = i;
3095 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3096 markTextureStagesDirty(This, i);
3099 This->oneToOneTexUnitMap = TRUE;
3100 return;
3101 } else {
3102 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3103 * First, see if we can succeed at all
3105 tex = 0;
3106 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3107 if(This->stateBlock->textures[i] == NULL) tex++;
3110 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3111 FIXME("Too many bound textures to support the combiner settings\n");
3112 return;
3115 /* Now work out the mapping */
3116 tex = 0;
3117 This->oneToOneTexUnitMap = FALSE;
3118 WARN("Non 1:1 mapping UNTESTED!\n");
3119 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3120 /* Skip NULL textures */
3121 if (!This->stateBlock->textures[i]) {
3122 /* Map to -1, so the check below doesn't fail if a non-NULL
3123 * texture is set on this stage */
3124 TRACE("Mapping texture stage %d to -1\n", i);
3125 This->texUnitMap[i] = -1;
3127 continue;
3130 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3131 if(This->texUnitMap[i] != tex) {
3132 This->texUnitMap[i] = tex;
3133 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3134 markTextureStagesDirty(This, i);
3137 ++tex;
3142 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3144 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3145 This->updateStateBlock->pixelShader = pShader;
3146 This->updateStateBlock->changed.pixelShader = TRUE;
3147 This->updateStateBlock->set.pixelShader = TRUE;
3149 /* Handle recording of state blocks */
3150 if (This->isRecordingState) {
3151 TRACE("Recording... not performing anything\n");
3154 if (This->isRecordingState) {
3155 TRACE("Recording... not performing anything\n");
3156 return WINED3D_OK;
3159 if(pShader == oldShader) {
3160 TRACE("App is setting the old pixel shader over, nothing to do\n");
3161 return WINED3D_OK;
3164 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3165 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3167 /* Rebuild the texture unit mapping if nvrc's are supported */
3168 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3169 IWineD3DDeviceImpl_FindTexUnitMap(This);
3172 return WINED3D_OK;
3175 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3178 if (NULL == ppShader) {
3179 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3180 return WINED3DERR_INVALIDCALL;
3183 *ppShader = This->stateBlock->pixelShader;
3184 if (NULL != *ppShader) {
3185 IWineD3DPixelShader_AddRef(*ppShader);
3187 TRACE("(%p) : returning %p\n", This, *ppShader);
3188 return WINED3D_OK;
3191 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3192 IWineD3DDevice *iface,
3193 UINT start,
3194 CONST BOOL *srcData,
3195 UINT count) {
3197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3198 int i, cnt = min(count, MAX_CONST_B - start);
3200 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3201 iface, srcData, start, count);
3203 if (srcData == NULL || cnt < 0)
3204 return WINED3DERR_INVALIDCALL;
3206 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3207 for (i = 0; i < cnt; i++)
3208 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3210 for (i = start; i < cnt + start; ++i) {
3211 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3212 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3215 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3217 return WINED3D_OK;
3220 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3221 IWineD3DDevice *iface,
3222 UINT start,
3223 BOOL *dstData,
3224 UINT count) {
3226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3227 int cnt = min(count, MAX_CONST_B - start);
3229 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3230 iface, dstData, start, count);
3232 if (dstData == NULL || cnt < 0)
3233 return WINED3DERR_INVALIDCALL;
3235 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3236 return WINED3D_OK;
3239 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3240 IWineD3DDevice *iface,
3241 UINT start,
3242 CONST int *srcData,
3243 UINT count) {
3245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3246 int i, cnt = min(count, MAX_CONST_I - start);
3248 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3249 iface, srcData, start, count);
3251 if (srcData == NULL || cnt < 0)
3252 return WINED3DERR_INVALIDCALL;
3254 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3255 for (i = 0; i < cnt; i++)
3256 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3257 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3259 for (i = start; i < cnt + start; ++i) {
3260 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3261 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3266 return WINED3D_OK;
3269 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3270 IWineD3DDevice *iface,
3271 UINT start,
3272 int *dstData,
3273 UINT count) {
3275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3276 int cnt = min(count, MAX_CONST_I - start);
3278 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3279 iface, dstData, start, count);
3281 if (dstData == NULL || cnt < 0)
3282 return WINED3DERR_INVALIDCALL;
3284 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3285 return WINED3D_OK;
3288 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3289 IWineD3DDevice *iface,
3290 UINT start,
3291 CONST float *srcData,
3292 UINT count) {
3294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3295 int i;
3297 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3298 iface, srcData, start, count);
3300 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3301 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3302 return WINED3DERR_INVALIDCALL;
3304 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3305 if(TRACE_ON(d3d)) {
3306 for (i = 0; i < count; i++)
3307 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3308 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3311 for (i = start; i < count + start; ++i) {
3312 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3313 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3314 ptr->idx = i;
3315 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3316 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3318 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3321 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3323 return WINED3D_OK;
3326 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3327 IWineD3DDevice *iface,
3328 UINT start,
3329 float *dstData,
3330 UINT count) {
3332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3333 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3335 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3336 iface, dstData, start, count);
3338 if (dstData == NULL || cnt < 0)
3339 return WINED3DERR_INVALIDCALL;
3341 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3342 return WINED3D_OK;
3345 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3346 static HRESULT
3347 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3348 char *dest_ptr, *dest_conv = NULL;
3349 unsigned int i;
3350 DWORD DestFVF = dest->fvf;
3351 WINED3DVIEWPORT vp;
3352 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3353 BOOL doClip;
3354 int numTextures;
3356 if (SrcFVF & WINED3DFVF_NORMAL) {
3357 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3360 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3361 ERR("Source has no position mask\n");
3362 return WINED3DERR_INVALIDCALL;
3365 /* We might access VBOs from this code, so hold the lock */
3366 ENTER_GL();
3368 if (dest->resource.allocatedMemory == NULL) {
3369 /* This may happen if we do direct locking into a vbo. Unlikely,
3370 * but theoretically possible(ddraw processvertices test)
3372 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3373 if(!dest->resource.allocatedMemory) {
3374 LEAVE_GL();
3375 ERR("Out of memory\n");
3376 return E_OUTOFMEMORY;
3378 if(dest->vbo) {
3379 void *src;
3380 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3381 checkGLcall("glBindBufferARB");
3382 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3383 if(src) {
3384 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3386 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3387 checkGLcall("glUnmapBufferARB");
3391 /* Get a pointer into the destination vbo(create one if none exists) and
3392 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3394 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3395 CreateVBO(dest);
3398 if(dest->vbo) {
3399 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3400 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
3401 if(!dest_conv) {
3402 ERR("glMapBuffer failed\n");
3403 /* Continue without storing converted vertices */
3407 /* Should I clip?
3408 * a) WINED3DRS_CLIPPING is enabled
3409 * b) WINED3DVOP_CLIP is passed
3411 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3412 static BOOL warned = FALSE;
3414 * The clipping code is not quite correct. Some things need
3415 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3416 * so disable clipping for now.
3417 * (The graphics in Half-Life are broken, and my processvertices
3418 * test crashes with IDirect3DDevice3)
3419 doClip = TRUE;
3421 doClip = FALSE;
3422 if(!warned) {
3423 warned = TRUE;
3424 FIXME("Clipping is broken and disabled for now\n");
3426 } else doClip = FALSE;
3427 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3428 if(dest_conv) {
3429 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3432 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3433 WINED3DTS_VIEW,
3434 &view_mat);
3435 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3436 WINED3DTS_PROJECTION,
3437 &proj_mat);
3438 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3439 WINED3DTS_WORLDMATRIX(0),
3440 &world_mat);
3442 TRACE("View mat:\n");
3443 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);
3444 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);
3445 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);
3446 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);
3448 TRACE("Proj mat:\n");
3449 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);
3450 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);
3451 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);
3452 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);
3454 TRACE("World mat:\n");
3455 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);
3456 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);
3457 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);
3458 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);
3460 /* Get the viewport */
3461 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3462 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3463 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3465 multiply_matrix(&mat,&view_mat,&world_mat);
3466 multiply_matrix(&mat,&proj_mat,&mat);
3468 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3470 for (i = 0; i < dwCount; i+= 1) {
3471 unsigned int tex_index;
3473 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3474 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3475 /* The position first */
3476 float *p =
3477 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3478 float x, y, z, rhw;
3479 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3481 /* Multiplication with world, view and projection matrix */
3482 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);
3483 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);
3484 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);
3485 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);
3487 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3489 /* WARNING: The following things are taken from d3d7 and were not yet checked
3490 * against d3d8 or d3d9!
3493 /* Clipping conditions: From
3494 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3496 * A vertex is clipped if it does not match the following requirements
3497 * -rhw < x <= rhw
3498 * -rhw < y <= rhw
3499 * 0 < z <= rhw
3500 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3502 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3503 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3507 if( !doClip ||
3508 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3509 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3510 ( rhw > eps ) ) ) {
3512 /* "Normal" viewport transformation (not clipped)
3513 * 1) The values are divided by rhw
3514 * 2) The y axis is negative, so multiply it with -1
3515 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3516 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3517 * 4) Multiply x with Width/2 and add Width/2
3518 * 5) The same for the height
3519 * 6) Add the viewpoint X and Y to the 2D coordinates and
3520 * The minimum Z value to z
3521 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3523 * Well, basically it's simply a linear transformation into viewport
3524 * coordinates
3527 x /= rhw;
3528 y /= rhw;
3529 z /= rhw;
3531 y *= -1;
3533 x *= vp.Width / 2;
3534 y *= vp.Height / 2;
3535 z *= vp.MaxZ - vp.MinZ;
3537 x += vp.Width / 2 + vp.X;
3538 y += vp.Height / 2 + vp.Y;
3539 z += vp.MinZ;
3541 rhw = 1 / rhw;
3542 } else {
3543 /* That vertex got clipped
3544 * Contrary to OpenGL it is not dropped completely, it just
3545 * undergoes a different calculation.
3547 TRACE("Vertex got clipped\n");
3548 x += rhw;
3549 y += rhw;
3551 x /= 2;
3552 y /= 2;
3554 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3555 * outside of the main vertex buffer memory. That needs some more
3556 * investigation...
3560 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3563 ( (float *) dest_ptr)[0] = x;
3564 ( (float *) dest_ptr)[1] = y;
3565 ( (float *) dest_ptr)[2] = z;
3566 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3568 dest_ptr += 3 * sizeof(float);
3570 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3571 dest_ptr += sizeof(float);
3574 if(dest_conv) {
3575 float w = 1 / rhw;
3576 ( (float *) dest_conv)[0] = x * w;
3577 ( (float *) dest_conv)[1] = y * w;
3578 ( (float *) dest_conv)[2] = z * w;
3579 ( (float *) dest_conv)[3] = w;
3581 dest_conv += 3 * sizeof(float);
3583 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3584 dest_conv += sizeof(float);
3588 if (DestFVF & WINED3DFVF_PSIZE) {
3589 dest_ptr += sizeof(DWORD);
3590 if(dest_conv) dest_conv += sizeof(DWORD);
3592 if (DestFVF & WINED3DFVF_NORMAL) {
3593 float *normal =
3594 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3595 /* AFAIK this should go into the lighting information */
3596 FIXME("Didn't expect the destination to have a normal\n");
3597 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3598 if(dest_conv) {
3599 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3603 if (DestFVF & WINED3DFVF_DIFFUSE) {
3604 DWORD *color_d =
3605 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3606 if(!color_d) {
3607 static BOOL warned = FALSE;
3609 if(!warned) {
3610 ERR("No diffuse color in source, but destination has one\n");
3611 warned = TRUE;
3614 *( (DWORD *) dest_ptr) = 0xffffffff;
3615 dest_ptr += sizeof(DWORD);
3617 if(dest_conv) {
3618 *( (DWORD *) dest_conv) = 0xffffffff;
3619 dest_conv += sizeof(DWORD);
3622 else {
3623 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3624 if(dest_conv) {
3625 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3626 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3627 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3628 dest_conv += sizeof(DWORD);
3633 if (DestFVF & WINED3DFVF_SPECULAR) {
3634 /* What's the color value in the feedback buffer? */
3635 DWORD *color_s =
3636 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3637 if(!color_s) {
3638 static BOOL warned = FALSE;
3640 if(!warned) {
3641 ERR("No specular color in source, but destination has one\n");
3642 warned = TRUE;
3645 *( (DWORD *) dest_ptr) = 0xFF000000;
3646 dest_ptr += sizeof(DWORD);
3648 if(dest_conv) {
3649 *( (DWORD *) dest_conv) = 0xFF000000;
3650 dest_conv += sizeof(DWORD);
3653 else {
3654 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3655 if(dest_conv) {
3656 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3657 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3658 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3659 dest_conv += sizeof(DWORD);
3664 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3665 float *tex_coord =
3666 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3667 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3668 if(!tex_coord) {
3669 ERR("No source texture, but destination requests one\n");
3670 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3671 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3673 else {
3674 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3675 if(dest_conv) {
3676 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3682 if(dest_conv) {
3683 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3684 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
3687 LEAVE_GL();
3689 return WINED3D_OK;
3691 #undef copy_and_next
3693 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
3694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3695 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
3696 WineDirect3DVertexStridedData strided;
3697 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3699 if (!SrcImpl) {
3700 WARN("NULL source vertex buffer\n");
3701 return WINED3DERR_INVALIDCALL;
3703 /* We don't need the source vbo because this buffer is only used as
3704 * a source for ProcessVertices. Avoid wasting resources by converting the
3705 * buffer and loading the VBO
3707 if(SrcImpl->vbo) {
3708 TRACE("Releasing the source vbo, it won't be needed\n");
3710 if(!SrcImpl->resource.allocatedMemory) {
3711 /* Rescue the data from the buffer */
3712 void *src;
3713 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
3714 if(!SrcImpl->resource.allocatedMemory) {
3715 ERR("Out of memory\n");
3716 return E_OUTOFMEMORY;
3719 ENTER_GL();
3720 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
3721 checkGLcall("glBindBufferARB");
3723 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3724 if(src) {
3725 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
3728 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3729 checkGLcall("glUnmapBufferARB");
3730 } else {
3731 ENTER_GL();
3734 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
3735 checkGLcall("glBindBufferARB");
3736 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
3737 checkGLcall("glDeleteBuffersARB");
3738 LEAVE_GL();
3740 SrcImpl->vbo = 0;
3743 memset(&strided, 0, sizeof(strided));
3744 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0, 0);
3746 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3749 /*****
3750 * Get / Set Texture Stage States
3751 * TODO: Verify against dx9 definitions
3752 *****/
3753 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3755 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3757 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3759 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3761 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3762 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3763 This->updateStateBlock->textureState[Stage][Type] = Value;
3765 if (This->isRecordingState) {
3766 TRACE("Recording... not performing anything\n");
3767 return WINED3D_OK;
3770 /* Checked after the assignments to allow proper stateblock recording */
3771 if(oldValue == Value) {
3772 TRACE("App is setting the old value over, nothing to do\n");
3773 return WINED3D_OK;
3776 if(Stage > This->stateBlock->lowest_disabled_stage &&
3777 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3778 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3779 * Changes in other states are important on disabled stages too
3781 return WINED3D_OK;
3784 if(Type == WINED3DTSS_COLOROP) {
3785 int i;
3787 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3788 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3789 * they have to be disabled
3791 * The current stage is dirtified below.
3793 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3794 TRACE("Additionally dirtifying stage %d\n", i);
3795 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3797 This->stateBlock->lowest_disabled_stage = Stage;
3798 TRACE("New lowest disabled: %d\n", Stage);
3799 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3800 /* Previously disabled stage enabled. Stages above it may need enabling
3801 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3802 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3804 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3807 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3808 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3809 break;
3811 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3812 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3814 This->stateBlock->lowest_disabled_stage = i;
3815 TRACE("New lowest disabled: %d\n", i);
3817 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3818 /* TODO: Built a stage -> texture unit mapping for register combiners */
3822 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3824 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3825 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3826 * will call FindTexUnitMap too.
3828 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3829 IWineD3DDeviceImpl_FindTexUnitMap(This);
3831 return WINED3D_OK;
3834 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3836 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3837 *pValue = This->updateStateBlock->textureState[Stage][Type];
3838 return WINED3D_OK;
3841 /*****
3842 * Get / Set Texture
3843 *****/
3844 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
3846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3847 IWineD3DBaseTexture *oldTexture;
3849 oldTexture = This->updateStateBlock->textures[Stage];
3850 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
3852 #if 0 /* TODO: check so vertex textures */
3853 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
3854 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
3855 return WINED3D_OK;
3857 #endif
3859 if(pTexture != NULL) {
3860 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
3862 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
3863 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
3864 return WINED3DERR_INVALIDCALL;
3866 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
3869 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
3870 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
3872 This->updateStateBlock->set.textures[Stage] = TRUE;
3873 This->updateStateBlock->changed.textures[Stage] = TRUE;
3874 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
3875 This->updateStateBlock->textures[Stage] = pTexture;
3877 /* Handle recording of state blocks */
3878 if (This->isRecordingState) {
3879 TRACE("Recording... not performing anything\n");
3880 return WINED3D_OK;
3883 if(oldTexture == pTexture) {
3884 TRACE("App is setting the same texture again, nothing to do\n");
3885 return WINED3D_OK;
3888 /** NOTE: MSDN says that setTexture increases the reference count,
3889 * and the the application nust set the texture back to null (or have a leaky application),
3890 * This means we should pass the refcount up to the parent
3891 *******************************/
3892 if (NULL != This->updateStateBlock->textures[Stage]) {
3893 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
3894 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
3896 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
3897 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
3898 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
3899 * so the COLOROP and ALPHAOP have to be dirtified.
3901 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3902 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3904 if(bindCount == 1) {
3905 new->baseTexture.sampler = Stage;
3907 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
3911 if (NULL != oldTexture) {
3912 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
3913 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
3915 IWineD3DBaseTexture_Release(oldTexture);
3916 if(pTexture == NULL && Stage < MAX_TEXTURES) {
3917 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3918 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3921 if(bindCount && old->baseTexture.sampler == Stage) {
3922 int i;
3923 /* Have to do a search for the other sampler(s) where the texture is bound to
3924 * Shouldn't happen as long as apps bind a texture only to one stage
3926 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
3927 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
3928 if(This->updateStateBlock->textures[i] == oldTexture) {
3929 old->baseTexture.sampler = i;
3930 break;
3936 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
3938 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
3939 * pixel shader is used
3941 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3942 IWineD3DDeviceImpl_FindTexUnitMap(This);
3945 return WINED3D_OK;
3948 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3950 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
3952 *ppTexture=This->stateBlock->textures[Stage];
3953 if (*ppTexture)
3954 IWineD3DBaseTexture_AddRef(*ppTexture);
3956 return WINED3D_OK;
3959 /*****
3960 * Get Back Buffer
3961 *****/
3962 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
3963 IWineD3DSurface **ppBackBuffer) {
3964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3965 IWineD3DSwapChain *swapChain;
3966 HRESULT hr;
3968 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
3970 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
3971 if (hr == WINED3D_OK) {
3972 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
3973 IWineD3DSwapChain_Release(swapChain);
3974 } else {
3975 *ppBackBuffer = NULL;
3977 return hr;
3980 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
3981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3982 WARN("(%p) : stub, calling idirect3d for now\n", This);
3983 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
3986 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
3987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3988 IWineD3DSwapChain *swapChain;
3989 HRESULT hr;
3991 if(iSwapChain > 0) {
3992 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
3993 if (hr == WINED3D_OK) {
3994 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
3995 IWineD3DSwapChain_Release(swapChain);
3996 } else {
3997 FIXME("(%p) Error getting display mode\n", This);
3999 } else {
4000 /* Don't read the real display mode,
4001 but return the stored mode instead. X11 can't change the color
4002 depth, and some apps are pretty angry if they SetDisplayMode from
4003 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4005 Also don't relay to the swapchain because with ddraw it's possible
4006 that there isn't a swapchain at all */
4007 pMode->Width = This->ddraw_width;
4008 pMode->Height = This->ddraw_height;
4009 pMode->Format = This->ddraw_format;
4010 pMode->RefreshRate = 0;
4011 hr = WINED3D_OK;
4014 return hr;
4017 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4019 TRACE("(%p)->(%p)\n", This, hWnd);
4021 if(This->ddraw_fullscreen) {
4022 if(This->ddraw_window && This->ddraw_window != hWnd) {
4023 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4025 if(hWnd && This->ddraw_window != hWnd) {
4026 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4030 This->ddraw_window = hWnd;
4031 return WINED3D_OK;
4034 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4036 TRACE("(%p)->(%p)\n", This, hWnd);
4038 *hWnd = This->ddraw_window;
4039 return WINED3D_OK;
4042 /*****
4043 * Stateblock related functions
4044 *****/
4046 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4048 IWineD3DStateBlockImpl *object;
4049 HRESULT temp_result;
4050 int i;
4052 TRACE("(%p)\n", This);
4054 if (This->isRecordingState) {
4055 return WINED3DERR_INVALIDCALL;
4058 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4059 if (NULL == object ) {
4060 FIXME("(%p)Error allocating memory for stateblock\n", This);
4061 return E_OUTOFMEMORY;
4063 TRACE("(%p) created object %p\n", This, object);
4064 object->wineD3DDevice= This;
4065 /** FIXME: object->parent = parent; **/
4066 object->parent = NULL;
4067 object->blockType = WINED3DSBT_ALL;
4068 object->ref = 1;
4069 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4071 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4072 list_init(&object->lightMap[i]);
4075 temp_result = allocate_shader_constants(object);
4076 if (WINED3D_OK != temp_result)
4077 return temp_result;
4079 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4080 This->updateStateBlock = object;
4081 This->isRecordingState = TRUE;
4083 TRACE("(%p) recording stateblock %p\n",This , object);
4084 return WINED3D_OK;
4087 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4090 if (!This->isRecordingState) {
4091 FIXME("(%p) not recording! returning error\n", This);
4092 *ppStateBlock = NULL;
4093 return WINED3DERR_INVALIDCALL;
4096 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4097 This->isRecordingState = FALSE;
4098 This->updateStateBlock = This->stateBlock;
4099 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4100 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4101 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4102 return WINED3D_OK;
4105 /*****
4106 * Scene related functions
4107 *****/
4108 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4109 /* At the moment we have no need for any functionality at the beginning
4110 of a scene */
4111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4112 TRACE("(%p)\n", This);
4114 if(This->inScene) {
4115 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4116 return WINED3DERR_INVALIDCALL;
4118 This->inScene = TRUE;
4119 return WINED3D_OK;
4122 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4124 TRACE("(%p)\n", This);
4126 if(!This->inScene) {
4127 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4128 return WINED3DERR_INVALIDCALL;
4131 ENTER_GL();
4132 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4133 glFlush();
4134 checkGLcall("glFlush");
4135 LEAVE_GL();
4137 This->inScene = FALSE;
4138 return WINED3D_OK;
4141 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4142 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4143 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4145 IWineD3DSwapChain *swapChain = NULL;
4146 int i;
4147 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4149 TRACE("(%p) Presenting the frame\n", This);
4151 for(i = 0 ; i < swapchains ; i ++) {
4153 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4154 TRACE("presentinng chain %d, %p\n", i, swapChain);
4155 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4156 IWineD3DSwapChain_Release(swapChain);
4159 return WINED3D_OK;
4162 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4163 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4166 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4167 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4168 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4169 GLbitfield glMask = 0;
4170 GLboolean old_ztest;
4171 GLfloat old_z_clear_value;
4172 GLint old_stencil_clear_value;
4173 GLfloat old_color_clear_value[4];
4174 unsigned int i;
4175 CONST WINED3DRECT* curRect;
4177 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4178 Count, pRects, Flags, Z, Stencil);
4180 ENTER_GL();
4182 glEnable(GL_SCISSOR_TEST);
4183 checkGLcall("glEnable GL_SCISSOR_TEST");
4185 if (Count > 0 && pRects) {
4186 curRect = pRects;
4187 } else {
4188 curRect = NULL;
4191 /* Only set the values up once, as they are not changing */
4192 if (Flags & WINED3DCLEAR_STENCIL) {
4193 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
4194 glClearStencil(Stencil);
4195 checkGLcall("glClearStencil");
4196 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4197 glStencilMask(0xFFFFFFFF);
4200 if (Flags & WINED3DCLEAR_ZBUFFER) {
4201 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
4202 glDepthMask(GL_TRUE);
4203 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
4204 glClearDepth(Z);
4205 checkGLcall("glClearDepth");
4206 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4209 if (Flags & WINED3DCLEAR_TARGET) {
4210 TRACE("Clearing screen with glClear to color %x\n", Color);
4211 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
4212 glClearColor(D3DCOLOR_R(Color),
4213 D3DCOLOR_G(Color),
4214 D3DCOLOR_B(Color),
4215 D3DCOLOR_A(Color));
4216 checkGLcall("glClearColor");
4218 /* Clear ALL colors! */
4219 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4220 glMask = glMask | GL_COLOR_BUFFER_BIT;
4223 /* Now process each rect in turn */
4224 for (i = 0; i < Count || i == 0; i++) {
4226 if (curRect) {
4227 /* Note gl uses lower left, width/height */
4228 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4229 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
4230 curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4231 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4232 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4233 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4234 checkGLcall("glScissor");
4235 } else {
4236 glScissor(This->stateBlock->viewport.X,
4237 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4238 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4239 This->stateBlock->viewport.Width,
4240 This->stateBlock->viewport.Height);
4241 checkGLcall("glScissor");
4244 /* Clear the selected rectangle (or full screen) */
4245 glClear(glMask);
4246 checkGLcall("glClear");
4248 /* Step to the next rectangle */
4249 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
4252 /* Restore the old values (why..?) */
4253 if (Flags & WINED3DCLEAR_STENCIL) {
4254 glClearStencil(old_stencil_clear_value);
4255 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4257 if (Flags & WINED3DCLEAR_ZBUFFER) {
4258 glDepthMask(old_ztest);
4259 glClearDepth(old_z_clear_value);
4261 if (Flags & WINED3DCLEAR_TARGET) {
4262 glClearColor(old_color_clear_value[0],
4263 old_color_clear_value[1],
4264 old_color_clear_value[2],
4265 old_color_clear_value[3]);
4266 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4267 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4268 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4269 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4272 glDisable(GL_SCISSOR_TEST);
4273 checkGLcall("glDisable");
4274 LEAVE_GL();
4276 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4277 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4279 ((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_GLDIRTY;
4280 return WINED3D_OK;
4283 /*****
4284 * Drawing functions
4285 *****/
4286 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4287 UINT PrimitiveCount) {
4289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4290 This->stateBlock->streamIsUP = FALSE;
4292 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4293 debug_d3dprimitivetype(PrimitiveType),
4294 StartVertex, PrimitiveCount);
4296 if(This->stateBlock->loadBaseVertexIndex != 0) {
4297 This->stateBlock->loadBaseVertexIndex = 0;
4298 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4300 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4301 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4302 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4303 return WINED3D_OK;
4306 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4307 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4308 WINED3DPRIMITIVETYPE PrimitiveType,
4309 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4312 UINT idxStride = 2;
4313 IWineD3DIndexBuffer *pIB;
4314 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4315 GLint vbo;
4317 pIB = This->stateBlock->pIndexData;
4318 This->stateBlock->streamIsUP = FALSE;
4319 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4321 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4322 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4323 minIndex, NumVertices, startIndex, primCount);
4325 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4326 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4327 idxStride = 2;
4328 } else {
4329 idxStride = 4;
4332 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4333 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4334 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4337 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4338 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4340 return WINED3D_OK;
4343 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4344 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4345 UINT VertexStreamZeroStride) {
4346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4348 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4349 debug_d3dprimitivetype(PrimitiveType),
4350 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4352 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4353 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4354 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4355 This->stateBlock->streamIsUP = TRUE;
4356 This->stateBlock->loadBaseVertexIndex = 0;
4358 /* TODO: Only mark dirty if drawing from a different UP address */
4359 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4361 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4362 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4364 /* MSDN specifies stream zero settings must be set to NULL */
4365 This->stateBlock->streamStride[0] = 0;
4366 This->stateBlock->streamSource[0] = NULL;
4368 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4369 * the new stream sources or use UP drawing again
4371 return WINED3D_OK;
4374 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4375 UINT MinVertexIndex, UINT NumVertices,
4376 UINT PrimitiveCount, CONST void* pIndexData,
4377 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4378 UINT VertexStreamZeroStride) {
4379 int idxStride;
4380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4382 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4383 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4384 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4385 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4387 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4388 idxStride = 2;
4389 } else {
4390 idxStride = 4;
4393 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4394 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4395 This->stateBlock->streamIsUP = TRUE;
4396 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4398 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4399 This->stateBlock->baseVertexIndex = 0;
4400 This->stateBlock->loadBaseVertexIndex = 0;
4401 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4402 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4403 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4405 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4407 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4408 This->stateBlock->streamSource[0] = NULL;
4409 This->stateBlock->streamStride[0] = 0;
4410 This->stateBlock->pIndexData = NULL;
4411 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4412 * SetStreamSource to specify a vertex buffer
4415 return WINED3D_OK;
4418 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4421 /* Mark the state dirty until we have nicer tracking
4422 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4423 * that value.
4425 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4426 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4427 This->stateBlock->baseVertexIndex = 0;
4428 This->up_strided = DrawPrimStrideData;
4429 This->stateBlock->streamIsUP = TRUE;
4430 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4431 This->up_strided = NULL;
4432 return WINED3D_OK;
4434 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4435 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4437 HRESULT hr = WINED3D_OK;
4438 WINED3DRESOURCETYPE sourceType;
4439 WINED3DRESOURCETYPE destinationType;
4440 int i ,levels;
4442 /* TODO: think about moving the code into IWineD3DBaseTexture */
4444 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4446 /* verify that the source and destination textures aren't NULL */
4447 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4448 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4449 This, pSourceTexture, pDestinationTexture);
4450 hr = WINED3DERR_INVALIDCALL;
4453 if (pSourceTexture == pDestinationTexture) {
4454 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4455 This, pSourceTexture, pDestinationTexture);
4456 hr = WINED3DERR_INVALIDCALL;
4458 /* Verify that the source and destination textures are the same type */
4459 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4460 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4462 if (sourceType != destinationType) {
4463 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4464 This);
4465 hr = WINED3DERR_INVALIDCALL;
4468 /* check that both textures have the identical numbers of levels */
4469 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4470 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4471 hr = WINED3DERR_INVALIDCALL;
4474 if (WINED3D_OK == hr) {
4476 /* Make sure that the destination texture is loaded */
4477 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4479 /* Update every surface level of the texture */
4480 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4482 switch (sourceType) {
4483 case WINED3DRTYPE_TEXTURE:
4485 IWineD3DSurface *srcSurface;
4486 IWineD3DSurface *destSurface;
4488 for (i = 0 ; i < levels ; ++i) {
4489 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4490 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4491 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4492 IWineD3DSurface_Release(srcSurface);
4493 IWineD3DSurface_Release(destSurface);
4494 if (WINED3D_OK != hr) {
4495 WARN("(%p) : Call to update surface failed\n", This);
4496 return hr;
4500 break;
4501 case WINED3DRTYPE_CUBETEXTURE:
4503 IWineD3DSurface *srcSurface;
4504 IWineD3DSurface *destSurface;
4505 WINED3DCUBEMAP_FACES faceType;
4507 for (i = 0 ; i < levels ; ++i) {
4508 /* Update each cube face */
4509 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4510 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4511 if (WINED3D_OK != hr) {
4512 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4513 } else {
4514 TRACE("Got srcSurface %p\n", srcSurface);
4516 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4517 if (WINED3D_OK != hr) {
4518 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4519 } else {
4520 TRACE("Got desrSurface %p\n", destSurface);
4522 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4523 IWineD3DSurface_Release(srcSurface);
4524 IWineD3DSurface_Release(destSurface);
4525 if (WINED3D_OK != hr) {
4526 WARN("(%p) : Call to update surface failed\n", This);
4527 return hr;
4532 break;
4533 #if 0 /* TODO: Add support for volume textures */
4534 case WINED3DRTYPE_VOLUMETEXTURE:
4536 IWineD3DVolume srcVolume = NULL;
4537 IWineD3DSurface destVolume = NULL;
4539 for (i = 0 ; i < levels ; ++i) {
4540 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4541 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4542 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4543 IWineD3DVolume_Release(srcSurface);
4544 IWineD3DVolume_Release(destSurface);
4545 if (WINED3D_OK != hr) {
4546 WARN("(%p) : Call to update volume failed\n", This);
4547 return hr;
4551 break;
4552 #endif
4553 default:
4554 FIXME("(%p) : Unsupported source and destination type\n", This);
4555 hr = WINED3DERR_INVALIDCALL;
4559 return hr;
4562 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4563 IWineD3DSwapChain *swapChain;
4564 HRESULT hr;
4565 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4566 if(hr == WINED3D_OK) {
4567 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4568 IWineD3DSwapChain_Release(swapChain);
4570 return hr;
4573 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4575 /* return a sensible default */
4576 *pNumPasses = 1;
4577 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4578 FIXME("(%p) : stub\n", This);
4579 return WINED3D_OK;
4582 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4584 int j;
4585 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4586 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4587 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4588 return WINED3DERR_INVALIDCALL;
4590 for (j = 0; j < 256; ++j) {
4591 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4592 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4593 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4594 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4596 TRACE("(%p) : returning\n", This);
4597 return WINED3D_OK;
4600 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4602 int j;
4603 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4604 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4605 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4606 return WINED3DERR_INVALIDCALL;
4608 for (j = 0; j < 256; ++j) {
4609 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4610 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4611 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4612 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4614 TRACE("(%p) : returning\n", This);
4615 return WINED3D_OK;
4618 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4620 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4621 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4622 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4623 return WINED3DERR_INVALIDCALL;
4625 /*TODO: stateblocks */
4626 This->currentPalette = PaletteNumber;
4627 TRACE("(%p) : returning\n", This);
4628 return WINED3D_OK;
4631 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4633 if (PaletteNumber == NULL) {
4634 WARN("(%p) : returning Invalid Call\n", This);
4635 return WINED3DERR_INVALIDCALL;
4637 /*TODO: stateblocks */
4638 *PaletteNumber = This->currentPalette;
4639 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4640 return WINED3D_OK;
4643 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4645 static BOOL showFixmes = TRUE;
4646 if (showFixmes) {
4647 FIXME("(%p) : stub\n", This);
4648 showFixmes = FALSE;
4651 This->softwareVertexProcessing = bSoftware;
4652 return WINED3D_OK;
4656 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4658 static BOOL showFixmes = TRUE;
4659 if (showFixmes) {
4660 FIXME("(%p) : stub\n", This);
4661 showFixmes = FALSE;
4663 return This->softwareVertexProcessing;
4667 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4669 IWineD3DSwapChain *swapChain;
4670 HRESULT hr;
4672 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4674 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4675 if(hr == WINED3D_OK){
4676 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4677 IWineD3DSwapChain_Release(swapChain);
4678 }else{
4679 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4681 return hr;
4685 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4687 static BOOL showfixmes = TRUE;
4688 if(nSegments != 0.0f) {
4689 if( showfixmes) {
4690 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4691 showfixmes = FALSE;
4694 return WINED3D_OK;
4697 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4699 static BOOL showfixmes = TRUE;
4700 if( showfixmes) {
4701 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4702 showfixmes = FALSE;
4704 return 0.0f;
4707 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4709 /** TODO: remove casts to IWineD3DSurfaceImpl
4710 * NOTE: move code to surface to accomplish this
4711 ****************************************/
4712 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4713 int srcWidth, srcHeight;
4714 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4715 WINED3DFORMAT destFormat, srcFormat;
4716 UINT destSize;
4717 int srcLeft, destLeft, destTop;
4718 WINED3DPOOL srcPool, destPool;
4719 int offset = 0;
4720 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4721 glDescriptor *glDescription = NULL;
4722 GLenum textureDimensions = GL_TEXTURE_2D;
4723 IWineD3DBaseTexture *baseTexture;
4725 WINED3DSURFACE_DESC winedesc;
4727 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4728 memset(&winedesc, 0, sizeof(winedesc));
4729 winedesc.Width = &srcSurfaceWidth;
4730 winedesc.Height = &srcSurfaceHeight;
4731 winedesc.Pool = &srcPool;
4732 winedesc.Format = &srcFormat;
4734 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4736 winedesc.Width = &destSurfaceWidth;
4737 winedesc.Height = &destSurfaceHeight;
4738 winedesc.Pool = &destPool;
4739 winedesc.Format = &destFormat;
4740 winedesc.Size = &destSize;
4742 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4744 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4745 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4746 return WINED3DERR_INVALIDCALL;
4749 if (destFormat == WINED3DFMT_UNKNOWN) {
4750 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4751 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4753 /* Get the update surface description */
4754 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4757 /* Make sure the surface is loaded and up to date */
4758 IWineD3DSurface_PreLoad(pDestinationSurface);
4760 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4762 ENTER_GL();
4764 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4765 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4766 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
4767 srcLeft = pSourceRect ? pSourceRect->left : 0;
4768 destLeft = pDestPoint ? pDestPoint->x : 0;
4769 destTop = pDestPoint ? pDestPoint->y : 0;
4772 /* This function doesn't support compressed textures
4773 the pitch is just bytesPerPixel * width */
4774 if(srcWidth != srcSurfaceWidth || srcLeft ){
4775 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
4776 offset += srcLeft * pSrcSurface->bytesPerPixel;
4777 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4779 /* TODO DXT formats */
4781 if(pSourceRect != NULL && pSourceRect->top != 0){
4782 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
4784 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4785 ,This
4786 ,glDescription->level
4787 ,destLeft
4788 ,destTop
4789 ,srcWidth
4790 ,srcHeight
4791 ,glDescription->glFormat
4792 ,glDescription->glType
4793 ,IWineD3DSurface_GetData(pSourceSurface)
4796 /* Sanity check */
4797 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
4799 /* need to lock the surface to get the data */
4800 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
4803 /* TODO: Cube and volume support */
4804 if(rowoffset != 0){
4805 /* not a whole row so we have to do it a line at a time */
4806 int j;
4808 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
4809 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
4811 for(j = destTop ; j < (srcHeight + destTop) ; j++){
4813 glTexSubImage2D(glDescription->target
4814 ,glDescription->level
4815 ,destLeft
4817 ,srcWidth
4819 ,glDescription->glFormat
4820 ,glDescription->glType
4821 ,data /* could be quicker using */
4823 data += rowoffset;
4826 } else { /* Full width, so just write out the whole texture */
4828 if (WINED3DFMT_DXT1 == destFormat ||
4829 WINED3DFMT_DXT2 == destFormat ||
4830 WINED3DFMT_DXT3 == destFormat ||
4831 WINED3DFMT_DXT4 == destFormat ||
4832 WINED3DFMT_DXT5 == destFormat) {
4833 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
4834 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
4835 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
4836 FIXME("Updating part of a compressed texture is not supported at the moment\n");
4837 } if (destFormat != srcFormat) {
4838 FIXME("Updating mixed format compressed texture is not curretly support\n");
4839 } else {
4840 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
4841 glDescription->level,
4842 glDescription->glFormatInternal,
4843 srcWidth,
4844 srcHeight,
4846 destSize,
4847 IWineD3DSurface_GetData(pSourceSurface));
4849 } else {
4850 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
4854 } else {
4855 glTexSubImage2D(glDescription->target
4856 ,glDescription->level
4857 ,destLeft
4858 ,destTop
4859 ,srcWidth
4860 ,srcHeight
4861 ,glDescription->glFormat
4862 ,glDescription->glType
4863 ,IWineD3DSurface_GetData(pSourceSurface)
4867 checkGLcall("glTexSubImage2D");
4868 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
4870 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
4871 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
4872 * surface bigger than it needs to be hmm.. */
4873 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
4874 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
4875 IWineD3DBaseTexture_Release(baseTexture);
4878 glDisable(textureDimensions); /* This needs to be managed better.... */
4879 LEAVE_GL();
4881 return WINED3D_OK;
4884 /* Implementation details at http://developer.nvidia.com/attach/6494
4886 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
4887 hmm.. no longer supported use
4888 OpenGL evaluators or tessellate surfaces within your application.
4891 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
4892 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
4893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4894 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
4895 FIXME("(%p) : Stub\n", This);
4896 return WINED3D_OK;
4900 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
4901 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
4902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4903 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
4904 FIXME("(%p) : Stub\n", This);
4905 return WINED3D_OK;
4908 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
4909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4910 TRACE("(%p) Handle(%d)\n", This, Handle);
4911 FIXME("(%p) : Stub\n", This);
4912 return WINED3D_OK;
4915 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
4916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4917 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
4918 DDBLTFX BltFx;
4919 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
4921 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
4922 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
4923 return WINED3DERR_INVALIDCALL;
4926 /* Just forward this to the DirectDraw blitting engine */
4927 memset(&BltFx, 0, sizeof(BltFx));
4928 BltFx.dwSize = sizeof(BltFx);
4929 BltFx.u5.dwFillColor = color;
4930 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
4933 /* rendertarget and deptth stencil functions */
4934 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
4935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4937 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
4938 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
4939 return WINED3DERR_INVALIDCALL;
4942 *ppRenderTarget = This->render_targets[RenderTargetIndex];
4943 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
4944 /* Note inc ref on returned surface */
4945 if(*ppRenderTarget != NULL)
4946 IWineD3DSurface_AddRef(*ppRenderTarget);
4947 return WINED3D_OK;
4950 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
4951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4952 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
4953 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
4954 IWineD3DSwapChainImpl *Swapchain;
4955 HRESULT hr;
4957 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
4959 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
4960 if(hr != WINED3D_OK) {
4961 ERR("Can't get the swapchain\n");
4962 return hr;
4965 /* Make sure to release the swapchain */
4966 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
4968 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
4969 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4970 return WINED3DERR_INVALIDCALL;
4972 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
4973 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4974 return WINED3DERR_INVALIDCALL;
4977 if(Swapchain->frontBuffer != Front) {
4978 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
4980 if(Swapchain->frontBuffer)
4981 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
4982 Swapchain->frontBuffer = Front;
4984 if(Swapchain->frontBuffer) {
4985 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
4989 if(Back && !Swapchain->backBuffer) {
4990 /* We need memory for the back buffer array - only one back buffer this way */
4991 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
4992 if(!Swapchain->backBuffer) {
4993 ERR("Out of memory\n");
4994 return E_OUTOFMEMORY;
4998 if(Swapchain->backBuffer[0] != Back) {
4999 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5000 ENTER_GL();
5001 if(!Swapchain->backBuffer[0]) {
5002 /* GL was told to draw to the front buffer at creation,
5003 * undo that
5005 glDrawBuffer(GL_BACK);
5006 checkGLcall("glDrawBuffer(GL_BACK)");
5007 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5008 Swapchain->presentParms.BackBufferCount = 1;
5009 } else if (!Back) {
5010 /* That makes problems - disable for now */
5011 /* glDrawBuffer(GL_FRONT); */
5012 checkGLcall("glDrawBuffer(GL_FRONT)");
5013 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5014 Swapchain->presentParms.BackBufferCount = 0;
5016 LEAVE_GL();
5018 if(Swapchain->backBuffer[0])
5019 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5020 Swapchain->backBuffer[0] = Back;
5022 if(Swapchain->backBuffer[0]) {
5023 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5024 } else {
5025 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5030 return WINED3D_OK;
5033 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5035 *ppZStencilSurface = This->depthStencilBuffer;
5036 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5038 if(*ppZStencilSurface != NULL) {
5039 /* Note inc ref on returned surface */
5040 IWineD3DSurface_AddRef(*ppZStencilSurface);
5042 return WINED3D_OK;
5045 static void bind_fbo(IWineD3DDevice *iface) {
5046 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5048 if (!This->fbo) {
5049 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5050 checkGLcall("glGenFramebuffersEXT()");
5052 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5053 checkGLcall("glBindFramebuffer()");
5056 /* TODO: Handle stencil attachments */
5057 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5058 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5059 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5061 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5063 bind_fbo(iface);
5065 if (depth_stencil_impl) {
5066 GLenum texttarget, target;
5067 GLint old_binding = 0;
5069 IWineD3DSurface_PreLoad(depth_stencil);
5070 texttarget = depth_stencil_impl->glDescription.target;
5071 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5073 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5074 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5075 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5076 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5077 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5078 glBindTexture(target, old_binding);
5080 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5081 checkGLcall("glFramebufferTexture2DEXT()");
5082 } else {
5083 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5084 checkGLcall("glFramebufferTexture2DEXT()");
5087 if (!This->render_offscreen) {
5088 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5089 checkGLcall("glBindFramebuffer()");
5093 void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5094 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5095 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5097 if (idx >= GL_LIMITS(buffers)) {
5098 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5101 bind_fbo(iface);
5103 if (rtimpl) {
5104 GLenum texttarget, target;
5105 GLint old_binding = 0;
5107 IWineD3DSurface_PreLoad(render_target);
5108 texttarget = rtimpl->glDescription.target;
5109 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5111 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5112 glBindTexture(target, rtimpl->glDescription.textureName);
5113 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5114 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5115 glBindTexture(target, old_binding);
5117 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5118 checkGLcall("glFramebufferTexture2DEXT()");
5120 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5121 } else {
5122 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5123 checkGLcall("glFramebufferTexture2DEXT()");
5125 This->draw_buffers[idx] = GL_NONE;
5128 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5129 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5130 checkGLcall("glDrawBuffers()");
5133 if (!This->render_offscreen) {
5134 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5135 checkGLcall("glBindFramebuffer()");
5139 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5141 WINED3DVIEWPORT viewport;
5143 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5145 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5146 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5147 return WINED3DERR_INVALIDCALL;
5150 /* MSDN says that null disables the render target
5151 but a device must always be associated with a render target
5152 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5154 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5155 for more details
5157 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5158 FIXME("Trying to set render target 0 to NULL\n");
5159 return WINED3DERR_INVALIDCALL;
5161 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5162 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);
5163 return WINED3DERR_INVALIDCALL;
5166 /* If we are trying to set what we already have, don't bother */
5167 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5168 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5169 return WINED3D_OK;
5171 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5172 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5173 This->render_targets[RenderTargetIndex] = pRenderTarget;
5175 /* Render target 0 is special */
5176 if(RenderTargetIndex == 0) {
5177 /* Finally, reset the viewport as the MSDN states. */
5178 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5179 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5180 viewport.X = 0;
5181 viewport.Y = 0;
5182 viewport.MaxZ = 1.0f;
5183 viewport.MinZ = 0.0f;
5184 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5186 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5187 * ctx properly.
5188 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5189 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5191 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5192 } else {
5193 /* We only get more than 1 render target with fbos, so no need to check the offscreen rendering method */
5194 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5196 return WINED3D_OK;
5199 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5201 HRESULT hr = WINED3D_OK;
5202 IWineD3DSurface *tmp;
5204 TRACE("(%p) Swapping z-buffer\n",This);
5206 if (pNewZStencil == This->stencilBufferTarget) {
5207 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5208 } else {
5209 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5210 * depending on the renter target implementation being used.
5211 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5212 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5213 * stencil buffer and incure an extra memory overhead
5214 ******************************************************/
5217 tmp = This->stencilBufferTarget;
5218 This->stencilBufferTarget = pNewZStencil;
5219 /* should we be calling the parent or the wined3d surface? */
5220 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5221 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5222 hr = WINED3D_OK;
5223 /** TODO: glEnable/glDisable on depth/stencil depending on
5224 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5225 **********************************************************/
5226 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5227 set_depth_stencil_fbo(iface, pNewZStencil);
5231 return hr;
5234 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5235 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5237 /* TODO: the use of Impl is deprecated. */
5238 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5240 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5242 /* some basic validation checks */
5243 if(This->cursorTexture) {
5244 ENTER_GL();
5245 glDeleteTextures(1, &This->cursorTexture);
5246 LEAVE_GL();
5247 This->cursorTexture = 0;
5250 if(pCursorBitmap) {
5251 /* MSDN: Cursor must be A8R8G8B8 */
5252 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5253 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5254 return WINED3DERR_INVALIDCALL;
5257 /* MSDN: Cursor must be smaller than the display mode */
5258 if(pSur->currentDesc.Width > This->ddraw_width ||
5259 pSur->currentDesc.Height > This->ddraw_height) {
5260 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);
5261 return WINED3DERR_INVALIDCALL;
5264 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5265 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
5266 * Texture and Blitting code to draw the cursor
5268 pSur->Flags |= SFLAG_FORCELOAD;
5269 IWineD3DSurface_PreLoad(pCursorBitmap);
5270 pSur->Flags &= ~SFLAG_FORCELOAD;
5271 /* Do not store the surface's pointer because the application may release
5272 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5273 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5275 This->cursorTexture = pSur->glDescription.textureName;
5276 This->cursorWidth = pSur->currentDesc.Width;
5277 This->cursorHeight = pSur->currentDesc.Height;
5278 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
5281 This->xHotSpot = XHotSpot;
5282 This->yHotSpot = YHotSpot;
5283 return WINED3D_OK;
5286 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5288 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5290 This->xScreenSpace = XScreenSpace;
5291 This->yScreenSpace = YScreenSpace;
5293 return;
5297 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5299 BOOL oldVisible = This->bCursorVisible;
5300 TRACE("(%p) : visible(%d)\n", This, bShow);
5302 if(This->cursorTexture)
5303 This->bCursorVisible = bShow;
5305 return oldVisible;
5308 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5310 TRACE("(%p) : state (%u)\n", This, This->state);
5311 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5312 switch (This->state) {
5313 case WINED3D_OK:
5314 return WINED3D_OK;
5315 case WINED3DERR_DEVICELOST:
5317 ResourceList *resourceList = This->resources;
5318 while (NULL != resourceList) {
5319 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5320 return WINED3DERR_DEVICENOTRESET;
5321 resourceList = resourceList->next;
5323 return WINED3DERR_DEVICELOST;
5325 case WINED3DERR_DRIVERINTERNALERROR:
5326 return WINED3DERR_DRIVERINTERNALERROR;
5329 /* Unknown state */
5330 return WINED3DERR_DRIVERINTERNALERROR;
5334 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5336 /** FIXME: Resource tracking needs to be done,
5337 * The closes we can do to this is set the priorities of all managed textures low
5338 * and then reset them.
5339 ***********************************************************/
5340 FIXME("(%p) : stub\n", This);
5341 return WINED3D_OK;
5344 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5345 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5347 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5348 if(surface->Flags & SFLAG_DIBSECTION) {
5349 /* Release the DC */
5350 SelectObject(surface->hDC, surface->dib.holdbitmap);
5351 DeleteDC(surface->hDC);
5352 /* Release the DIB section */
5353 DeleteObject(surface->dib.DIBsection);
5354 surface->dib.bitmap_data = NULL;
5355 surface->resource.allocatedMemory = NULL;
5356 surface->Flags &= ~SFLAG_DIBSECTION;
5358 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5359 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5360 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5361 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5362 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5363 } else {
5364 surface->pow2Width = surface->pow2Height = 1;
5365 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5366 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5368 if(surface->glDescription.textureName) {
5369 ENTER_GL();
5370 glDeleteTextures(1, &surface->glDescription.textureName);
5371 LEAVE_GL();
5372 surface->glDescription.textureName = 0;
5374 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5375 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5376 surface->Flags |= SFLAG_NONPOW2;
5377 } else {
5378 surface->Flags &= ~SFLAG_NONPOW2;
5380 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5381 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5384 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5386 IWineD3DSwapChainImpl *swapchain;
5387 HRESULT hr;
5388 BOOL DisplayModeChanged = FALSE;
5389 WINED3DDISPLAYMODE mode;
5390 TRACE("(%p)\n", This);
5392 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5393 if(FAILED(hr)) {
5394 ERR("Failed to get the first implicit swapchain\n");
5395 return hr;
5398 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5399 * on an existing gl context, so there's no real need for recreation.
5401 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5403 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5405 TRACE("New params:\n");
5406 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5407 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5408 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5409 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5410 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
5411 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
5412 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
5413 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
5414 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
5415 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5416 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
5417 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
5418 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
5420 /* No special treatment of these parameters. Just store them */
5421 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
5422 swapchain->presentParms.Flags = pPresentationParameters->Flags;
5423 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
5424 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
5426 /* What to do about these? */
5427 if(pPresentationParameters->BackBufferCount != 0 &&
5428 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
5429 ERR("Cannot change the back buffer count yet\n");
5431 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5432 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5433 ERR("Cannot change the back buffer format yet\n");
5435 if(pPresentationParameters->hDeviceWindow != NULL &&
5436 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
5437 ERR("Cannot change the device window yet\n");
5439 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
5440 ERR("What do do about a changed auto depth stencil parameter?\n");
5443 if(pPresentationParameters->Windowed) {
5444 mode.Width = swapchain->orig_width;
5445 mode.Height = swapchain->orig_height;
5446 mode.RefreshRate = 0;
5447 mode.Format = swapchain->presentParms.BackBufferFormat;
5448 } else {
5449 mode.Width = pPresentationParameters->BackBufferWidth;
5450 mode.Height = pPresentationParameters->BackBufferHeight;
5451 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
5452 mode.Format = swapchain->presentParms.BackBufferFormat;
5455 /* Should Width == 800 && Height == 0 set 800x600? */
5456 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
5457 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
5458 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5460 WINED3DVIEWPORT vp;
5461 int i;
5463 vp.X = 0;
5464 vp.Y = 0;
5465 vp.Width = pPresentationParameters->BackBufferWidth;
5466 vp.Height = pPresentationParameters->BackBufferHeight;
5467 vp.MinZ = 0;
5468 vp.MaxZ = 1;
5470 if(!pPresentationParameters->Windowed) {
5471 DisplayModeChanged = TRUE;
5473 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
5474 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
5476 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
5477 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
5478 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
5481 /* Now set the new viewport */
5482 IWineD3DDevice_SetViewport(iface, &vp);
5485 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
5486 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
5487 DisplayModeChanged) {
5489 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
5490 if(!pPresentationParameters->Windowed) {
5491 IWineD3DDevice_SetFullscreen(iface, TRUE);
5494 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
5496 /* Switching out of fullscreen mode? First set the original res, then change the window */
5497 if(pPresentationParameters->Windowed) {
5498 IWineD3DDevice_SetFullscreen(iface, FALSE);
5500 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
5503 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5504 return WINED3D_OK;
5507 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
5508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5509 /** FIXME: always true at the moment **/
5510 if(!bEnableDialogs) {
5511 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
5513 return WINED3D_OK;
5517 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
5518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5519 TRACE("(%p) : pParameters %p\n", This, pParameters);
5521 *pParameters = This->createParms;
5522 return WINED3D_OK;
5525 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
5526 IWineD3DSwapChain *swapchain;
5527 HRESULT hrc = WINED3D_OK;
5529 TRACE("Relaying to swapchain\n");
5531 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5532 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
5533 IWineD3DSwapChain_Release(swapchain);
5535 return;
5538 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
5539 IWineD3DSwapChain *swapchain;
5540 HRESULT hrc = WINED3D_OK;
5542 TRACE("Relaying to swapchain\n");
5544 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5545 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
5546 IWineD3DSwapChain_Release(swapchain);
5548 return;
5552 /** ********************************************************
5553 * Notification functions
5554 ** ********************************************************/
5555 /** This function must be called in the release of a resource when ref == 0,
5556 * the contents of resource must still be correct,
5557 * any handels to other resource held by the caller must be closed
5558 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
5559 *****************************************************/
5560 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5562 ResourceList* resourceList;
5564 TRACE("(%p) : resource %p\n", This, resource);
5565 #if 0
5566 EnterCriticalSection(&resourceStoreCriticalSection);
5567 #endif
5568 /* add a new texture to the frot of the linked list */
5569 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
5570 resourceList->resource = resource;
5572 /* Get the old head */
5573 resourceList->next = This->resources;
5575 This->resources = resourceList;
5576 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
5578 #if 0
5579 LeaveCriticalSection(&resourceStoreCriticalSection);
5580 #endif
5581 return;
5584 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5586 ResourceList* resourceList = NULL;
5587 ResourceList* previousResourceList = NULL;
5589 TRACE("(%p) : resource %p\n", This, resource);
5591 #if 0
5592 EnterCriticalSection(&resourceStoreCriticalSection);
5593 #endif
5594 resourceList = This->resources;
5596 while (resourceList != NULL) {
5597 if(resourceList->resource == resource) break;
5598 previousResourceList = resourceList;
5599 resourceList = resourceList->next;
5602 if (resourceList == NULL) {
5603 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
5604 #if 0
5605 LeaveCriticalSection(&resourceStoreCriticalSection);
5606 #endif
5607 return;
5608 } else {
5609 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
5611 /* make sure we don't leave a hole in the list */
5612 if (previousResourceList != NULL) {
5613 previousResourceList->next = resourceList->next;
5614 } else {
5615 This->resources = resourceList->next;
5618 #if 0
5619 LeaveCriticalSection(&resourceStoreCriticalSection);
5620 #endif
5621 return;
5625 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
5626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5627 int counter;
5629 TRACE("(%p) : resource %p\n", This, resource);
5630 switch(IWineD3DResource_GetType(resource)){
5631 case WINED3DRTYPE_SURFACE:
5632 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
5633 break;
5634 case WINED3DRTYPE_TEXTURE:
5635 case WINED3DRTYPE_CUBETEXTURE:
5636 case WINED3DRTYPE_VOLUMETEXTURE:
5637 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
5638 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5639 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5640 This->stateBlock->textures[counter] = NULL;
5642 if (This->updateStateBlock != This->stateBlock ){
5643 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5644 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5645 This->updateStateBlock->textures[counter] = NULL;
5649 break;
5650 case WINED3DRTYPE_VOLUME:
5651 /* TODO: nothing really? */
5652 break;
5653 case WINED3DRTYPE_VERTEXBUFFER:
5654 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
5656 int streamNumber;
5657 TRACE("Cleaning up stream pointers\n");
5659 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
5660 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
5661 FINDOUT: should changes.streamSource[StreamNumber] be set ?
5663 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5664 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
5665 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5666 This->updateStateBlock->streamSource[streamNumber] = 0;
5667 /* Set changed flag? */
5670 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) */
5671 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
5672 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5673 This->stateBlock->streamSource[streamNumber] = 0;
5676 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
5677 else { /* This shouldn't happen */
5678 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
5680 #endif
5684 break;
5685 case WINED3DRTYPE_INDEXBUFFER:
5686 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
5687 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5688 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5689 This->updateStateBlock->pIndexData = NULL;
5692 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
5693 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5694 This->stateBlock->pIndexData = NULL;
5698 break;
5699 default:
5700 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
5701 break;
5705 /* Remove the resoruce from the resourceStore */
5706 IWineD3DDeviceImpl_RemoveResource(iface, resource);
5708 TRACE("Resource released\n");
5712 /**********************************************************
5713 * IWineD3DDevice VTbl follows
5714 **********************************************************/
5716 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
5718 /*** IUnknown methods ***/
5719 IWineD3DDeviceImpl_QueryInterface,
5720 IWineD3DDeviceImpl_AddRef,
5721 IWineD3DDeviceImpl_Release,
5722 /*** IWineD3DDevice methods ***/
5723 IWineD3DDeviceImpl_GetParent,
5724 /*** Creation methods**/
5725 IWineD3DDeviceImpl_CreateVertexBuffer,
5726 IWineD3DDeviceImpl_CreateIndexBuffer,
5727 IWineD3DDeviceImpl_CreateStateBlock,
5728 IWineD3DDeviceImpl_CreateSurface,
5729 IWineD3DDeviceImpl_CreateTexture,
5730 IWineD3DDeviceImpl_CreateVolumeTexture,
5731 IWineD3DDeviceImpl_CreateVolume,
5732 IWineD3DDeviceImpl_CreateCubeTexture,
5733 IWineD3DDeviceImpl_CreateQuery,
5734 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
5735 IWineD3DDeviceImpl_CreateVertexDeclaration,
5736 IWineD3DDeviceImpl_CreateVertexShader,
5737 IWineD3DDeviceImpl_CreatePixelShader,
5738 IWineD3DDeviceImpl_CreatePalette,
5739 /*** Odd functions **/
5740 IWineD3DDeviceImpl_Init3D,
5741 IWineD3DDeviceImpl_Uninit3D,
5742 IWineD3DDeviceImpl_SetFullscreen,
5743 IWineD3DDeviceImpl_EvictManagedResources,
5744 IWineD3DDeviceImpl_GetAvailableTextureMem,
5745 IWineD3DDeviceImpl_GetBackBuffer,
5746 IWineD3DDeviceImpl_GetCreationParameters,
5747 IWineD3DDeviceImpl_GetDeviceCaps,
5748 IWineD3DDeviceImpl_GetDirect3D,
5749 IWineD3DDeviceImpl_GetDisplayMode,
5750 IWineD3DDeviceImpl_SetDisplayMode,
5751 IWineD3DDeviceImpl_GetHWND,
5752 IWineD3DDeviceImpl_SetHWND,
5753 IWineD3DDeviceImpl_GetNumberOfSwapChains,
5754 IWineD3DDeviceImpl_GetRasterStatus,
5755 IWineD3DDeviceImpl_GetSwapChain,
5756 IWineD3DDeviceImpl_Reset,
5757 IWineD3DDeviceImpl_SetDialogBoxMode,
5758 IWineD3DDeviceImpl_SetCursorProperties,
5759 IWineD3DDeviceImpl_SetCursorPosition,
5760 IWineD3DDeviceImpl_ShowCursor,
5761 IWineD3DDeviceImpl_TestCooperativeLevel,
5762 /*** Getters and setters **/
5763 IWineD3DDeviceImpl_SetClipPlane,
5764 IWineD3DDeviceImpl_GetClipPlane,
5765 IWineD3DDeviceImpl_SetClipStatus,
5766 IWineD3DDeviceImpl_GetClipStatus,
5767 IWineD3DDeviceImpl_SetCurrentTexturePalette,
5768 IWineD3DDeviceImpl_GetCurrentTexturePalette,
5769 IWineD3DDeviceImpl_SetDepthStencilSurface,
5770 IWineD3DDeviceImpl_GetDepthStencilSurface,
5771 IWineD3DDeviceImpl_SetFVF,
5772 IWineD3DDeviceImpl_GetFVF,
5773 IWineD3DDeviceImpl_SetGammaRamp,
5774 IWineD3DDeviceImpl_GetGammaRamp,
5775 IWineD3DDeviceImpl_SetIndices,
5776 IWineD3DDeviceImpl_GetIndices,
5777 IWineD3DDeviceImpl_SetBasevertexIndex,
5778 IWineD3DDeviceImpl_SetLight,
5779 IWineD3DDeviceImpl_GetLight,
5780 IWineD3DDeviceImpl_SetLightEnable,
5781 IWineD3DDeviceImpl_GetLightEnable,
5782 IWineD3DDeviceImpl_SetMaterial,
5783 IWineD3DDeviceImpl_GetMaterial,
5784 IWineD3DDeviceImpl_SetNPatchMode,
5785 IWineD3DDeviceImpl_GetNPatchMode,
5786 IWineD3DDeviceImpl_SetPaletteEntries,
5787 IWineD3DDeviceImpl_GetPaletteEntries,
5788 IWineD3DDeviceImpl_SetPixelShader,
5789 IWineD3DDeviceImpl_GetPixelShader,
5790 IWineD3DDeviceImpl_SetPixelShaderConstantB,
5791 IWineD3DDeviceImpl_GetPixelShaderConstantB,
5792 IWineD3DDeviceImpl_SetPixelShaderConstantI,
5793 IWineD3DDeviceImpl_GetPixelShaderConstantI,
5794 IWineD3DDeviceImpl_SetPixelShaderConstantF,
5795 IWineD3DDeviceImpl_GetPixelShaderConstantF,
5796 IWineD3DDeviceImpl_SetRenderState,
5797 IWineD3DDeviceImpl_GetRenderState,
5798 IWineD3DDeviceImpl_SetRenderTarget,
5799 IWineD3DDeviceImpl_GetRenderTarget,
5800 IWineD3DDeviceImpl_SetFrontBackBuffers,
5801 IWineD3DDeviceImpl_SetSamplerState,
5802 IWineD3DDeviceImpl_GetSamplerState,
5803 IWineD3DDeviceImpl_SetScissorRect,
5804 IWineD3DDeviceImpl_GetScissorRect,
5805 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
5806 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
5807 IWineD3DDeviceImpl_SetStreamSource,
5808 IWineD3DDeviceImpl_GetStreamSource,
5809 IWineD3DDeviceImpl_SetStreamSourceFreq,
5810 IWineD3DDeviceImpl_GetStreamSourceFreq,
5811 IWineD3DDeviceImpl_SetTexture,
5812 IWineD3DDeviceImpl_GetTexture,
5813 IWineD3DDeviceImpl_SetTextureStageState,
5814 IWineD3DDeviceImpl_GetTextureStageState,
5815 IWineD3DDeviceImpl_SetTransform,
5816 IWineD3DDeviceImpl_GetTransform,
5817 IWineD3DDeviceImpl_SetVertexDeclaration,
5818 IWineD3DDeviceImpl_GetVertexDeclaration,
5819 IWineD3DDeviceImpl_SetVertexShader,
5820 IWineD3DDeviceImpl_GetVertexShader,
5821 IWineD3DDeviceImpl_SetVertexShaderConstantB,
5822 IWineD3DDeviceImpl_GetVertexShaderConstantB,
5823 IWineD3DDeviceImpl_SetVertexShaderConstantI,
5824 IWineD3DDeviceImpl_GetVertexShaderConstantI,
5825 IWineD3DDeviceImpl_SetVertexShaderConstantF,
5826 IWineD3DDeviceImpl_GetVertexShaderConstantF,
5827 IWineD3DDeviceImpl_SetViewport,
5828 IWineD3DDeviceImpl_GetViewport,
5829 IWineD3DDeviceImpl_MultiplyTransform,
5830 IWineD3DDeviceImpl_ValidateDevice,
5831 IWineD3DDeviceImpl_ProcessVertices,
5832 /*** State block ***/
5833 IWineD3DDeviceImpl_BeginStateBlock,
5834 IWineD3DDeviceImpl_EndStateBlock,
5835 /*** Scene management ***/
5836 IWineD3DDeviceImpl_BeginScene,
5837 IWineD3DDeviceImpl_EndScene,
5838 IWineD3DDeviceImpl_Present,
5839 IWineD3DDeviceImpl_Clear,
5840 /*** Drawing ***/
5841 IWineD3DDeviceImpl_DrawPrimitive,
5842 IWineD3DDeviceImpl_DrawIndexedPrimitive,
5843 IWineD3DDeviceImpl_DrawPrimitiveUP,
5844 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
5845 IWineD3DDeviceImpl_DrawPrimitiveStrided,
5846 IWineD3DDeviceImpl_DrawRectPatch,
5847 IWineD3DDeviceImpl_DrawTriPatch,
5848 IWineD3DDeviceImpl_DeletePatch,
5849 IWineD3DDeviceImpl_ColorFill,
5850 IWineD3DDeviceImpl_UpdateTexture,
5851 IWineD3DDeviceImpl_UpdateSurface,
5852 IWineD3DDeviceImpl_GetFrontBufferData,
5853 /*** object tracking ***/
5854 IWineD3DDeviceImpl_ResourceReleased
5858 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
5859 WINED3DRS_ALPHABLENDENABLE ,
5860 WINED3DRS_ALPHAFUNC ,
5861 WINED3DRS_ALPHAREF ,
5862 WINED3DRS_ALPHATESTENABLE ,
5863 WINED3DRS_BLENDOP ,
5864 WINED3DRS_COLORWRITEENABLE ,
5865 WINED3DRS_DESTBLEND ,
5866 WINED3DRS_DITHERENABLE ,
5867 WINED3DRS_FILLMODE ,
5868 WINED3DRS_FOGDENSITY ,
5869 WINED3DRS_FOGEND ,
5870 WINED3DRS_FOGSTART ,
5871 WINED3DRS_LASTPIXEL ,
5872 WINED3DRS_SHADEMODE ,
5873 WINED3DRS_SRCBLEND ,
5874 WINED3DRS_STENCILENABLE ,
5875 WINED3DRS_STENCILFAIL ,
5876 WINED3DRS_STENCILFUNC ,
5877 WINED3DRS_STENCILMASK ,
5878 WINED3DRS_STENCILPASS ,
5879 WINED3DRS_STENCILREF ,
5880 WINED3DRS_STENCILWRITEMASK ,
5881 WINED3DRS_STENCILZFAIL ,
5882 WINED3DRS_TEXTUREFACTOR ,
5883 WINED3DRS_WRAP0 ,
5884 WINED3DRS_WRAP1 ,
5885 WINED3DRS_WRAP2 ,
5886 WINED3DRS_WRAP3 ,
5887 WINED3DRS_WRAP4 ,
5888 WINED3DRS_WRAP5 ,
5889 WINED3DRS_WRAP6 ,
5890 WINED3DRS_WRAP7 ,
5891 WINED3DRS_ZENABLE ,
5892 WINED3DRS_ZFUNC ,
5893 WINED3DRS_ZWRITEENABLE
5896 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
5897 WINED3DTSS_ADDRESSW ,
5898 WINED3DTSS_ALPHAARG0 ,
5899 WINED3DTSS_ALPHAARG1 ,
5900 WINED3DTSS_ALPHAARG2 ,
5901 WINED3DTSS_ALPHAOP ,
5902 WINED3DTSS_BUMPENVLOFFSET ,
5903 WINED3DTSS_BUMPENVLSCALE ,
5904 WINED3DTSS_BUMPENVMAT00 ,
5905 WINED3DTSS_BUMPENVMAT01 ,
5906 WINED3DTSS_BUMPENVMAT10 ,
5907 WINED3DTSS_BUMPENVMAT11 ,
5908 WINED3DTSS_COLORARG0 ,
5909 WINED3DTSS_COLORARG1 ,
5910 WINED3DTSS_COLORARG2 ,
5911 WINED3DTSS_COLOROP ,
5912 WINED3DTSS_RESULTARG ,
5913 WINED3DTSS_TEXCOORDINDEX ,
5914 WINED3DTSS_TEXTURETRANSFORMFLAGS
5917 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
5918 WINED3DSAMP_ADDRESSU ,
5919 WINED3DSAMP_ADDRESSV ,
5920 WINED3DSAMP_ADDRESSW ,
5921 WINED3DSAMP_BORDERCOLOR ,
5922 WINED3DSAMP_MAGFILTER ,
5923 WINED3DSAMP_MINFILTER ,
5924 WINED3DSAMP_MIPFILTER ,
5925 WINED3DSAMP_MIPMAPLODBIAS ,
5926 WINED3DSAMP_MAXMIPLEVEL ,
5927 WINED3DSAMP_MAXANISOTROPY ,
5928 WINED3DSAMP_SRGBTEXTURE ,
5929 WINED3DSAMP_ELEMENTINDEX
5932 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
5933 WINED3DRS_AMBIENT ,
5934 WINED3DRS_AMBIENTMATERIALSOURCE ,
5935 WINED3DRS_CLIPPING ,
5936 WINED3DRS_CLIPPLANEENABLE ,
5937 WINED3DRS_COLORVERTEX ,
5938 WINED3DRS_DIFFUSEMATERIALSOURCE ,
5939 WINED3DRS_EMISSIVEMATERIALSOURCE ,
5940 WINED3DRS_FOGDENSITY ,
5941 WINED3DRS_FOGEND ,
5942 WINED3DRS_FOGSTART ,
5943 WINED3DRS_FOGTABLEMODE ,
5944 WINED3DRS_FOGVERTEXMODE ,
5945 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
5946 WINED3DRS_LIGHTING ,
5947 WINED3DRS_LOCALVIEWER ,
5948 WINED3DRS_MULTISAMPLEANTIALIAS ,
5949 WINED3DRS_MULTISAMPLEMASK ,
5950 WINED3DRS_NORMALIZENORMALS ,
5951 WINED3DRS_PATCHEDGESTYLE ,
5952 WINED3DRS_POINTSCALE_A ,
5953 WINED3DRS_POINTSCALE_B ,
5954 WINED3DRS_POINTSCALE_C ,
5955 WINED3DRS_POINTSCALEENABLE ,
5956 WINED3DRS_POINTSIZE ,
5957 WINED3DRS_POINTSIZE_MAX ,
5958 WINED3DRS_POINTSIZE_MIN ,
5959 WINED3DRS_POINTSPRITEENABLE ,
5960 WINED3DRS_RANGEFOGENABLE ,
5961 WINED3DRS_SPECULARMATERIALSOURCE ,
5962 WINED3DRS_TWEENFACTOR ,
5963 WINED3DRS_VERTEXBLEND
5966 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
5967 WINED3DTSS_TEXCOORDINDEX ,
5968 WINED3DTSS_TEXTURETRANSFORMFLAGS
5971 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
5972 WINED3DSAMP_DMAPOFFSET
5975 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
5976 DWORD rep = StateTable[state].representative;
5977 DWORD idx;
5978 BYTE shift;
5979 UINT i;
5980 WineD3DContext *context;
5982 if(!rep) return;
5983 for(i = 0; i < This->numContexts; i++) {
5984 context = This->contexts[i];
5985 if(isStateDirty(context, rep)) continue;
5987 context->dirtyArray[context->numDirtyEntries++] = rep;
5988 idx = rep >> 5;
5989 shift = rep & 0x1f;
5990 context->isStateDirty[idx] |= (1 << shift);