wined3d: Flip the coordinate system rather than the coordinates itself for onscreen...
[wine.git] / dlls / wined3d / device.c
blob2ad92dab0092fa70b90968cf9681036f81713763
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-2007 Henri Verbeet
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include <stdio.h>
29 #ifdef HAVE_FLOAT_H
30 # include <float.h>
31 #endif
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
35 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
37 /* Define the default light parameters as specified by MSDN */
38 const WINED3DLIGHT WINED3D_default_light = {
40 WINED3DLIGHT_DIRECTIONAL, /* Type */
41 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
42 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
44 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
45 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
46 0.0, /* Range */
47 0.0, /* Falloff */
48 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
49 0.0, /* Theta */
50 0.0 /* Phi */
53 /* x11drv GDI escapes */
54 #define X11DRV_ESCAPE 6789
55 enum x11drv_escape_codes
57 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
58 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
59 X11DRV_GET_FONT, /* get current X font for a DC */
62 /* retrieve the X display to use on a given DC */
63 static inline Display *get_display( HDC hdc )
65 Display *display;
66 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
68 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
69 sizeof(display), (LPSTR)&display )) display = NULL;
70 return display;
73 /* static function declarations */
74 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
76 /* helper macros */
77 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
79 #define D3DCREATEOBJECTINSTANCE(object, type) { \
80 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
81 D3DMEMCHECK(object, pp##type); \
82 object->lpVtbl = &IWineD3D##type##_Vtbl; \
83 object->wineD3DDevice = This; \
84 object->parent = parent; \
85 object->ref = 1; \
86 *pp##type = (IWineD3D##type *) object; \
89 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
90 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
91 D3DMEMCHECK(object, pp##type); \
92 object->lpVtbl = &IWineD3D##type##_Vtbl; \
93 object->parent = parent; \
94 object->ref = 1; \
95 object->baseShader.device = (IWineD3DDevice*) This; \
96 list_init(&object->baseShader.linked_programs); \
97 *pp##type = (IWineD3D##type *) object; \
100 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
101 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
102 D3DMEMCHECK(object, pp##type); \
103 object->lpVtbl = &IWineD3D##type##_Vtbl; \
104 object->resource.wineD3DDevice = This; \
105 object->resource.parent = parent; \
106 object->resource.resourceType = d3dtype; \
107 object->resource.ref = 1; \
108 object->resource.pool = Pool; \
109 object->resource.format = Format; \
110 object->resource.usage = Usage; \
111 object->resource.size = _size; \
112 /* Check that we have enough video ram left */ \
113 if (Pool == WINED3DPOOL_DEFAULT) { \
114 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
115 WARN("Out of 'bogus' video memory\n"); \
116 HeapFree(GetProcessHeap(), 0, object); \
117 *pp##type = NULL; \
118 return WINED3DERR_OUTOFVIDEOMEMORY; \
120 globalChangeGlRam(_size); \
122 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
123 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
124 FIXME("Out of memory!\n"); \
125 HeapFree(GetProcessHeap(), 0, object); \
126 *pp##type = NULL; \
127 return WINED3DERR_OUTOFVIDEOMEMORY; \
129 *pp##type = (IWineD3D##type *) object; \
130 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
131 TRACE("(%p) : Created resource %p\n", This, object); \
134 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
135 _basetexture.levels = Levels; \
136 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
137 _basetexture.LOD = 0; \
138 _basetexture.dirty = TRUE; \
141 /**********************************************************
142 * Global variable / Constants follow
143 **********************************************************/
144 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
146 /**********************************************************
147 * IUnknown parts follows
148 **********************************************************/
150 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
154 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
155 if (IsEqualGUID(riid, &IID_IUnknown)
156 || IsEqualGUID(riid, &IID_IWineD3DBase)
157 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
158 IUnknown_AddRef(iface);
159 *ppobj = This;
160 return S_OK;
162 *ppobj = NULL;
163 return E_NOINTERFACE;
166 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
168 ULONG refCount = InterlockedIncrement(&This->ref);
170 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
171 return refCount;
174 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
176 ULONG refCount = InterlockedDecrement(&This->ref);
178 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
180 if (!refCount) {
181 if (This->fbo) {
182 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
184 if (This->src_fbo) {
185 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
187 if (This->dst_fbo) {
188 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
191 HeapFree(GetProcessHeap(), 0, This->render_targets);
192 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
193 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
195 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
197 /* TODO: Clean up all the surfaces and textures! */
198 /* NOTE: You must release the parent if the object was created via a callback
199 ** ***************************/
201 /* Release the update stateblock */
202 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
203 if(This->updateStateBlock != This->stateBlock)
204 FIXME("(%p) Something's still holding the Update stateblock\n",This);
206 This->updateStateBlock = NULL;
207 { /* because were not doing proper internal refcounts releasing the primary state block
208 causes recursion with the extra checks in ResourceReleased, to avoid this we have
209 to set this->stateBlock = NULL; first */
210 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
211 This->stateBlock = NULL;
213 /* Release the stateblock */
214 if(IWineD3DStateBlock_Release(stateBlock) > 0){
215 FIXME("(%p) Something's still holding the Update stateblock\n",This);
219 if (This->resources != NULL ) {
220 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
221 dumpResources(This->resources);
224 if(This->contexts) ERR("Context array not freed!\n");
226 IWineD3D_Release(This->wineD3D);
227 This->wineD3D = NULL;
228 HeapFree(GetProcessHeap(), 0, This);
229 TRACE("Freed device %p\n", This);
230 This = NULL;
232 return refCount;
235 /**********************************************************
236 * IWineD3DDevice implementation follows
237 **********************************************************/
238 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
240 *pParent = This->parent;
241 IUnknown_AddRef(This->parent);
242 return WINED3D_OK;
245 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
246 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
247 GLenum error, glUsage;
248 DWORD vboUsage = object->resource.usage;
249 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
250 WARN("Creating a vbo failed once, not trying again\n");
251 return;
254 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
256 ENTER_GL();
257 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
258 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
260 /* Make sure that the gl error is cleared. Do not use checkGLcall
261 * here because checkGLcall just prints a fixme and continues. However,
262 * if an error during VBO creation occurs we can fall back to non-vbo operation
263 * with full functionality(but performance loss)
265 while(glGetError() != GL_NO_ERROR);
267 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
268 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
269 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
270 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
271 * to check if the rhw and color values are in the correct format.
274 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
275 error = glGetError();
276 if(object->vbo == 0 || error != GL_NO_ERROR) {
277 WARN("Failed to create a VBO with error %d\n", error);
278 goto error;
281 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
282 error = glGetError();
283 if(error != GL_NO_ERROR) {
284 WARN("Failed to bind the VBO, error %d\n", error);
285 goto error;
288 /* Don't use static, because dx apps tend to update the buffer
289 * quite often even if they specify 0 usage. Because we always keep the local copy
290 * we never read from the vbo and can create a write only opengl buffer.
292 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
293 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
294 case WINED3DUSAGE_DYNAMIC:
295 TRACE("Gl usage = GL_STREAM_DRAW\n");
296 glUsage = GL_STREAM_DRAW_ARB;
297 break;
298 case WINED3DUSAGE_WRITEONLY:
299 default:
300 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
301 glUsage = GL_DYNAMIC_DRAW_ARB;
302 break;
305 /* Reserve memory for the buffer. The amount of data won't change
306 * so we are safe with calling glBufferData once with a NULL ptr and
307 * calling glBufferSubData on updates
309 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
310 error = glGetError();
311 if(error != GL_NO_ERROR) {
312 WARN("glBufferDataARB failed with error %d\n", error);
313 goto error;
316 LEAVE_GL();
318 return;
319 error:
320 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
321 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
322 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
323 object->vbo = 0;
324 object->Flags |= VBFLAG_VBOCREATEFAIL;
325 LEAVE_GL();
326 return;
329 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
330 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
331 IUnknown *parent) {
332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
333 IWineD3DVertexBufferImpl *object;
334 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
335 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
336 BOOL conv;
338 if(Size == 0) {
339 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
340 *ppVertexBuffer = NULL;
341 return WINED3DERR_INVALIDCALL;
344 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
346 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
347 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
349 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
350 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
352 object->fvf = FVF;
354 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
355 * drawStridedFast (half-life 2).
357 * Basically converting the vertices in the buffer is quite expensive, and observations
358 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
359 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
361 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
362 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
363 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
364 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
365 * dx7 apps.
366 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
367 * more. In this call we can convert dx7 buffers too.
369 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
370 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
371 (dxVersion > 7 || !conv) ) {
372 CreateVBO(object);
374 return WINED3D_OK;
377 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
378 GLenum error, glUsage;
379 TRACE("Creating VBO for Index Buffer %p\n", object);
381 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
382 * restored on the next draw
384 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
386 ENTER_GL();
387 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
388 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
390 while(glGetError());
392 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
393 error = glGetError();
394 if(error != GL_NO_ERROR || object->vbo == 0) {
395 ERR("Creating a vbo failed, continueing without vbo for this buffer\n");
396 goto out;
399 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
400 error = glGetError();
401 if(error != GL_NO_ERROR) {
402 ERR("Failed to bind index buffer, continueing without vbo for this buffer\n");
403 goto out;
406 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
407 * copy no readback will be needed
409 glUsage = GL_STATIC_DRAW_ARB;
410 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
411 error = glGetError();
412 if(error != GL_NO_ERROR) {
413 ERR("Failed to initialize the index buffer\n");
414 goto out;
416 LEAVE_GL();
417 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
418 return;
420 out:
421 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
422 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
423 LEAVE_GL();
424 object->vbo = 0;
427 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
428 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
429 HANDLE *sharedHandle, IUnknown *parent) {
430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
431 IWineD3DIndexBufferImpl *object;
432 TRACE("(%p) Creating index buffer\n", This);
434 /* Allocate the storage for the device */
435 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
437 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
438 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
441 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
442 CreateIndexBufferVBO(This, object);
445 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
446 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
447 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
449 return WINED3D_OK;
452 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
455 IWineD3DStateBlockImpl *object;
456 int i, j;
457 HRESULT temp_result;
459 D3DCREATEOBJECTINSTANCE(object, StateBlock)
460 object->blockType = Type;
462 for(i = 0; i < LIGHTMAP_SIZE; i++) {
463 list_init(&object->lightMap[i]);
466 /* Special case - Used during initialization to produce a placeholder stateblock
467 so other functions called can update a state block */
468 if (Type == WINED3DSBT_INIT) {
469 /* Don't bother increasing the reference count otherwise a device will never
470 be freed due to circular dependencies */
471 return WINED3D_OK;
474 temp_result = allocate_shader_constants(object);
475 if (WINED3D_OK != temp_result)
476 return temp_result;
478 /* Otherwise, might as well set the whole state block to the appropriate values */
479 if (This->stateBlock != NULL)
480 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
481 else
482 memset(object->streamFreq, 1, sizeof(object->streamFreq));
484 /* Reset the ref and type after kludging it */
485 object->wineD3DDevice = This;
486 object->ref = 1;
487 object->blockType = Type;
489 TRACE("Updating changed flags appropriate for type %d\n", Type);
491 if (Type == WINED3DSBT_ALL) {
493 TRACE("ALL => Pretend everything has changed\n");
494 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
496 /* Lights are not part of the changed / set structure */
497 for(j = 0; j < LIGHTMAP_SIZE; j++) {
498 struct list *e;
499 LIST_FOR_EACH(e, &object->lightMap[j]) {
500 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
501 light->changed = TRUE;
502 light->enabledChanged = TRUE;
505 } else if (Type == WINED3DSBT_PIXELSTATE) {
507 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
508 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
510 object->changed.pixelShader = TRUE;
512 /* Pixel Shader Constants */
513 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
514 object->changed.pixelShaderConstantsF[i] = TRUE;
515 for (i = 0; i < MAX_CONST_B; ++i)
516 object->changed.pixelShaderConstantsB[i] = TRUE;
517 for (i = 0; i < MAX_CONST_I; ++i)
518 object->changed.pixelShaderConstantsI[i] = TRUE;
520 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
521 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
523 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
524 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
525 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
528 for (j = 0 ; j < 16; j++) {
529 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
531 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
535 } else if (Type == WINED3DSBT_VERTEXSTATE) {
537 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
538 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
540 object->changed.vertexShader = TRUE;
542 /* Vertex Shader Constants */
543 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
544 object->changed.vertexShaderConstantsF[i] = TRUE;
545 for (i = 0; i < MAX_CONST_B; ++i)
546 object->changed.vertexShaderConstantsB[i] = TRUE;
547 for (i = 0; i < MAX_CONST_I; ++i)
548 object->changed.vertexShaderConstantsI[i] = TRUE;
550 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
551 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
553 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
554 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
555 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
558 for (j = 0 ; j < 16; j++){
559 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
560 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
564 for(j = 0; j < LIGHTMAP_SIZE; j++) {
565 struct list *e;
566 LIST_FOR_EACH(e, &object->lightMap[j]) {
567 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
568 light->changed = TRUE;
569 light->enabledChanged = TRUE;
572 } else {
573 FIXME("Unrecognized state block type %d\n", Type);
576 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
577 return WINED3D_OK;
581 /* ************************************
582 MSDN:
583 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
585 Discard
586 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
588 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.
590 ******************************** */
592 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) {
593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
594 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
595 unsigned int pow2Width, pow2Height;
596 unsigned int Size = 1;
597 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
598 TRACE("(%p) Create surface\n",This);
600 /** FIXME: Check ranges on the inputs are valid
601 * MSDN
602 * MultisampleQuality
603 * [in] Quality level. The valid range is between zero and one less than the level
604 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
605 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
606 * values of paired render targets, depth stencil surfaces, and the MultiSample type
607 * must all match.
608 *******************************/
612 * TODO: Discard MSDN
613 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
615 * If this flag is set, the contents of the depth stencil buffer will be
616 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
617 * with a different depth surface.
619 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
620 ***************************/
622 if(MultisampleQuality < 0) {
623 FIXME("Invalid multisample level %d\n", MultisampleQuality);
624 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
627 if(MultisampleQuality > 0) {
628 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
629 MultisampleQuality=0;
632 /** FIXME: Check that the format is supported
633 * by the device.
634 *******************************/
636 /* Non-power2 support */
637 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
638 pow2Width = Width;
639 pow2Height = Height;
640 } else {
641 /* Find the nearest pow2 match */
642 pow2Width = pow2Height = 1;
643 while (pow2Width < Width) pow2Width <<= 1;
644 while (pow2Height < Height) pow2Height <<= 1;
647 if (pow2Width > Width || pow2Height > Height) {
648 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
649 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
650 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
651 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
652 This, Width, Height);
653 return WINED3DERR_NOTAVAILABLE;
657 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
658 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
659 * space!
660 *********************************/
661 if (WINED3DFMT_UNKNOWN == Format) {
662 Size = 0;
663 } else if (Format == WINED3DFMT_DXT1) {
664 /* DXT1 is half byte per pixel */
665 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
667 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
668 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
669 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
670 } else {
671 /* The pitch is a multiple of 4 bytes */
672 Size = ((Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
673 Size *= Height;
676 /** Create and initialise the surface resource **/
677 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
678 /* "Standalone" surface */
679 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
681 object->currentDesc.Width = Width;
682 object->currentDesc.Height = Height;
683 object->currentDesc.MultiSampleType = MultiSample;
684 object->currentDesc.MultiSampleQuality = MultisampleQuality;
686 /* Setup some glformat defaults */
687 object->glDescription.glFormat = tableEntry->glFormat;
688 object->glDescription.glFormatInternal = tableEntry->glInternal;
689 object->glDescription.glType = tableEntry->glType;
691 object->glDescription.textureName = 0;
692 object->glDescription.level = Level;
693 object->glDescription.target = GL_TEXTURE_2D;
695 /* Internal data */
696 object->pow2Width = pow2Width;
697 object->pow2Height = pow2Height;
699 /* Flags */
700 object->Flags = SFLAG_DYNLOCK;
701 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
702 object->Flags |= Discard ? SFLAG_DISCARD : 0;
703 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
704 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
707 if (WINED3DFMT_UNKNOWN != Format) {
708 object->bytesPerPixel = tableEntry->bpp;
709 } else {
710 object->bytesPerPixel = 0;
713 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
715 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
717 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
718 * this function is too deep to need to care about things like this.
719 * Levels need to be checked too, and possibly Type since they all affect what can be done.
720 * ****************************************/
721 switch(Pool) {
722 case WINED3DPOOL_SCRATCH:
723 if(!Lockable)
724 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
725 "which are mutually exclusive, setting lockable to TRUE\n");
726 Lockable = TRUE;
727 break;
728 case WINED3DPOOL_SYSTEMMEM:
729 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
730 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
731 case WINED3DPOOL_MANAGED:
732 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
733 "Usage of DYNAMIC which are mutually exclusive, not doing "
734 "anything just telling you.\n");
735 break;
736 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
737 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
738 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
739 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
740 break;
741 default:
742 FIXME("(%p) Unknown pool %d\n", This, Pool);
743 break;
746 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
747 FIXME("Trying to create a render target that isn't in the default pool\n");
750 /* mark the texture as dirty so that it gets loaded first time around*/
751 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
752 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
753 This, Width, Height, Format, debug_d3dformat(Format),
754 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
756 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
757 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
758 This->ddraw_primary = (IWineD3DSurface *) object;
760 /* Look at the implementation and set the correct Vtable */
761 switch(Impl) {
762 case SURFACE_OPENGL:
763 /* Nothing to do, it's set already */
764 break;
766 case SURFACE_GDI:
767 object->lpVtbl = &IWineGDISurface_Vtbl;
768 break;
770 default:
771 /* To be sure to catch this */
772 ERR("Unknown requested surface implementation %d!\n", Impl);
773 IWineD3DSurface_Release((IWineD3DSurface *) object);
774 return WINED3DERR_INVALIDCALL;
777 list_init(&object->renderbuffers);
779 /* Call the private setup routine */
780 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
784 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
785 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
786 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
787 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
790 IWineD3DTextureImpl *object;
791 unsigned int i;
792 UINT tmpW;
793 UINT tmpH;
794 HRESULT hr;
795 unsigned int pow2Width;
796 unsigned int pow2Height;
799 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
800 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
801 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
803 /* TODO: It should only be possible to create textures for formats
804 that are reported as supported */
805 if (WINED3DFMT_UNKNOWN >= Format) {
806 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
807 return WINED3DERR_INVALIDCALL;
810 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
811 D3DINITIALIZEBASETEXTURE(object->baseTexture);
812 object->width = Width;
813 object->height = Height;
815 /** Non-power2 support **/
816 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
817 pow2Width = Width;
818 pow2Height = Height;
819 } else {
820 /* Find the nearest pow2 match */
821 pow2Width = pow2Height = 1;
822 while (pow2Width < Width) pow2Width <<= 1;
823 while (pow2Height < Height) pow2Height <<= 1;
826 /** FIXME: add support for real non-power-two if it's provided by the video card **/
827 /* Precalculated scaling for 'faked' non power of two texture coords */
828 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
829 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
830 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
832 object->baseTexture.format = Format;
834 /* Calculate levels for mip mapping */
835 if (Levels == 0) {
836 TRACE("calculating levels %d\n", object->baseTexture.levels);
837 object->baseTexture.levels++;
838 tmpW = Width;
839 tmpH = Height;
840 while (tmpW > 1 || tmpH > 1) {
841 tmpW = max(1, tmpW >> 1);
842 tmpH = max(1, tmpH >> 1);
843 object->baseTexture.levels++;
845 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
848 /* Generate all the surfaces */
849 tmpW = Width;
850 tmpH = Height;
851 for (i = 0; i < object->baseTexture.levels; i++)
853 /* use the callback to create the texture surface */
854 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
855 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
856 FIXME("Failed to create surface %p\n", object);
857 /* clean up */
858 object->surfaces[i] = NULL;
859 IWineD3DTexture_Release((IWineD3DTexture *)object);
861 *ppTexture = NULL;
862 return hr;
865 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
866 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
867 /* calculate the next mipmap level */
868 tmpW = max(1, tmpW >> 1);
869 tmpH = max(1, tmpH >> 1);
872 TRACE("(%p) : Created texture %p\n", This, object);
873 return WINED3D_OK;
876 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
877 UINT Width, UINT Height, UINT Depth,
878 UINT Levels, DWORD Usage,
879 WINED3DFORMAT Format, WINED3DPOOL Pool,
880 IWineD3DVolumeTexture **ppVolumeTexture,
881 HANDLE *pSharedHandle, IUnknown *parent,
882 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
885 IWineD3DVolumeTextureImpl *object;
886 unsigned int i;
887 UINT tmpW;
888 UINT tmpH;
889 UINT tmpD;
891 /* TODO: It should only be possible to create textures for formats
892 that are reported as supported */
893 if (WINED3DFMT_UNKNOWN >= Format) {
894 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
895 return WINED3DERR_INVALIDCALL;
898 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
899 D3DINITIALIZEBASETEXTURE(object->baseTexture);
901 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
902 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
904 object->width = Width;
905 object->height = Height;
906 object->depth = Depth;
907 object->baseTexture.format = Format;
909 /* Calculate levels for mip mapping */
910 if (Levels == 0) {
911 object->baseTexture.levels++;
912 tmpW = Width;
913 tmpH = Height;
914 tmpD = Depth;
915 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
916 tmpW = max(1, tmpW >> 1);
917 tmpH = max(1, tmpH >> 1);
918 tmpD = max(1, tmpD >> 1);
919 object->baseTexture.levels++;
921 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
924 /* Generate all the surfaces */
925 tmpW = Width;
926 tmpH = Height;
927 tmpD = Depth;
929 for (i = 0; i < object->baseTexture.levels; i++)
931 HRESULT hr;
932 /* Create the volume */
933 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
934 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
936 if(FAILED(hr)) {
937 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
938 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
939 *ppVolumeTexture = NULL;
940 return hr;
943 /* Set its container to this object */
944 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
946 /* calcualte the next mipmap level */
947 tmpW = max(1, tmpW >> 1);
948 tmpH = max(1, tmpH >> 1);
949 tmpD = max(1, tmpD >> 1);
952 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
953 TRACE("(%p) : Created volume texture %p\n", This, object);
954 return WINED3D_OK;
957 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
958 UINT Width, UINT Height, UINT Depth,
959 DWORD Usage,
960 WINED3DFORMAT Format, WINED3DPOOL Pool,
961 IWineD3DVolume** ppVolume,
962 HANDLE* pSharedHandle, IUnknown *parent) {
964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
965 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
966 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
968 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
970 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
971 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
973 object->currentDesc.Width = Width;
974 object->currentDesc.Height = Height;
975 object->currentDesc.Depth = Depth;
976 object->bytesPerPixel = formatDesc->bpp;
978 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
979 object->lockable = TRUE;
980 object->locked = FALSE;
981 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
982 object->dirty = TRUE;
984 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
987 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
988 UINT Levels, DWORD Usage,
989 WINED3DFORMAT Format, WINED3DPOOL Pool,
990 IWineD3DCubeTexture **ppCubeTexture,
991 HANDLE *pSharedHandle, IUnknown *parent,
992 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
995 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
996 unsigned int i, j;
997 UINT tmpW;
998 HRESULT hr;
999 unsigned int pow2EdgeLength = EdgeLength;
1001 /* TODO: It should only be possible to create textures for formats
1002 that are reported as supported */
1003 if (WINED3DFMT_UNKNOWN >= Format) {
1004 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1005 return WINED3DERR_INVALIDCALL;
1008 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1009 WARN("(%p) : Tried to create not supported cube texture\n", This);
1010 return WINED3DERR_INVALIDCALL;
1013 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1014 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1016 TRACE("(%p) Create Cube Texture\n", This);
1018 /** Non-power2 support **/
1020 /* Find the nearest pow2 match */
1021 pow2EdgeLength = 1;
1022 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1024 object->edgeLength = EdgeLength;
1025 /* TODO: support for native non-power 2 */
1026 /* Precalculated scaling for 'faked' non power of two texture coords */
1027 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1028 object->baseTexture.format = Format;
1030 /* Calculate levels for mip mapping */
1031 if (Levels == 0) {
1032 object->baseTexture.levels++;
1033 tmpW = EdgeLength;
1034 while (tmpW > 1) {
1035 tmpW = max(1, tmpW >> 1);
1036 object->baseTexture.levels++;
1038 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1041 /* Generate all the surfaces */
1042 tmpW = EdgeLength;
1043 for (i = 0; i < object->baseTexture.levels; i++) {
1045 /* Create the 6 faces */
1046 for (j = 0; j < 6; j++) {
1048 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1049 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1051 if(hr!= WINED3D_OK) {
1052 /* clean up */
1053 int k;
1054 int l;
1055 for (l = 0; l < j; l++) {
1056 IWineD3DSurface_Release(object->surfaces[j][i]);
1058 for (k = 0; k < i; k++) {
1059 for (l = 0; l < 6; l++) {
1060 IWineD3DSurface_Release(object->surfaces[l][j]);
1064 FIXME("(%p) Failed to create surface\n",object);
1065 HeapFree(GetProcessHeap(),0,object);
1066 *ppCubeTexture = NULL;
1067 return hr;
1069 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1070 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1072 tmpW = max(1, tmpW >> 1);
1075 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1076 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1077 return WINED3D_OK;
1080 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1082 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1083 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1085 /* Just a check to see if we support this type of query */
1086 switch(Type) {
1087 case WINED3DQUERYTYPE_OCCLUSION:
1088 TRACE("(%p) occlusion query\n", This);
1089 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1090 hr = WINED3D_OK;
1091 else
1092 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1093 break;
1095 case WINED3DQUERYTYPE_EVENT:
1096 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1097 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1098 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1100 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1102 hr = WINED3D_OK;
1103 break;
1105 case WINED3DQUERYTYPE_VCACHE:
1106 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1107 case WINED3DQUERYTYPE_VERTEXSTATS:
1108 case WINED3DQUERYTYPE_TIMESTAMP:
1109 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1110 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1111 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1112 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1113 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1114 case WINED3DQUERYTYPE_PIXELTIMINGS:
1115 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1116 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1117 default:
1118 FIXME("(%p) Unhandled query type %d\n", This, Type);
1120 if(NULL == ppQuery || hr != WINED3D_OK) {
1121 return hr;
1124 D3DCREATEOBJECTINSTANCE(object, Query)
1125 object->type = Type;
1126 /* allocated the 'extended' data based on the type of query requested */
1127 switch(Type){
1128 case WINED3DQUERYTYPE_OCCLUSION:
1129 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1130 TRACE("(%p) Allocating data for an occlusion query\n", This);
1131 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1132 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1133 break;
1135 case WINED3DQUERYTYPE_EVENT:
1136 /* TODO: GL_APPLE_fence */
1137 if(GL_SUPPORT(APPLE_FENCE)) {
1138 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1139 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1140 checkGLcall("glGenFencesAPPLE");
1141 } else if(GL_SUPPORT(NV_FENCE)) {
1142 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1143 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1144 checkGLcall("glGenFencesNV");
1146 break;
1148 case WINED3DQUERYTYPE_VCACHE:
1149 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1150 case WINED3DQUERYTYPE_VERTEXSTATS:
1151 case WINED3DQUERYTYPE_TIMESTAMP:
1152 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1153 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1154 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1155 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1156 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1157 case WINED3DQUERYTYPE_PIXELTIMINGS:
1158 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1159 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1160 default:
1161 object->extendedData = 0;
1162 FIXME("(%p) Unhandled query type %d\n",This , Type);
1164 TRACE("(%p) : Created Query %p\n", This, object);
1165 return WINED3D_OK;
1168 /*****************************************************************************
1169 * IWineD3DDeviceImpl_SetupFullscreenWindow
1171 * Helper function that modifies a HWND's Style and ExStyle for proper
1172 * fullscreen use.
1174 * Params:
1175 * iface: Pointer to the IWineD3DDevice interface
1176 * window: Window to setup
1178 *****************************************************************************/
1179 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1182 LONG style, exStyle;
1183 /* Don't do anything if an original style is stored.
1184 * That shouldn't happen
1186 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1187 if (This->style || This->exStyle) {
1188 ERR("(%p): Want to change the window parameters of HWND %p, but "
1189 "another style is stored for restoration afterwards\n", This, window);
1192 /* Get the parameters and save them */
1193 style = GetWindowLongW(window, GWL_STYLE);
1194 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1195 This->style = style;
1196 This->exStyle = exStyle;
1198 /* Filter out window decorations */
1199 style &= ~WS_CAPTION;
1200 style &= ~WS_THICKFRAME;
1201 exStyle &= ~WS_EX_WINDOWEDGE;
1202 exStyle &= ~WS_EX_CLIENTEDGE;
1204 /* Make sure the window is managed, otherwise we won't get keyboard input */
1205 style |= WS_POPUP | WS_SYSMENU;
1207 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1208 This->style, This->exStyle, style, exStyle);
1210 SetWindowLongW(window, GWL_STYLE, style);
1211 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1213 /* Inform the window about the update. */
1214 SetWindowPos(window, HWND_TOP, 0, 0,
1215 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1216 ShowWindow(window, SW_NORMAL);
1219 /*****************************************************************************
1220 * IWineD3DDeviceImpl_RestoreWindow
1222 * Helper function that restores a windows' properties when taking it out
1223 * of fullscreen mode
1225 * Params:
1226 * iface: Pointer to the IWineD3DDevice interface
1227 * window: Window to setup
1229 *****************************************************************************/
1230 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1233 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1234 * switch, do nothing
1236 if (!This->style && !This->exStyle) return;
1238 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1239 This, window, This->style, This->exStyle);
1241 SetWindowLongW(window, GWL_STYLE, This->style);
1242 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1244 /* Delete the old values */
1245 This->style = 0;
1246 This->exStyle = 0;
1248 /* Inform the window about the update */
1249 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1250 0, 0, 0, 0, /* Pos, Size, ignored */
1251 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1254 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1255 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1256 IUnknown* parent,
1257 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1258 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1261 HDC hDc;
1262 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1263 HRESULT hr = WINED3D_OK;
1264 IUnknown *bufferParent;
1265 Display *display;
1267 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1269 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1270 * does a device hold a reference to a swap chain giving them a lifetime of the device
1271 * or does the swap chain notify the device of its destruction.
1272 *******************************/
1274 /* Check the params */
1275 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1276 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1277 return WINED3DERR_INVALIDCALL;
1278 } else if (pPresentationParameters->BackBufferCount > 1) {
1279 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");
1282 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1284 /*********************
1285 * Lookup the window Handle and the relating X window handle
1286 ********************/
1288 /* Setup hwnd we are using, plus which display this equates to */
1289 object->win_handle = pPresentationParameters->hDeviceWindow;
1290 if (!object->win_handle) {
1291 object->win_handle = This->createParms.hFocusWindow;
1294 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1295 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1296 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1297 return WINED3DERR_NOTAVAILABLE;
1299 hDc = GetDC(object->win_handle);
1300 display = get_display(hDc);
1301 ReleaseDC(object->win_handle, hDc);
1302 TRACE("Using a display of %p %p\n", display, hDc);
1304 if (NULL == display || NULL == hDc) {
1305 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1306 return WINED3DERR_NOTAVAILABLE;
1309 if (object->win == 0) {
1310 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1311 return WINED3DERR_NOTAVAILABLE;
1314 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1315 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1316 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1318 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1319 * then the corresponding dimension of the client area of the hDeviceWindow
1320 * (or the focus window, if hDeviceWindow is NULL) is taken.
1321 **********************/
1323 if (pPresentationParameters->Windowed &&
1324 ((pPresentationParameters->BackBufferWidth == 0) ||
1325 (pPresentationParameters->BackBufferHeight == 0))) {
1327 RECT Rect;
1328 GetClientRect(object->win_handle, &Rect);
1330 if (pPresentationParameters->BackBufferWidth == 0) {
1331 pPresentationParameters->BackBufferWidth = Rect.right;
1332 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1334 if (pPresentationParameters->BackBufferHeight == 0) {
1335 pPresentationParameters->BackBufferHeight = Rect.bottom;
1336 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1340 /* Put the correct figures in the presentation parameters */
1341 TRACE("Copying across presentation parameters\n");
1342 object->presentParms = *pPresentationParameters;
1344 TRACE("calling rendertarget CB\n");
1345 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1346 parent,
1347 object->presentParms.BackBufferWidth,
1348 object->presentParms.BackBufferHeight,
1349 object->presentParms.BackBufferFormat,
1350 object->presentParms.MultiSampleType,
1351 object->presentParms.MultiSampleQuality,
1352 TRUE /* Lockable */,
1353 &object->frontBuffer,
1354 NULL /* pShared (always null)*/);
1355 if (object->frontBuffer != NULL) {
1356 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1357 } else {
1358 ERR("Failed to create the front buffer\n");
1359 goto error;
1363 * Create an opengl context for the display visual
1364 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1365 * use different properties after that point in time. FIXME: How to handle when requested format
1366 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1367 * it chooses is identical to the one already being used!
1368 **********************************/
1369 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1371 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1372 if(!object->context) {
1374 object->num_contexts = 1;
1376 ENTER_GL();
1377 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1378 LEAVE_GL();
1380 if (!object->context) {
1381 ERR("Failed to create a new context\n");
1382 hr = WINED3DERR_NOTAVAILABLE;
1383 goto error;
1384 } else {
1385 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1386 object->win_handle, object->context[0]->glCtx, object->win);
1389 /*********************
1390 * Windowed / Fullscreen
1391 *******************/
1394 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1395 * so we should really check to see if there is a fullscreen swapchain already
1396 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1397 **************************************/
1399 if (!pPresentationParameters->Windowed) {
1401 DEVMODEW devmode;
1402 HDC hdc;
1403 int bpp = 0;
1404 RECT clip_rc;
1406 /* Get info on the current display setup */
1407 hdc = GetDC(0);
1408 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1409 ReleaseDC(0, hdc);
1411 /* Change the display settings */
1412 memset(&devmode, 0, sizeof(DEVMODEW));
1413 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1414 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1415 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1416 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1417 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1418 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1420 /* For GetDisplayMode */
1421 This->ddraw_width = devmode.dmPelsWidth;
1422 This->ddraw_height = devmode.dmPelsHeight;
1423 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1425 IWineD3DDevice_SetFullscreen(iface, TRUE);
1427 /* And finally clip mouse to our screen */
1428 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1429 ClipCursor(&clip_rc);
1432 /*********************
1433 * Create the back, front and stencil buffers
1434 *******************/
1435 if(object->presentParms.BackBufferCount > 0) {
1436 int i;
1438 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1439 if(!object->backBuffer) {
1440 ERR("Out of memory\n");
1441 hr = E_OUTOFMEMORY;
1442 goto error;
1445 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1446 TRACE("calling rendertarget CB\n");
1447 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1448 parent,
1449 object->presentParms.BackBufferWidth,
1450 object->presentParms.BackBufferHeight,
1451 object->presentParms.BackBufferFormat,
1452 object->presentParms.MultiSampleType,
1453 object->presentParms.MultiSampleQuality,
1454 TRUE /* Lockable */,
1455 &object->backBuffer[i],
1456 NULL /* pShared (always null)*/);
1457 if(hr == WINED3D_OK && object->backBuffer[i]) {
1458 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1459 } else {
1460 ERR("Cannot create new back buffer\n");
1461 goto error;
1463 ENTER_GL();
1464 glDrawBuffer(GL_BACK);
1465 checkGLcall("glDrawBuffer(GL_BACK)");
1466 LEAVE_GL();
1468 } else {
1469 object->backBuffer = NULL;
1471 /* Single buffering - draw to front buffer */
1472 ENTER_GL();
1473 glDrawBuffer(GL_FRONT);
1474 checkGLcall("glDrawBuffer(GL_FRONT)");
1475 LEAVE_GL();
1478 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1479 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1480 TRACE("Creating depth stencil buffer\n");
1481 if (This->depthStencilBuffer == NULL ) {
1482 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1483 parent,
1484 object->presentParms.BackBufferWidth,
1485 object->presentParms.BackBufferHeight,
1486 object->presentParms.AutoDepthStencilFormat,
1487 object->presentParms.MultiSampleType,
1488 object->presentParms.MultiSampleQuality,
1489 FALSE /* FIXME: Discard */,
1490 &This->depthStencilBuffer,
1491 NULL /* pShared (always null)*/ );
1492 if (This->depthStencilBuffer != NULL)
1493 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1496 /** TODO: A check on width, height and multisample types
1497 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1498 ****************************/
1499 object->wantsDepthStencilBuffer = TRUE;
1500 } else {
1501 object->wantsDepthStencilBuffer = FALSE;
1504 TRACE("Created swapchain %p\n", object);
1505 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1506 return WINED3D_OK;
1508 error:
1509 if (object->backBuffer) {
1510 int i;
1511 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1512 if(object->backBuffer[i]) {
1513 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1514 IUnknown_Release(bufferParent); /* once for the get parent */
1515 if (IUnknown_Release(bufferParent) > 0) {
1516 FIXME("(%p) Something's still holding the back buffer\n",This);
1520 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1521 object->backBuffer = NULL;
1523 if(object->context) {
1524 DestroyContext(This, object->context[0]);
1526 if(object->frontBuffer) {
1527 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1528 IUnknown_Release(bufferParent); /* once for the get parent */
1529 if (IUnknown_Release(bufferParent) > 0) {
1530 FIXME("(%p) Something's still holding the front buffer\n",This);
1533 HeapFree(GetProcessHeap(), 0, object);
1534 return hr;
1537 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1538 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1540 TRACE("(%p)\n", This);
1542 return This->NumberOfSwapChains;
1545 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1547 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1549 if(iSwapChain < This->NumberOfSwapChains) {
1550 *pSwapChain = This->swapchains[iSwapChain];
1551 IWineD3DSwapChain_AddRef(*pSwapChain);
1552 TRACE("(%p) returning %p\n", This, *pSwapChain);
1553 return WINED3D_OK;
1554 } else {
1555 TRACE("Swapchain out of range\n");
1556 *pSwapChain = NULL;
1557 return WINED3DERR_INVALIDCALL;
1561 /*****
1562 * Vertex Declaration
1563 *****/
1564 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1565 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1567 IWineD3DVertexDeclarationImpl *object = NULL;
1568 HRESULT hr = WINED3D_OK;
1570 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1571 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1573 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1575 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1577 return hr;
1580 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1582 unsigned int idx, idx2;
1583 unsigned int offset;
1584 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1585 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1586 BOOL has_blend_idx = has_blend &&
1587 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1588 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1589 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1590 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1591 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1592 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1593 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1595 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1596 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1598 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1599 WINED3DVERTEXELEMENT *elements = NULL;
1601 unsigned int size;
1602 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1603 if (has_blend_idx) num_blends--;
1605 /* Compute declaration size */
1606 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1607 has_psize + has_diffuse + has_specular + num_textures + 1;
1609 /* convert the declaration */
1610 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1611 if (!elements)
1612 return 0;
1614 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1615 idx = 0;
1616 if (has_pos) {
1617 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1618 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1619 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1621 else {
1622 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1623 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1625 elements[idx].UsageIndex = 0;
1626 idx++;
1628 if (has_blend && (num_blends > 0)) {
1629 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1630 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1631 else
1632 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1633 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1634 elements[idx].UsageIndex = 0;
1635 idx++;
1637 if (has_blend_idx) {
1638 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1639 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1640 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1641 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1642 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1643 else
1644 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1645 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1646 elements[idx].UsageIndex = 0;
1647 idx++;
1649 if (has_normal) {
1650 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1651 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1652 elements[idx].UsageIndex = 0;
1653 idx++;
1655 if (has_psize) {
1656 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1657 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1658 elements[idx].UsageIndex = 0;
1659 idx++;
1661 if (has_diffuse) {
1662 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1663 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1664 elements[idx].UsageIndex = 0;
1665 idx++;
1667 if (has_specular) {
1668 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1669 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1670 elements[idx].UsageIndex = 1;
1671 idx++;
1673 for (idx2 = 0; idx2 < num_textures; idx2++) {
1674 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1675 switch (numcoords) {
1676 case WINED3DFVF_TEXTUREFORMAT1:
1677 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1678 break;
1679 case WINED3DFVF_TEXTUREFORMAT2:
1680 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1681 break;
1682 case WINED3DFVF_TEXTUREFORMAT3:
1683 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1684 break;
1685 case WINED3DFVF_TEXTUREFORMAT4:
1686 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1687 break;
1689 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1690 elements[idx].UsageIndex = idx2;
1691 idx++;
1694 /* Now compute offsets, and initialize the rest of the fields */
1695 for (idx = 0, offset = 0; idx < size-1; idx++) {
1696 elements[idx].Stream = 0;
1697 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1698 elements[idx].Offset = offset;
1699 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1702 *ppVertexElements = elements;
1703 return size;
1706 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1707 WINED3DVERTEXELEMENT* elements = NULL;
1708 size_t size;
1709 DWORD hr;
1711 size = ConvertFvfToDeclaration(Fvf, &elements);
1712 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1714 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1715 HeapFree(GetProcessHeap(), 0, elements);
1716 if (hr != S_OK) return hr;
1718 return WINED3D_OK;
1721 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1722 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1724 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1725 HRESULT hr = WINED3D_OK;
1726 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1727 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1729 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1731 if (vertex_declaration) {
1732 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1735 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1737 if (WINED3D_OK != hr) {
1738 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1739 IWineD3DVertexShader_Release(*ppVertexShader);
1740 return WINED3DERR_INVALIDCALL;
1743 return WINED3D_OK;
1746 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1748 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1749 HRESULT hr = WINED3D_OK;
1751 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1752 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1753 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1754 if (WINED3D_OK == hr) {
1755 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1756 } else {
1757 WARN("(%p) : Failed to create pixel shader\n", This);
1760 return hr;
1763 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1765 IWineD3DPaletteImpl *object;
1766 HRESULT hr;
1767 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1769 /* Create the new object */
1770 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1771 if(!object) {
1772 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1773 return E_OUTOFMEMORY;
1776 object->lpVtbl = &IWineD3DPalette_Vtbl;
1777 object->ref = 1;
1778 object->Flags = Flags;
1779 object->parent = Parent;
1780 object->wineD3DDevice = This;
1781 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1783 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1785 if(!object->hpal) {
1786 HeapFree( GetProcessHeap(), 0, object);
1787 return E_OUTOFMEMORY;
1790 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1791 if(FAILED(hr)) {
1792 IWineD3DPalette_Release((IWineD3DPalette *) object);
1793 return hr;
1796 *Palette = (IWineD3DPalette *) object;
1798 return WINED3D_OK;
1801 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1803 IWineD3DSwapChainImpl *swapchain;
1804 DWORD state;
1806 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1807 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1809 /* TODO: Test if OpenGL is compiled in and loaded */
1811 /* Initialize the texture unit mapping to a 1:1 mapping */
1812 for(state = 0; state < MAX_SAMPLERS; state++) {
1813 This->texUnitMap[state] = state;
1815 This->oneToOneTexUnitMap = TRUE;
1817 /* Setup the implicit swapchain */
1818 TRACE("Creating implicit swapchain\n");
1819 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain)) || !swapchain) {
1820 WARN("Failed to create implicit swapchain\n");
1821 return WINED3DERR_INVALIDCALL;
1824 This->NumberOfSwapChains = 1;
1825 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1826 if(!This->swapchains) {
1827 ERR("Out of memory!\n");
1828 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1829 return E_OUTOFMEMORY;
1831 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1833 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1835 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1836 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1837 This->render_targets[0] = swapchain->backBuffer[0];
1838 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1840 else {
1841 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1842 This->render_targets[0] = swapchain->frontBuffer;
1843 This->lastActiveRenderTarget = swapchain->frontBuffer;
1845 IWineD3DSurface_AddRef(This->render_targets[0]);
1846 This->activeContext = swapchain->context[0];
1848 /* Depth Stencil support */
1849 This->stencilBufferTarget = This->depthStencilBuffer;
1850 if (NULL != This->stencilBufferTarget) {
1851 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1854 /* Set up some starting GL setup */
1855 ENTER_GL();
1857 * Initialize openGL extension related variables
1858 * with Default values
1861 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps(This->wineD3D, swapchain->context[0]->display);
1862 /* Setup all the devices defaults */
1863 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1864 #if 0
1865 IWineD3DImpl_CheckGraphicsMemory();
1866 #endif
1868 { /* Set a default viewport */
1869 WINED3DVIEWPORT vp;
1870 vp.X = 0;
1871 vp.Y = 0;
1872 vp.Width = pPresentationParameters->BackBufferWidth;
1873 vp.Height = pPresentationParameters->BackBufferHeight;
1874 vp.MinZ = 0.0f;
1875 vp.MaxZ = 1.0f;
1876 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1879 /* Initialize the current view state */
1880 This->view_ident = 1;
1881 This->contexts[0]->last_was_rhw = 0;
1882 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1883 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1885 switch(wined3d_settings.offscreen_rendering_mode) {
1886 case ORM_FBO:
1887 case ORM_PBUFFER:
1888 This->offscreenBuffer = GL_BACK;
1889 break;
1891 case ORM_BACKBUFFER:
1893 if(GL_LIMITS(aux_buffers) > 0) {
1894 TRACE("Using auxilliary buffer for offscreen rendering\n");
1895 This->offscreenBuffer = GL_AUX0;
1896 } else {
1897 TRACE("Using back buffer for offscreen rendering\n");
1898 This->offscreenBuffer = GL_BACK;
1903 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1904 LEAVE_GL();
1906 /* Clear the screen */
1907 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1908 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1909 0x00, 1.0, 0);
1911 This->d3d_initialized = TRUE;
1912 return WINED3D_OK;
1915 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1917 int sampler;
1918 uint i;
1919 TRACE("(%p)\n", This);
1921 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1923 ENTER_GL();
1924 /* I don't think that the interface guarants that the device is destroyed from the same thread
1925 * it was created. Thus make sure a context is active for the glDelete* calls
1927 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1928 LEAVE_GL();
1930 /* Delete the pbuffer context if there is any */
1931 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1933 /* Delete the mouse cursor texture */
1934 if(This->cursorTexture) {
1935 ENTER_GL();
1936 glDeleteTextures(1, &This->cursorTexture);
1937 LEAVE_GL();
1938 This->cursorTexture = 0;
1941 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1942 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1945 /* Release the buffers (with sanity checks)*/
1946 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1947 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1948 if(This->depthStencilBuffer != This->stencilBufferTarget)
1949 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1951 This->stencilBufferTarget = NULL;
1953 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1954 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1955 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1957 TRACE("Setting rendertarget to NULL\n");
1958 This->render_targets[0] = NULL;
1960 if (This->depthStencilBuffer) {
1961 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1962 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1964 This->depthStencilBuffer = NULL;
1967 for(i=0; i < This->NumberOfSwapChains; i++) {
1968 TRACE("Releasing the implicit swapchain %d\n", i);
1969 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1970 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1974 HeapFree(GetProcessHeap(), 0, This->swapchains);
1975 This->swapchains = NULL;
1976 This->NumberOfSwapChains = 0;
1978 This->d3d_initialized = FALSE;
1979 return WINED3D_OK;
1982 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1984 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1986 /* Setup the window for fullscreen mode */
1987 if(fullscreen && !This->ddraw_fullscreen) {
1988 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1989 } else if(!fullscreen && This->ddraw_fullscreen) {
1990 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1993 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1994 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1995 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1996 * separately.
1998 This->ddraw_fullscreen = fullscreen;
2001 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2002 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2003 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2005 * There is no way to deactivate thread safety once it is enabled
2007 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2009 FIXME("No thread safety in wined3d yet\n");
2011 /*For now just store the flag(needed in case of ddraw) */
2012 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2014 return;
2017 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2018 DEVMODEW devmode;
2019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2020 LONG ret;
2021 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2022 RECT clip_rc;
2024 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2026 /* Resize the screen even without a window:
2027 * The app could have unset it with SetCooperativeLevel, but not called
2028 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2029 * but we don't have any hwnd
2032 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2033 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2034 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2035 devmode.dmPelsWidth = pMode->Width;
2036 devmode.dmPelsHeight = pMode->Height;
2038 devmode.dmDisplayFrequency = pMode->RefreshRate;
2039 if (pMode->RefreshRate != 0) {
2040 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2043 /* Only change the mode if necessary */
2044 if( (This->ddraw_width == pMode->Width) &&
2045 (This->ddraw_height == pMode->Height) &&
2046 (This->ddraw_format == pMode->Format) &&
2047 (pMode->RefreshRate == 0) ) {
2048 return WINED3D_OK;
2051 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2052 if (ret != DISP_CHANGE_SUCCESSFUL) {
2053 if(devmode.dmDisplayFrequency != 0) {
2054 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2055 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2056 devmode.dmDisplayFrequency = 0;
2057 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2059 if(ret != DISP_CHANGE_SUCCESSFUL) {
2060 return WINED3DERR_NOTAVAILABLE;
2064 /* Store the new values */
2065 This->ddraw_width = pMode->Width;
2066 This->ddraw_height = pMode->Height;
2067 This->ddraw_format = pMode->Format;
2069 /* Only do this with a window of course */
2070 if(This->ddraw_window)
2071 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2073 /* And finally clip mouse to our screen */
2074 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2075 ClipCursor(&clip_rc);
2077 return WINED3D_OK;
2080 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2082 *ppD3D= This->wineD3D;
2083 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2084 IWineD3D_AddRef(*ppD3D);
2085 return WINED3D_OK;
2088 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2089 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2090 * into the video ram as possible and seeing how many fit
2091 * you can also get the correct initial value from nvidia and ATI's driver via X
2092 * texture memory is video memory + AGP memory
2093 *******************/
2094 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2095 static BOOL showfixmes = TRUE;
2096 if (showfixmes) {
2097 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2098 (wined3d_settings.emulated_textureram/(1024*1024)),
2099 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2100 showfixmes = FALSE;
2102 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2103 (wined3d_settings.emulated_textureram/(1024*1024)),
2104 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2105 /* return simulated texture memory left */
2106 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2111 /*****
2112 * Get / Set FVF
2113 *****/
2114 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2117 /* Update the current state block */
2118 This->updateStateBlock->changed.fvf = TRUE;
2119 This->updateStateBlock->set.fvf = TRUE;
2121 if(This->updateStateBlock->fvf == fvf) {
2122 TRACE("Application is setting the old fvf over, nothing to do\n");
2123 return WINED3D_OK;
2126 This->updateStateBlock->fvf = fvf;
2127 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2128 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2129 return WINED3D_OK;
2133 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2135 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2136 *pfvf = This->stateBlock->fvf;
2137 return WINED3D_OK;
2140 /*****
2141 * Get / Set Stream Source
2142 *****/
2143 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2145 IWineD3DVertexBuffer *oldSrc;
2147 if (StreamNumber >= MAX_STREAMS) {
2148 WARN("Stream out of range %d\n", StreamNumber);
2149 return WINED3DERR_INVALIDCALL;
2152 oldSrc = This->stateBlock->streamSource[StreamNumber];
2153 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2155 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2156 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2158 if(oldSrc == pStreamData &&
2159 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2160 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2161 TRACE("Application is setting the old values over, nothing to do\n");
2162 return WINED3D_OK;
2165 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2166 if (pStreamData) {
2167 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2168 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2171 /* Handle recording of state blocks */
2172 if (This->isRecordingState) {
2173 TRACE("Recording... not performing anything\n");
2174 return WINED3D_OK;
2177 /* Need to do a getParent and pass the reffs up */
2178 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2179 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2180 so for now, just count internally */
2181 if (pStreamData != NULL) {
2182 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2183 InterlockedIncrement(&vbImpl->bindCount);
2185 if (oldSrc != NULL) {
2186 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2189 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2191 return WINED3D_OK;
2194 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2197 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2198 This->stateBlock->streamSource[StreamNumber],
2199 This->stateBlock->streamOffset[StreamNumber],
2200 This->stateBlock->streamStride[StreamNumber]);
2202 if (StreamNumber >= MAX_STREAMS) {
2203 WARN("Stream out of range %d\n", StreamNumber);
2204 return WINED3DERR_INVALIDCALL;
2206 *pStream = This->stateBlock->streamSource[StreamNumber];
2207 *pStride = This->stateBlock->streamStride[StreamNumber];
2208 if (pOffset) {
2209 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2212 if (*pStream != NULL) {
2213 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2215 return WINED3D_OK;
2218 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2219 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2220 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2221 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2223 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2224 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2226 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2227 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2228 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2230 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2231 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2232 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2235 return WINED3D_OK;
2238 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2241 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2242 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2244 TRACE("(%p) : returning %d\n", This, *Divider);
2246 return WINED3D_OK;
2249 /*****
2250 * Get / Set & Multiply Transform
2251 *****/
2252 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2255 /* Most of this routine, comments included copied from ddraw tree initially: */
2256 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2258 /* Handle recording of state blocks */
2259 if (This->isRecordingState) {
2260 TRACE("Recording... not performing anything\n");
2261 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2262 This->updateStateBlock->set.transform[d3dts] = TRUE;
2263 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2264 return WINED3D_OK;
2268 * If the new matrix is the same as the current one,
2269 * we cut off any further processing. this seems to be a reasonable
2270 * optimization because as was noticed, some apps (warcraft3 for example)
2271 * tend towards setting the same matrix repeatedly for some reason.
2273 * From here on we assume that the new matrix is different, wherever it matters.
2275 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2276 TRACE("The app is setting the same matrix over again\n");
2277 return WINED3D_OK;
2278 } else {
2279 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2283 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2284 where ViewMat = Camera space, WorldMat = world space.
2286 In OpenGL, camera and world space is combined into GL_MODELVIEW
2287 matrix. The Projection matrix stay projection matrix.
2290 /* Capture the times we can just ignore the change for now */
2291 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2292 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2293 /* Handled by the state manager */
2296 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2297 return WINED3D_OK;
2300 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2302 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2303 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2304 return WINED3D_OK;
2307 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2308 WINED3DMATRIX *mat = NULL;
2309 WINED3DMATRIX temp;
2311 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2312 * below means it will be recorded in a state block change, but it
2313 * works regardless where it is recorded.
2314 * If this is found to be wrong, change to StateBlock.
2316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2317 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2319 if (State < HIGHEST_TRANSFORMSTATE)
2321 mat = &This->updateStateBlock->transforms[State];
2322 } else {
2323 FIXME("Unhandled transform state!!\n");
2326 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2328 /* Apply change via set transform - will reapply to eg. lights this way */
2329 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2332 /*****
2333 * Get / Set Light
2334 *****/
2335 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2336 you can reference any indexes you want as long as that number max are enabled at any
2337 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2338 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2339 but when recording, just build a chain pretty much of commands to be replayed. */
2341 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2342 float rho;
2343 PLIGHTINFOEL *object = NULL;
2344 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2345 struct list *e;
2347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2348 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2350 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2351 * the gl driver.
2353 if(!pLight) {
2354 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2355 return WINED3DERR_INVALIDCALL;
2358 switch(pLight->Type) {
2359 case WINED3DLIGHT_POINT:
2360 case WINED3DLIGHT_SPOT:
2361 case WINED3DLIGHT_PARALLELPOINT:
2362 case WINED3DLIGHT_GLSPOT:
2363 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2364 * most wanted
2366 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2367 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2368 return WINED3DERR_INVALIDCALL;
2370 break;
2372 case WINED3DLIGHT_DIRECTIONAL:
2373 /* Ignores attenuation */
2374 break;
2376 default:
2377 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2378 return WINED3DERR_INVALIDCALL;
2381 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2382 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2383 if(object->OriginalIndex == Index) break;
2384 object = NULL;
2387 if(!object) {
2388 TRACE("Adding new light\n");
2389 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2390 if(!object) {
2391 ERR("Out of memory error when allocating a light\n");
2392 return E_OUTOFMEMORY;
2394 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2395 object->glIndex = -1;
2396 object->OriginalIndex = Index;
2397 object->changed = TRUE;
2400 /* Initialize the object */
2401 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,
2402 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2403 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2404 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2405 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2406 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2407 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2409 /* Save away the information */
2410 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2412 switch (pLight->Type) {
2413 case WINED3DLIGHT_POINT:
2414 /* Position */
2415 object->lightPosn[0] = pLight->Position.x;
2416 object->lightPosn[1] = pLight->Position.y;
2417 object->lightPosn[2] = pLight->Position.z;
2418 object->lightPosn[3] = 1.0f;
2419 object->cutoff = 180.0f;
2420 /* FIXME: Range */
2421 break;
2423 case WINED3DLIGHT_DIRECTIONAL:
2424 /* Direction */
2425 object->lightPosn[0] = -pLight->Direction.x;
2426 object->lightPosn[1] = -pLight->Direction.y;
2427 object->lightPosn[2] = -pLight->Direction.z;
2428 object->lightPosn[3] = 0.0;
2429 object->exponent = 0.0f;
2430 object->cutoff = 180.0f;
2431 break;
2433 case WINED3DLIGHT_SPOT:
2434 /* Position */
2435 object->lightPosn[0] = pLight->Position.x;
2436 object->lightPosn[1] = pLight->Position.y;
2437 object->lightPosn[2] = pLight->Position.z;
2438 object->lightPosn[3] = 1.0;
2440 /* Direction */
2441 object->lightDirn[0] = pLight->Direction.x;
2442 object->lightDirn[1] = pLight->Direction.y;
2443 object->lightDirn[2] = pLight->Direction.z;
2444 object->lightDirn[3] = 1.0;
2447 * opengl-ish and d3d-ish spot lights use too different models for the
2448 * light "intensity" as a function of the angle towards the main light direction,
2449 * so we only can approximate very roughly.
2450 * however spot lights are rather rarely used in games (if ever used at all).
2451 * furthermore if still used, probably nobody pays attention to such details.
2453 if (pLight->Falloff == 0) {
2454 rho = 6.28f;
2455 } else {
2456 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2458 if (rho < 0.0001) rho = 0.0001f;
2459 object->exponent = -0.3/log(cos(rho/2));
2460 if (object->exponent > 128.0) {
2461 object->exponent = 128.0;
2463 object->cutoff = pLight->Phi*90/M_PI;
2465 /* FIXME: Range */
2466 break;
2468 default:
2469 FIXME("Unrecognized light type %d\n", pLight->Type);
2472 /* Update the live definitions if the light is currently assigned a glIndex */
2473 if (object->glIndex != -1 && !This->isRecordingState) {
2474 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2476 return WINED3D_OK;
2479 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2480 PLIGHTINFOEL *lightInfo = NULL;
2481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2482 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2483 struct list *e;
2484 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2486 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2487 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2488 if(lightInfo->OriginalIndex == Index) break;
2489 lightInfo = NULL;
2492 if (lightInfo == NULL) {
2493 TRACE("Light information requested but light not defined\n");
2494 return WINED3DERR_INVALIDCALL;
2497 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2498 return WINED3D_OK;
2501 /*****
2502 * Get / Set Light Enable
2503 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2504 *****/
2505 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2506 PLIGHTINFOEL *lightInfo = NULL;
2507 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2508 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2509 struct list *e;
2510 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2512 /* Tests show true = 128...not clear why */
2513 Enable = Enable? 128: 0;
2515 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2516 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2517 if(lightInfo->OriginalIndex == Index) break;
2518 lightInfo = NULL;
2520 TRACE("Found light: %p\n", lightInfo);
2522 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2523 if (lightInfo == NULL) {
2525 TRACE("Light enabled requested but light not defined, so defining one!\n");
2526 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2528 /* Search for it again! Should be fairly quick as near head of list */
2529 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2530 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2531 if(lightInfo->OriginalIndex == Index) break;
2532 lightInfo = NULL;
2534 if (lightInfo == NULL) {
2535 FIXME("Adding default lights has failed dismally\n");
2536 return WINED3DERR_INVALIDCALL;
2540 lightInfo->enabledChanged = TRUE;
2541 if(!Enable) {
2542 if(lightInfo->glIndex != -1) {
2543 if(!This->isRecordingState) {
2544 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2547 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2548 lightInfo->glIndex = -1;
2549 } else {
2550 TRACE("Light already disabled, nothing to do\n");
2552 } else {
2553 if (lightInfo->glIndex != -1) {
2554 /* nop */
2555 TRACE("Nothing to do as light was enabled\n");
2556 } else {
2557 int i;
2558 /* Find a free gl light */
2559 for(i = 0; i < This->maxConcurrentLights; i++) {
2560 if(This->stateBlock->activeLights[i] == NULL) {
2561 This->stateBlock->activeLights[i] = lightInfo;
2562 lightInfo->glIndex = i;
2563 break;
2566 if(lightInfo->glIndex == -1) {
2567 ERR("Too many concurrently active lights\n");
2568 return WINED3DERR_INVALIDCALL;
2571 /* i == lightInfo->glIndex */
2572 if(!This->isRecordingState) {
2573 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2578 return WINED3D_OK;
2581 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2583 PLIGHTINFOEL *lightInfo = NULL;
2584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2585 struct list *e;
2586 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2587 TRACE("(%p) : for idx(%d)\n", This, Index);
2589 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2590 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2591 if(lightInfo->OriginalIndex == Index) break;
2592 lightInfo = NULL;
2595 if (lightInfo == NULL) {
2596 TRACE("Light enabled state requested but light not defined\n");
2597 return WINED3DERR_INVALIDCALL;
2599 /* true is 128 according to SetLightEnable */
2600 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2601 return WINED3D_OK;
2604 /*****
2605 * Get / Set Clip Planes
2606 *****/
2607 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2609 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2611 /* Validate Index */
2612 if (Index >= GL_LIMITS(clipplanes)) {
2613 TRACE("Application has requested clipplane this device doesn't support\n");
2614 return WINED3DERR_INVALIDCALL;
2617 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2618 This->updateStateBlock->set.clipplane[Index] = TRUE;
2620 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2621 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2622 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2623 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2624 TRACE("Application is setting old values over, nothing to do\n");
2625 return WINED3D_OK;
2628 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2629 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2630 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2631 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2633 /* Handle recording of state blocks */
2634 if (This->isRecordingState) {
2635 TRACE("Recording... not performing anything\n");
2636 return WINED3D_OK;
2639 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2641 return WINED3D_OK;
2644 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2646 TRACE("(%p) : for idx %d\n", This, Index);
2648 /* Validate Index */
2649 if (Index >= GL_LIMITS(clipplanes)) {
2650 TRACE("Application has requested clipplane this device doesn't support\n");
2651 return WINED3DERR_INVALIDCALL;
2654 pPlane[0] = This->stateBlock->clipplane[Index][0];
2655 pPlane[1] = This->stateBlock->clipplane[Index][1];
2656 pPlane[2] = This->stateBlock->clipplane[Index][2];
2657 pPlane[3] = This->stateBlock->clipplane[Index][3];
2658 return WINED3D_OK;
2661 /*****
2662 * Get / Set Clip Plane Status
2663 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2664 *****/
2665 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2666 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2667 FIXME("(%p) : stub\n", This);
2668 if (NULL == pClipStatus) {
2669 return WINED3DERR_INVALIDCALL;
2671 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2672 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2673 return WINED3D_OK;
2676 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2678 FIXME("(%p) : stub\n", This);
2679 if (NULL == pClipStatus) {
2680 return WINED3DERR_INVALIDCALL;
2682 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2683 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2684 return WINED3D_OK;
2687 /*****
2688 * Get / Set Material
2689 *****/
2690 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2693 This->updateStateBlock->changed.material = TRUE;
2694 This->updateStateBlock->set.material = TRUE;
2695 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2697 /* Handle recording of state blocks */
2698 if (This->isRecordingState) {
2699 TRACE("Recording... not performing anything\n");
2700 return WINED3D_OK;
2703 ENTER_GL();
2704 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2705 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2706 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2707 pMaterial->Ambient.b, pMaterial->Ambient.a);
2708 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2709 pMaterial->Specular.b, pMaterial->Specular.a);
2710 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2711 pMaterial->Emissive.b, pMaterial->Emissive.a);
2712 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2714 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2715 checkGLcall("glMaterialfv(GL_AMBIENT)");
2716 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2717 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2719 /* Only change material color if specular is enabled, otherwise it is set to black */
2720 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2721 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2722 checkGLcall("glMaterialfv(GL_SPECULAR");
2723 } else {
2724 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2725 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2726 checkGLcall("glMaterialfv(GL_SPECULAR");
2728 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2729 checkGLcall("glMaterialfv(GL_EMISSION)");
2730 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2731 checkGLcall("glMaterialf(GL_SHININESS");
2733 LEAVE_GL();
2734 return WINED3D_OK;
2737 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2739 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2740 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2741 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2742 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2743 pMaterial->Ambient.b, pMaterial->Ambient.a);
2744 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2745 pMaterial->Specular.b, pMaterial->Specular.a);
2746 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2747 pMaterial->Emissive.b, pMaterial->Emissive.a);
2748 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2750 return WINED3D_OK;
2753 /*****
2754 * Get / Set Indices
2755 *****/
2756 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2757 UINT BaseVertexIndex) {
2758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2759 IWineD3DIndexBuffer *oldIdxs;
2760 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2762 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2763 oldIdxs = This->updateStateBlock->pIndexData;
2765 This->updateStateBlock->changed.indices = TRUE;
2766 This->updateStateBlock->set.indices = TRUE;
2767 This->updateStateBlock->pIndexData = pIndexData;
2768 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2770 /* Handle recording of state blocks */
2771 if (This->isRecordingState) {
2772 TRACE("Recording... not performing anything\n");
2773 return WINED3D_OK;
2776 /* The base vertex index affects the stream sources, while
2777 * The index buffer is a seperate index buffer state
2779 if(BaseVertexIndex != oldBaseIndex) {
2780 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2782 if(oldIdxs != pIndexData) {
2783 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2785 return WINED3D_OK;
2788 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2791 *ppIndexData = This->stateBlock->pIndexData;
2793 /* up ref count on ppindexdata */
2794 if (*ppIndexData) {
2795 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2796 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2797 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2798 }else{
2799 TRACE("(%p) No index data set\n", This);
2801 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2803 return WINED3D_OK;
2806 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2807 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2809 TRACE("(%p)->(%d)\n", This, BaseIndex);
2811 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2812 TRACE("Application is setting the old value over, nothing to do\n");
2813 return WINED3D_OK;
2816 This->updateStateBlock->baseVertexIndex = BaseIndex;
2818 if (This->isRecordingState) {
2819 TRACE("Recording... not performing anything\n");
2820 return WINED3D_OK;
2822 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2823 return WINED3D_OK;
2826 /*****
2827 * Get / Set Viewports
2828 *****/
2829 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2832 TRACE("(%p)\n", This);
2833 This->updateStateBlock->changed.viewport = TRUE;
2834 This->updateStateBlock->set.viewport = TRUE;
2835 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2837 /* Handle recording of state blocks */
2838 if (This->isRecordingState) {
2839 TRACE("Recording... not performing anything\n");
2840 return WINED3D_OK;
2843 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2844 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2846 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2847 return WINED3D_OK;
2851 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2853 TRACE("(%p)\n", This);
2854 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2855 return WINED3D_OK;
2858 /*****
2859 * Get / Set Render States
2860 * TODO: Verify against dx9 definitions
2861 *****/
2862 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2865 DWORD oldValue = This->stateBlock->renderState[State];
2867 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2869 This->updateStateBlock->changed.renderState[State] = TRUE;
2870 This->updateStateBlock->set.renderState[State] = TRUE;
2871 This->updateStateBlock->renderState[State] = Value;
2873 /* Handle recording of state blocks */
2874 if (This->isRecordingState) {
2875 TRACE("Recording... not performing anything\n");
2876 return WINED3D_OK;
2879 /* Compared here and not before the assignment to allow proper stateblock recording */
2880 if(Value == oldValue) {
2881 TRACE("Application is setting the old value over, nothing to do\n");
2882 } else {
2883 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2886 return WINED3D_OK;
2889 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2891 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2892 *pValue = This->stateBlock->renderState[State];
2893 return WINED3D_OK;
2896 /*****
2897 * Get / Set Sampler States
2898 * TODO: Verify against dx9 definitions
2899 *****/
2901 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2903 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2906 * SetSampler is designed to allow for more than the standard up to 8 textures
2907 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2908 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2910 * http://developer.nvidia.com/object/General_FAQ.html#t6
2912 * There are two new settings for GForce
2913 * the sampler one:
2914 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2915 * and the texture one:
2916 * GL_MAX_TEXTURE_COORDS_ARB.
2917 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2918 ******************/
2920 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2921 debug_d3dsamplerstate(Type), Type, Value);
2922 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2923 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2924 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2926 /* Handle recording of state blocks */
2927 if (This->isRecordingState) {
2928 TRACE("Recording... not performing anything\n");
2929 return WINED3D_OK;
2932 if(oldValue == Value) {
2933 TRACE("Application is setting the old value over, nothing to do\n");
2934 return WINED3D_OK;
2937 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2939 return WINED3D_OK;
2942 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2944 *Value = This->stateBlock->samplerState[Sampler][Type];
2945 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2947 return WINED3D_OK;
2950 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2953 This->updateStateBlock->set.scissorRect = TRUE;
2954 This->updateStateBlock->changed.scissorRect = TRUE;
2955 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2956 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2957 return WINED3D_OK;
2959 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2961 if(This->isRecordingState) {
2962 TRACE("Recording... not performing anything\n");
2963 return WINED3D_OK;
2966 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2968 return WINED3D_OK;
2971 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2974 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2975 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2976 return WINED3D_OK;
2979 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2981 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2983 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2985 This->updateStateBlock->vertexDecl = pDecl;
2986 This->updateStateBlock->changed.vertexDecl = TRUE;
2987 This->updateStateBlock->set.vertexDecl = TRUE;
2989 if (This->isRecordingState) {
2990 TRACE("Recording... not performing anything\n");
2991 return WINED3D_OK;
2992 } else if(pDecl == oldDecl) {
2993 /* Checked after the assignment to allow proper stateblock recording */
2994 TRACE("Application is setting the old declaration over, nothing to do\n");
2995 return WINED3D_OK;
2998 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2999 return WINED3D_OK;
3002 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3005 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3007 *ppDecl = This->stateBlock->vertexDecl;
3008 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3009 return WINED3D_OK;
3012 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3014 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3016 This->updateStateBlock->vertexShader = pShader;
3017 This->updateStateBlock->changed.vertexShader = TRUE;
3018 This->updateStateBlock->set.vertexShader = TRUE;
3020 if (This->isRecordingState) {
3021 TRACE("Recording... not performing anything\n");
3022 return WINED3D_OK;
3023 } else if(oldShader == pShader) {
3024 /* Checked here to allow proper stateblock recording */
3025 TRACE("App is setting the old shader over, nothing to do\n");
3026 return WINED3D_OK;
3029 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3031 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3033 return WINED3D_OK;
3036 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3039 if (NULL == ppShader) {
3040 return WINED3DERR_INVALIDCALL;
3042 *ppShader = This->stateBlock->vertexShader;
3043 if( NULL != *ppShader)
3044 IWineD3DVertexShader_AddRef(*ppShader);
3046 TRACE("(%p) : returning %p\n", This, *ppShader);
3047 return WINED3D_OK;
3050 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3051 IWineD3DDevice *iface,
3052 UINT start,
3053 CONST BOOL *srcData,
3054 UINT count) {
3056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3057 int i, cnt = min(count, MAX_CONST_B - start);
3059 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3060 iface, srcData, start, count);
3062 if (srcData == NULL || cnt < 0)
3063 return WINED3DERR_INVALIDCALL;
3065 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3066 for (i = 0; i < cnt; i++)
3067 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3069 for (i = start; i < cnt + start; ++i) {
3070 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3071 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3074 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3076 return WINED3D_OK;
3079 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3080 IWineD3DDevice *iface,
3081 UINT start,
3082 BOOL *dstData,
3083 UINT count) {
3085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3086 int cnt = min(count, MAX_CONST_B - start);
3088 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3089 iface, dstData, start, count);
3091 if (dstData == NULL || cnt < 0)
3092 return WINED3DERR_INVALIDCALL;
3094 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3095 return WINED3D_OK;
3098 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3099 IWineD3DDevice *iface,
3100 UINT start,
3101 CONST int *srcData,
3102 UINT count) {
3104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3105 int i, cnt = min(count, MAX_CONST_I - start);
3107 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3108 iface, srcData, start, count);
3110 if (srcData == NULL || cnt < 0)
3111 return WINED3DERR_INVALIDCALL;
3113 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3114 for (i = 0; i < cnt; i++)
3115 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3116 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3118 for (i = start; i < cnt + start; ++i) {
3119 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3120 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3123 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3125 return WINED3D_OK;
3128 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3129 IWineD3DDevice *iface,
3130 UINT start,
3131 int *dstData,
3132 UINT count) {
3134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3135 int cnt = min(count, MAX_CONST_I - start);
3137 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3138 iface, dstData, start, count);
3140 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3141 return WINED3DERR_INVALIDCALL;
3143 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3144 return WINED3D_OK;
3147 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3148 IWineD3DDevice *iface,
3149 UINT start,
3150 CONST float *srcData,
3151 UINT count) {
3153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3154 int i;
3156 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3157 iface, srcData, start, count);
3159 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3160 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3161 return WINED3DERR_INVALIDCALL;
3163 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3164 if(TRACE_ON(d3d)) {
3165 for (i = 0; i < count; i++)
3166 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3167 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3170 for (i = start; i < count + start; ++i) {
3171 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3172 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3173 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3174 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3175 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3177 ptr->idx[ptr->count++] = i;
3178 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3180 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3183 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3185 return WINED3D_OK;
3188 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3189 IWineD3DDevice *iface,
3190 UINT start,
3191 float *dstData,
3192 UINT count) {
3194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3195 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3197 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3198 iface, dstData, start, count);
3200 if (dstData == NULL || cnt < 0)
3201 return WINED3DERR_INVALIDCALL;
3203 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3204 return WINED3D_OK;
3207 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3208 DWORD i;
3209 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3210 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3214 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3215 DWORD i, tex;
3216 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3217 * it is never called.
3219 * Rules are:
3220 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3221 * that would be really messy and require shader recompilation
3222 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3223 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3224 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3225 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3227 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3228 if(This->oneToOneTexUnitMap) {
3229 TRACE("Not touching 1:1 map\n");
3230 return;
3232 TRACE("Restoring 1:1 texture unit mapping\n");
3233 /* Restore a 1:1 mapping */
3234 for(i = 0; i < MAX_SAMPLERS; i++) {
3235 if(This->texUnitMap[i] != i) {
3236 This->texUnitMap[i] = i;
3237 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3238 markTextureStagesDirty(This, i);
3241 This->oneToOneTexUnitMap = TRUE;
3242 return;
3243 } else {
3244 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3245 * First, see if we can succeed at all
3247 tex = 0;
3248 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3249 if(This->stateBlock->textures[i] == NULL) tex++;
3252 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3253 FIXME("Too many bound textures to support the combiner settings\n");
3254 return;
3257 /* Now work out the mapping */
3258 tex = 0;
3259 This->oneToOneTexUnitMap = FALSE;
3260 WARN("Non 1:1 mapping UNTESTED!\n");
3261 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3262 /* Skip NULL textures */
3263 if (!This->stateBlock->textures[i]) {
3264 /* Map to -1, so the check below doesn't fail if a non-NULL
3265 * texture is set on this stage */
3266 TRACE("Mapping texture stage %d to -1\n", i);
3267 This->texUnitMap[i] = -1;
3269 continue;
3272 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3273 if(This->texUnitMap[i] != tex) {
3274 This->texUnitMap[i] = tex;
3275 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3276 markTextureStagesDirty(This, i);
3279 ++tex;
3284 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3286 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3287 This->updateStateBlock->pixelShader = pShader;
3288 This->updateStateBlock->changed.pixelShader = TRUE;
3289 This->updateStateBlock->set.pixelShader = TRUE;
3291 /* Handle recording of state blocks */
3292 if (This->isRecordingState) {
3293 TRACE("Recording... not performing anything\n");
3296 if (This->isRecordingState) {
3297 TRACE("Recording... not performing anything\n");
3298 return WINED3D_OK;
3301 if(pShader == oldShader) {
3302 TRACE("App is setting the old pixel shader over, nothing to do\n");
3303 return WINED3D_OK;
3306 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3307 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3309 /* Rebuild the texture unit mapping if nvrc's are supported */
3310 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3311 IWineD3DDeviceImpl_FindTexUnitMap(This);
3314 return WINED3D_OK;
3317 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3320 if (NULL == ppShader) {
3321 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3322 return WINED3DERR_INVALIDCALL;
3325 *ppShader = This->stateBlock->pixelShader;
3326 if (NULL != *ppShader) {
3327 IWineD3DPixelShader_AddRef(*ppShader);
3329 TRACE("(%p) : returning %p\n", This, *ppShader);
3330 return WINED3D_OK;
3333 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3334 IWineD3DDevice *iface,
3335 UINT start,
3336 CONST BOOL *srcData,
3337 UINT count) {
3339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3340 int i, cnt = min(count, MAX_CONST_B - start);
3342 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3343 iface, srcData, start, count);
3345 if (srcData == NULL || cnt < 0)
3346 return WINED3DERR_INVALIDCALL;
3348 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3349 for (i = 0; i < cnt; i++)
3350 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3352 for (i = start; i < cnt + start; ++i) {
3353 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3354 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3357 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3359 return WINED3D_OK;
3362 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3363 IWineD3DDevice *iface,
3364 UINT start,
3365 BOOL *dstData,
3366 UINT count) {
3368 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3369 int cnt = min(count, MAX_CONST_B - start);
3371 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3372 iface, dstData, start, count);
3374 if (dstData == NULL || cnt < 0)
3375 return WINED3DERR_INVALIDCALL;
3377 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3378 return WINED3D_OK;
3381 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3382 IWineD3DDevice *iface,
3383 UINT start,
3384 CONST int *srcData,
3385 UINT count) {
3387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3388 int i, cnt = min(count, MAX_CONST_I - start);
3390 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3391 iface, srcData, start, count);
3393 if (srcData == NULL || cnt < 0)
3394 return WINED3DERR_INVALIDCALL;
3396 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3397 for (i = 0; i < cnt; i++)
3398 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3399 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3401 for (i = start; i < cnt + start; ++i) {
3402 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3403 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3406 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3408 return WINED3D_OK;
3411 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3412 IWineD3DDevice *iface,
3413 UINT start,
3414 int *dstData,
3415 UINT count) {
3417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3418 int cnt = min(count, MAX_CONST_I - start);
3420 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3421 iface, dstData, start, count);
3423 if (dstData == NULL || cnt < 0)
3424 return WINED3DERR_INVALIDCALL;
3426 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3427 return WINED3D_OK;
3430 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3431 IWineD3DDevice *iface,
3432 UINT start,
3433 CONST float *srcData,
3434 UINT count) {
3436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3437 int i;
3439 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3440 iface, srcData, start, count);
3442 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3443 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3444 return WINED3DERR_INVALIDCALL;
3446 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3447 if(TRACE_ON(d3d)) {
3448 for (i = 0; i < count; i++)
3449 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3450 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3453 for (i = start; i < count + start; ++i) {
3454 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3455 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3456 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3457 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3458 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3460 ptr->idx[ptr->count++] = i;
3461 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3463 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3466 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3468 return WINED3D_OK;
3471 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3472 IWineD3DDevice *iface,
3473 UINT start,
3474 float *dstData,
3475 UINT count) {
3477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3478 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3480 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3481 iface, dstData, start, count);
3483 if (dstData == NULL || cnt < 0)
3484 return WINED3DERR_INVALIDCALL;
3486 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3487 return WINED3D_OK;
3490 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3491 static HRESULT
3492 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3493 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3494 unsigned int i;
3495 DWORD DestFVF = dest->fvf;
3496 WINED3DVIEWPORT vp;
3497 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3498 BOOL doClip;
3499 int numTextures;
3501 if (lpStrideData->u.s.normal.lpData) {
3502 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3505 if (lpStrideData->u.s.position.lpData == NULL) {
3506 ERR("Source has no position mask\n");
3507 return WINED3DERR_INVALIDCALL;
3510 /* We might access VBOs from this code, so hold the lock */
3511 ENTER_GL();
3513 if (dest->resource.allocatedMemory == NULL) {
3514 /* This may happen if we do direct locking into a vbo. Unlikely,
3515 * but theoretically possible(ddraw processvertices test)
3517 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3518 if(!dest->resource.allocatedMemory) {
3519 LEAVE_GL();
3520 ERR("Out of memory\n");
3521 return E_OUTOFMEMORY;
3523 if(dest->vbo) {
3524 void *src;
3525 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3526 checkGLcall("glBindBufferARB");
3527 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3528 if(src) {
3529 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3531 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3532 checkGLcall("glUnmapBufferARB");
3536 /* Get a pointer into the destination vbo(create one if none exists) and
3537 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3539 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3540 CreateVBO(dest);
3543 if(dest->vbo) {
3544 dest_conv_addr = HeapAlloc(GetProcessHeap(), 0, dwCount * get_flexible_vertex_size(DestFVF));
3545 if(!dest_conv_addr) {
3546 ERR("Out of memory\n");
3547 /* Continue without storing converted vertices */
3549 dest_conv = dest_conv_addr;
3552 /* Should I clip?
3553 * a) WINED3DRS_CLIPPING is enabled
3554 * b) WINED3DVOP_CLIP is passed
3556 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3557 static BOOL warned = FALSE;
3559 * The clipping code is not quite correct. Some things need
3560 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3561 * so disable clipping for now.
3562 * (The graphics in Half-Life are broken, and my processvertices
3563 * test crashes with IDirect3DDevice3)
3564 doClip = TRUE;
3566 doClip = FALSE;
3567 if(!warned) {
3568 warned = TRUE;
3569 FIXME("Clipping is broken and disabled for now\n");
3571 } else doClip = FALSE;
3572 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3574 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3575 WINED3DTS_VIEW,
3576 &view_mat);
3577 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3578 WINED3DTS_PROJECTION,
3579 &proj_mat);
3580 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3581 WINED3DTS_WORLDMATRIX(0),
3582 &world_mat);
3584 TRACE("View mat:\n");
3585 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);
3586 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);
3587 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);
3588 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);
3590 TRACE("Proj mat:\n");
3591 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);
3592 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);
3593 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);
3594 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);
3596 TRACE("World mat:\n");
3597 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);
3598 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);
3599 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);
3600 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);
3602 /* Get the viewport */
3603 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3604 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3605 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3607 multiply_matrix(&mat,&view_mat,&world_mat);
3608 multiply_matrix(&mat,&proj_mat,&mat);
3610 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3612 for (i = 0; i < dwCount; i+= 1) {
3613 unsigned int tex_index;
3615 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3616 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3617 /* The position first */
3618 float *p =
3619 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3620 float x, y, z, rhw;
3621 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3623 /* Multiplication with world, view and projection matrix */
3624 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);
3625 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);
3626 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);
3627 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);
3629 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3631 /* WARNING: The following things are taken from d3d7 and were not yet checked
3632 * against d3d8 or d3d9!
3635 /* Clipping conditions: From
3636 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3638 * A vertex is clipped if it does not match the following requirements
3639 * -rhw < x <= rhw
3640 * -rhw < y <= rhw
3641 * 0 < z <= rhw
3642 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3644 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3645 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3649 if( !doClip ||
3650 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3651 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3652 ( rhw > eps ) ) ) {
3654 /* "Normal" viewport transformation (not clipped)
3655 * 1) The values are divided by rhw
3656 * 2) The y axis is negative, so multiply it with -1
3657 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3658 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3659 * 4) Multiply x with Width/2 and add Width/2
3660 * 5) The same for the height
3661 * 6) Add the viewpoint X and Y to the 2D coordinates and
3662 * The minimum Z value to z
3663 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3665 * Well, basically it's simply a linear transformation into viewport
3666 * coordinates
3669 x /= rhw;
3670 y /= rhw;
3671 z /= rhw;
3673 y *= -1;
3675 x *= vp.Width / 2;
3676 y *= vp.Height / 2;
3677 z *= vp.MaxZ - vp.MinZ;
3679 x += vp.Width / 2 + vp.X;
3680 y += vp.Height / 2 + vp.Y;
3681 z += vp.MinZ;
3683 rhw = 1 / rhw;
3684 } else {
3685 /* That vertex got clipped
3686 * Contrary to OpenGL it is not dropped completely, it just
3687 * undergoes a different calculation.
3689 TRACE("Vertex got clipped\n");
3690 x += rhw;
3691 y += rhw;
3693 x /= 2;
3694 y /= 2;
3696 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3697 * outside of the main vertex buffer memory. That needs some more
3698 * investigation...
3702 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3705 ( (float *) dest_ptr)[0] = x;
3706 ( (float *) dest_ptr)[1] = y;
3707 ( (float *) dest_ptr)[2] = z;
3708 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3710 dest_ptr += 3 * sizeof(float);
3712 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3713 dest_ptr += sizeof(float);
3716 if(dest_conv) {
3717 float w = 1 / rhw;
3718 ( (float *) dest_conv)[0] = x * w;
3719 ( (float *) dest_conv)[1] = y * w;
3720 ( (float *) dest_conv)[2] = z * w;
3721 ( (float *) dest_conv)[3] = w;
3723 dest_conv += 3 * sizeof(float);
3725 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3726 dest_conv += sizeof(float);
3730 if (DestFVF & WINED3DFVF_PSIZE) {
3731 dest_ptr += sizeof(DWORD);
3732 if(dest_conv) dest_conv += sizeof(DWORD);
3734 if (DestFVF & WINED3DFVF_NORMAL) {
3735 float *normal =
3736 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3737 /* AFAIK this should go into the lighting information */
3738 FIXME("Didn't expect the destination to have a normal\n");
3739 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3740 if(dest_conv) {
3741 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3745 if (DestFVF & WINED3DFVF_DIFFUSE) {
3746 DWORD *color_d =
3747 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3748 if(!color_d) {
3749 static BOOL warned = FALSE;
3751 if(!warned) {
3752 ERR("No diffuse color in source, but destination has one\n");
3753 warned = TRUE;
3756 *( (DWORD *) dest_ptr) = 0xffffffff;
3757 dest_ptr += sizeof(DWORD);
3759 if(dest_conv) {
3760 *( (DWORD *) dest_conv) = 0xffffffff;
3761 dest_conv += sizeof(DWORD);
3764 else {
3765 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3766 if(dest_conv) {
3767 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3768 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3769 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3770 dest_conv += sizeof(DWORD);
3775 if (DestFVF & WINED3DFVF_SPECULAR) {
3776 /* What's the color value in the feedback buffer? */
3777 DWORD *color_s =
3778 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3779 if(!color_s) {
3780 static BOOL warned = FALSE;
3782 if(!warned) {
3783 ERR("No specular color in source, but destination has one\n");
3784 warned = TRUE;
3787 *( (DWORD *) dest_ptr) = 0xFF000000;
3788 dest_ptr += sizeof(DWORD);
3790 if(dest_conv) {
3791 *( (DWORD *) dest_conv) = 0xFF000000;
3792 dest_conv += sizeof(DWORD);
3795 else {
3796 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3797 if(dest_conv) {
3798 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3799 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3800 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3801 dest_conv += sizeof(DWORD);
3806 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3807 float *tex_coord =
3808 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3809 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3810 if(!tex_coord) {
3811 ERR("No source texture, but destination requests one\n");
3812 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3813 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3815 else {
3816 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3817 if(dest_conv) {
3818 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3824 if(dest_conv) {
3825 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3826 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3827 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3828 dwCount * get_flexible_vertex_size(DestFVF),
3829 dest_conv_addr));
3830 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3831 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3834 LEAVE_GL();
3836 return WINED3D_OK;
3838 #undef copy_and_next
3840 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3842 WineDirect3DVertexStridedData strided;
3843 BOOL vbo = FALSE;
3844 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3846 if(pVertexDecl) {
3847 ERR("Output vertex declaration not implemented yet\n");
3850 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3851 * and this call is quite performance critical, so don't call needlessly
3853 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3854 ENTER_GL();
3855 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3856 LEAVE_GL();
3859 memset(&strided, 0, sizeof(strided));
3860 if(This->stateBlock->vertexDecl) {
3861 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
3862 } else {
3863 primitiveConvertToStridedData(iface, &strided, &vbo);
3866 if(vbo || SrcStartIndex) {
3867 unsigned int i;
3868 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
3869 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
3871 * Also get the start index in, but only loop over all elements if there's something to add at all.
3873 for(i=0; i < 16; i++) {
3874 if(strided.u.input[i].VBO) {
3875 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.input[i].streamNo];
3877 /* The vertex buffer is supposed to have a system memory copy */
3878 strided.u.input[i].VBO = 0;
3879 strided.u.input[i].lpData = (BYTE *) ((unsigned long) strided.u.input[i].lpData + (unsigned long) vb->resource.allocatedMemory);
3880 ENTER_GL();
3881 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo));
3882 vb->vbo = 0;
3883 LEAVE_GL();
3885 /* To be safe. An app could technically draw, then call ProcessVertices, then draw again without ever changing the stream sources */
3886 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3888 if(strided.u.input[i].lpData) {
3889 strided.u.input[i].lpData += strided.u.input[i].dwStride * SrcStartIndex;
3894 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3897 /*****
3898 * Get / Set Texture Stage States
3899 * TODO: Verify against dx9 definitions
3900 *****/
3901 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3903 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3905 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3907 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3909 if (Stage >= MAX_TEXTURES) {
3910 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
3911 return WINED3D_OK;
3914 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3915 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3916 This->updateStateBlock->textureState[Stage][Type] = Value;
3918 if (This->isRecordingState) {
3919 TRACE("Recording... not performing anything\n");
3920 return WINED3D_OK;
3923 /* Checked after the assignments to allow proper stateblock recording */
3924 if(oldValue == Value) {
3925 TRACE("App is setting the old value over, nothing to do\n");
3926 return WINED3D_OK;
3929 if(Stage > This->stateBlock->lowest_disabled_stage &&
3930 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3931 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3932 * Changes in other states are important on disabled stages too
3934 return WINED3D_OK;
3937 if(Type == WINED3DTSS_COLOROP) {
3938 int i;
3940 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3941 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3942 * they have to be disabled
3944 * The current stage is dirtified below.
3946 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3947 TRACE("Additionally dirtifying stage %d\n", i);
3948 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3950 This->stateBlock->lowest_disabled_stage = Stage;
3951 TRACE("New lowest disabled: %d\n", Stage);
3952 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3953 /* Previously disabled stage enabled. Stages above it may need enabling
3954 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3955 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3957 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3960 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3961 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3962 break;
3964 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3965 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3967 This->stateBlock->lowest_disabled_stage = i;
3968 TRACE("New lowest disabled: %d\n", i);
3970 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3971 /* TODO: Built a stage -> texture unit mapping for register combiners */
3975 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3977 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3978 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3979 * will call FindTexUnitMap too.
3981 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3982 IWineD3DDeviceImpl_FindTexUnitMap(This);
3984 return WINED3D_OK;
3987 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3989 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3990 *pValue = This->updateStateBlock->textureState[Stage][Type];
3991 return WINED3D_OK;
3994 /*****
3995 * Get / Set Texture
3996 *****/
3997 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
3999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4000 IWineD3DBaseTexture *oldTexture;
4002 oldTexture = This->updateStateBlock->textures[Stage];
4003 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4005 #if 0 /* TODO: check so vertex textures */
4006 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4007 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4008 return WINED3D_OK;
4010 #endif
4012 if(pTexture != NULL) {
4013 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4015 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4016 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4017 return WINED3DERR_INVALIDCALL;
4019 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4022 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4023 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4025 This->updateStateBlock->set.textures[Stage] = TRUE;
4026 This->updateStateBlock->changed.textures[Stage] = TRUE;
4027 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4028 This->updateStateBlock->textures[Stage] = pTexture;
4030 /* Handle recording of state blocks */
4031 if (This->isRecordingState) {
4032 TRACE("Recording... not performing anything\n");
4033 return WINED3D_OK;
4036 if(oldTexture == pTexture) {
4037 TRACE("App is setting the same texture again, nothing to do\n");
4038 return WINED3D_OK;
4041 /** NOTE: MSDN says that setTexture increases the reference count,
4042 * and the the application nust set the texture back to null (or have a leaky application),
4043 * This means we should pass the refcount up to the parent
4044 *******************************/
4045 if (NULL != This->updateStateBlock->textures[Stage]) {
4046 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4047 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4049 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4050 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4051 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4052 * so the COLOROP and ALPHAOP have to be dirtified.
4054 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4055 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4057 if(bindCount == 1) {
4058 new->baseTexture.sampler = Stage;
4060 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4064 if (NULL != oldTexture) {
4065 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4066 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4068 IWineD3DBaseTexture_Release(oldTexture);
4069 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4070 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4071 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4074 if(bindCount && old->baseTexture.sampler == Stage) {
4075 int i;
4076 /* Have to do a search for the other sampler(s) where the texture is bound to
4077 * Shouldn't happen as long as apps bind a texture only to one stage
4079 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4080 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
4081 if(This->updateStateBlock->textures[i] == oldTexture) {
4082 old->baseTexture.sampler = i;
4083 break;
4089 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4091 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
4092 * pixel shader is used
4094 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4095 IWineD3DDeviceImpl_FindTexUnitMap(This);
4098 return WINED3D_OK;
4101 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4103 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4105 *ppTexture=This->stateBlock->textures[Stage];
4106 if (*ppTexture)
4107 IWineD3DBaseTexture_AddRef(*ppTexture);
4109 return WINED3D_OK;
4112 /*****
4113 * Get Back Buffer
4114 *****/
4115 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4116 IWineD3DSurface **ppBackBuffer) {
4117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4118 IWineD3DSwapChain *swapChain;
4119 HRESULT hr;
4121 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4123 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4124 if (hr == WINED3D_OK) {
4125 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4126 IWineD3DSwapChain_Release(swapChain);
4127 } else {
4128 *ppBackBuffer = NULL;
4130 return hr;
4133 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4135 WARN("(%p) : stub, calling idirect3d for now\n", This);
4136 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4139 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4141 IWineD3DSwapChain *swapChain;
4142 HRESULT hr;
4144 if(iSwapChain > 0) {
4145 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4146 if (hr == WINED3D_OK) {
4147 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4148 IWineD3DSwapChain_Release(swapChain);
4149 } else {
4150 FIXME("(%p) Error getting display mode\n", This);
4152 } else {
4153 /* Don't read the real display mode,
4154 but return the stored mode instead. X11 can't change the color
4155 depth, and some apps are pretty angry if they SetDisplayMode from
4156 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4158 Also don't relay to the swapchain because with ddraw it's possible
4159 that there isn't a swapchain at all */
4160 pMode->Width = This->ddraw_width;
4161 pMode->Height = This->ddraw_height;
4162 pMode->Format = This->ddraw_format;
4163 pMode->RefreshRate = 0;
4164 hr = WINED3D_OK;
4167 return hr;
4170 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4172 TRACE("(%p)->(%p)\n", This, hWnd);
4174 if(This->ddraw_fullscreen) {
4175 if(This->ddraw_window && This->ddraw_window != hWnd) {
4176 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4178 if(hWnd && This->ddraw_window != hWnd) {
4179 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4183 This->ddraw_window = hWnd;
4184 return WINED3D_OK;
4187 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4189 TRACE("(%p)->(%p)\n", This, hWnd);
4191 *hWnd = This->ddraw_window;
4192 return WINED3D_OK;
4195 /*****
4196 * Stateblock related functions
4197 *****/
4199 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4201 IWineD3DStateBlockImpl *object;
4202 HRESULT temp_result;
4203 int i;
4205 TRACE("(%p)\n", This);
4207 if (This->isRecordingState) {
4208 return WINED3DERR_INVALIDCALL;
4211 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4212 if (NULL == object ) {
4213 FIXME("(%p)Error allocating memory for stateblock\n", This);
4214 return E_OUTOFMEMORY;
4216 TRACE("(%p) created object %p\n", This, object);
4217 object->wineD3DDevice= This;
4218 /** FIXME: object->parent = parent; **/
4219 object->parent = NULL;
4220 object->blockType = WINED3DSBT_ALL;
4221 object->ref = 1;
4222 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4224 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4225 list_init(&object->lightMap[i]);
4228 temp_result = allocate_shader_constants(object);
4229 if (WINED3D_OK != temp_result)
4230 return temp_result;
4232 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4233 This->updateStateBlock = object;
4234 This->isRecordingState = TRUE;
4236 TRACE("(%p) recording stateblock %p\n",This , object);
4237 return WINED3D_OK;
4240 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4243 if (!This->isRecordingState) {
4244 FIXME("(%p) not recording! returning error\n", This);
4245 *ppStateBlock = NULL;
4246 return WINED3DERR_INVALIDCALL;
4249 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4250 This->isRecordingState = FALSE;
4251 This->updateStateBlock = This->stateBlock;
4252 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4253 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4254 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4255 return WINED3D_OK;
4258 /*****
4259 * Scene related functions
4260 *****/
4261 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4262 /* At the moment we have no need for any functionality at the beginning
4263 of a scene */
4264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4265 TRACE("(%p)\n", This);
4267 if(This->inScene) {
4268 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4269 return WINED3DERR_INVALIDCALL;
4271 This->inScene = TRUE;
4272 return WINED3D_OK;
4275 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4277 TRACE("(%p)\n", This);
4279 if(!This->inScene) {
4280 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4281 return WINED3DERR_INVALIDCALL;
4284 ENTER_GL();
4285 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4286 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4288 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4289 glFlush();
4290 checkGLcall("glFlush");
4291 LEAVE_GL();
4293 This->inScene = FALSE;
4294 return WINED3D_OK;
4297 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4298 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4299 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4301 IWineD3DSwapChain *swapChain = NULL;
4302 int i;
4303 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4305 TRACE("(%p) Presenting the frame\n", This);
4307 for(i = 0 ; i < swapchains ; i ++) {
4309 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4310 TRACE("presentinng chain %d, %p\n", i, swapChain);
4311 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4312 IWineD3DSwapChain_Release(swapChain);
4315 return WINED3D_OK;
4318 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4319 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4321 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4323 GLbitfield glMask = 0;
4324 unsigned int i;
4325 CONST WINED3DRECT* curRect;
4327 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4328 Count, pRects, Flags, Z, Stencil);
4330 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4331 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4332 /* TODO: What about depth stencil buffers without stencil bits? */
4333 return WINED3DERR_INVALIDCALL;
4336 ENTER_GL();
4337 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4338 * and not the last active one.
4341 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4342 apply_fbo_state(iface);
4345 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
4347 glEnable(GL_SCISSOR_TEST);
4348 checkGLcall("glEnable GL_SCISSOR_TEST");
4349 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4350 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4352 if (Count > 0 && pRects) {
4353 curRect = pRects;
4354 } else {
4355 curRect = NULL;
4358 /* Only set the values up once, as they are not changing */
4359 if (Flags & WINED3DCLEAR_STENCIL) {
4360 glClearStencil(Stencil);
4361 checkGLcall("glClearStencil");
4362 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4363 glStencilMask(0xFFFFFFFF);
4366 if (Flags & WINED3DCLEAR_ZBUFFER) {
4367 glDepthMask(GL_TRUE);
4368 glClearDepth(Z);
4369 checkGLcall("glClearDepth");
4370 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4374 if (Flags & WINED3DCLEAR_TARGET) {
4375 TRACE("Clearing screen with glClear to color %x\n", Color);
4376 glClearColor(D3DCOLOR_R(Color),
4377 D3DCOLOR_G(Color),
4378 D3DCOLOR_B(Color),
4379 D3DCOLOR_A(Color));
4380 checkGLcall("glClearColor");
4382 /* Clear ALL colors! */
4383 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4384 glMask = glMask | GL_COLOR_BUFFER_BIT;
4387 if (!curRect) {
4388 /* In drawable flag is set below */
4390 glScissor(This->stateBlock->viewport.X,
4391 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4392 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4393 This->stateBlock->viewport.Width,
4394 This->stateBlock->viewport.Height);
4395 checkGLcall("glScissor");
4396 glClear(glMask);
4397 checkGLcall("glClear");
4398 } else {
4399 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4400 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4402 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4403 curRect[0].x2 < target->currentDesc.Width ||
4404 curRect[0].y2 < target->currentDesc.Height) {
4405 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4406 blt_to_drawable(This, target);
4410 /* Now process each rect in turn */
4411 for (i = 0; i < Count; i++) {
4412 /* Note gl uses lower left, width/height */
4413 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4414 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4415 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4416 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4418 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4419 * The rectangle is not cleared, no error is returned, but further rectanlges are
4420 * still cleared if they are valid
4422 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4423 TRACE("Rectangle with negative dimensions, ignoring\n");
4424 continue;
4427 if(This->render_offscreen) {
4428 glScissor(curRect[i].x1, curRect[i].y1,
4429 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4430 } else {
4431 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4432 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4434 checkGLcall("glScissor");
4436 glClear(glMask);
4437 checkGLcall("glClear");
4441 /* Restore the old values (why..?) */
4442 if (Flags & WINED3DCLEAR_STENCIL) {
4443 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4445 if (Flags & WINED3DCLEAR_TARGET) {
4446 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4447 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4448 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4449 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4450 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4453 LEAVE_GL();
4455 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4456 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4458 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4459 target->Flags |= SFLAG_INTEXTURE;
4460 target->Flags &= ~SFLAG_INSYSMEM;
4461 } else {
4462 target->Flags |= SFLAG_INDRAWABLE;
4463 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4465 return WINED3D_OK;
4468 /*****
4469 * Drawing functions
4470 *****/
4471 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4472 UINT PrimitiveCount) {
4474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4476 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4477 debug_d3dprimitivetype(PrimitiveType),
4478 StartVertex, PrimitiveCount);
4480 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4481 if(This->stateBlock->streamIsUP) {
4482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4483 This->stateBlock->streamIsUP = FALSE;
4486 if(This->stateBlock->loadBaseVertexIndex != 0) {
4487 This->stateBlock->loadBaseVertexIndex = 0;
4488 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4490 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4491 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4492 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4493 return WINED3D_OK;
4496 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4497 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4498 WINED3DPRIMITIVETYPE PrimitiveType,
4499 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4502 UINT idxStride = 2;
4503 IWineD3DIndexBuffer *pIB;
4504 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4505 GLuint vbo;
4507 if(This->stateBlock->streamIsUP) {
4508 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4509 This->stateBlock->streamIsUP = FALSE;
4511 pIB = This->stateBlock->pIndexData;
4512 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4514 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4515 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4516 minIndex, NumVertices, startIndex, primCount);
4518 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4519 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4520 idxStride = 2;
4521 } else {
4522 idxStride = 4;
4525 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4526 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4527 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4530 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4531 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4533 return WINED3D_OK;
4536 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4537 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4538 UINT VertexStreamZeroStride) {
4539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4541 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4542 debug_d3dprimitivetype(PrimitiveType),
4543 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4545 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4546 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4547 This->stateBlock->streamOffset[0] = 0;
4548 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4549 This->stateBlock->streamIsUP = TRUE;
4550 This->stateBlock->loadBaseVertexIndex = 0;
4552 /* TODO: Only mark dirty if drawing from a different UP address */
4553 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4555 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4556 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4558 /* MSDN specifies stream zero settings must be set to NULL */
4559 This->stateBlock->streamStride[0] = 0;
4560 This->stateBlock->streamSource[0] = NULL;
4562 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4563 * the new stream sources or use UP drawing again
4565 return WINED3D_OK;
4568 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4569 UINT MinVertexIndex, UINT NumVertices,
4570 UINT PrimitiveCount, CONST void* pIndexData,
4571 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4572 UINT VertexStreamZeroStride) {
4573 int idxStride;
4574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4576 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4577 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4578 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4579 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4581 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4582 idxStride = 2;
4583 } else {
4584 idxStride = 4;
4587 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4588 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4589 This->stateBlock->streamIsUP = TRUE;
4590 This->stateBlock->streamOffset[0] = 0;
4591 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4593 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4594 This->stateBlock->baseVertexIndex = 0;
4595 This->stateBlock->loadBaseVertexIndex = 0;
4596 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4597 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4598 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4600 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4602 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4603 This->stateBlock->streamSource[0] = NULL;
4604 This->stateBlock->streamStride[0] = 0;
4605 This->stateBlock->pIndexData = NULL;
4606 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4607 * SetStreamSource to specify a vertex buffer
4610 return WINED3D_OK;
4613 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4616 /* Mark the state dirty until we have nicer tracking
4617 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4618 * that value.
4620 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4621 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4622 This->stateBlock->baseVertexIndex = 0;
4623 This->up_strided = DrawPrimStrideData;
4624 This->stateBlock->streamIsUP = TRUE;
4625 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4626 This->up_strided = NULL;
4627 return WINED3D_OK;
4629 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4630 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4632 HRESULT hr = WINED3D_OK;
4633 WINED3DRESOURCETYPE sourceType;
4634 WINED3DRESOURCETYPE destinationType;
4635 int i ,levels;
4637 /* TODO: think about moving the code into IWineD3DBaseTexture */
4639 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4641 /* verify that the source and destination textures aren't NULL */
4642 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4643 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4644 This, pSourceTexture, pDestinationTexture);
4645 hr = WINED3DERR_INVALIDCALL;
4648 if (pSourceTexture == pDestinationTexture) {
4649 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4650 This, pSourceTexture, pDestinationTexture);
4651 hr = WINED3DERR_INVALIDCALL;
4653 /* Verify that the source and destination textures are the same type */
4654 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4655 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4657 if (sourceType != destinationType) {
4658 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4659 This);
4660 hr = WINED3DERR_INVALIDCALL;
4663 /* check that both textures have the identical numbers of levels */
4664 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4665 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4666 hr = WINED3DERR_INVALIDCALL;
4669 if (WINED3D_OK == hr) {
4671 /* Make sure that the destination texture is loaded */
4672 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4674 /* Update every surface level of the texture */
4675 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4677 switch (sourceType) {
4678 case WINED3DRTYPE_TEXTURE:
4680 IWineD3DSurface *srcSurface;
4681 IWineD3DSurface *destSurface;
4683 for (i = 0 ; i < levels ; ++i) {
4684 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4685 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4686 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4687 IWineD3DSurface_Release(srcSurface);
4688 IWineD3DSurface_Release(destSurface);
4689 if (WINED3D_OK != hr) {
4690 WARN("(%p) : Call to update surface failed\n", This);
4691 return hr;
4695 break;
4696 case WINED3DRTYPE_CUBETEXTURE:
4698 IWineD3DSurface *srcSurface;
4699 IWineD3DSurface *destSurface;
4700 WINED3DCUBEMAP_FACES faceType;
4702 for (i = 0 ; i < levels ; ++i) {
4703 /* Update each cube face */
4704 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4705 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4706 if (WINED3D_OK != hr) {
4707 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4708 } else {
4709 TRACE("Got srcSurface %p\n", srcSurface);
4711 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4712 if (WINED3D_OK != hr) {
4713 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4714 } else {
4715 TRACE("Got desrSurface %p\n", destSurface);
4717 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4718 IWineD3DSurface_Release(srcSurface);
4719 IWineD3DSurface_Release(destSurface);
4720 if (WINED3D_OK != hr) {
4721 WARN("(%p) : Call to update surface failed\n", This);
4722 return hr;
4727 break;
4728 #if 0 /* TODO: Add support for volume textures */
4729 case WINED3DRTYPE_VOLUMETEXTURE:
4731 IWineD3DVolume srcVolume = NULL;
4732 IWineD3DSurface destVolume = NULL;
4734 for (i = 0 ; i < levels ; ++i) {
4735 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4736 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4737 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4738 IWineD3DVolume_Release(srcSurface);
4739 IWineD3DVolume_Release(destSurface);
4740 if (WINED3D_OK != hr) {
4741 WARN("(%p) : Call to update volume failed\n", This);
4742 return hr;
4746 break;
4747 #endif
4748 default:
4749 FIXME("(%p) : Unsupported source and destination type\n", This);
4750 hr = WINED3DERR_INVALIDCALL;
4754 return hr;
4757 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4758 IWineD3DSwapChain *swapChain;
4759 HRESULT hr;
4760 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4761 if(hr == WINED3D_OK) {
4762 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4763 IWineD3DSwapChain_Release(swapChain);
4765 return hr;
4768 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4770 /* return a sensible default */
4771 *pNumPasses = 1;
4772 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4773 FIXME("(%p) : stub\n", This);
4774 return WINED3D_OK;
4777 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4779 int j;
4780 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4781 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4782 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4783 return WINED3DERR_INVALIDCALL;
4785 for (j = 0; j < 256; ++j) {
4786 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4787 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4788 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4789 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4791 TRACE("(%p) : returning\n", This);
4792 return WINED3D_OK;
4795 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4797 int j;
4798 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4799 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4800 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4801 return WINED3DERR_INVALIDCALL;
4803 for (j = 0; j < 256; ++j) {
4804 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4805 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4806 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4807 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4809 TRACE("(%p) : returning\n", This);
4810 return WINED3D_OK;
4813 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4815 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4816 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4817 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4818 return WINED3DERR_INVALIDCALL;
4820 /*TODO: stateblocks */
4821 This->currentPalette = PaletteNumber;
4822 TRACE("(%p) : returning\n", This);
4823 return WINED3D_OK;
4826 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4828 if (PaletteNumber == NULL) {
4829 WARN("(%p) : returning Invalid Call\n", This);
4830 return WINED3DERR_INVALIDCALL;
4832 /*TODO: stateblocks */
4833 *PaletteNumber = This->currentPalette;
4834 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4835 return WINED3D_OK;
4838 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4840 static BOOL showFixmes = TRUE;
4841 if (showFixmes) {
4842 FIXME("(%p) : stub\n", This);
4843 showFixmes = FALSE;
4846 This->softwareVertexProcessing = bSoftware;
4847 return WINED3D_OK;
4851 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4853 static BOOL showFixmes = TRUE;
4854 if (showFixmes) {
4855 FIXME("(%p) : stub\n", This);
4856 showFixmes = FALSE;
4858 return This->softwareVertexProcessing;
4862 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4864 IWineD3DSwapChain *swapChain;
4865 HRESULT hr;
4867 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4869 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4870 if(hr == WINED3D_OK){
4871 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4872 IWineD3DSwapChain_Release(swapChain);
4873 }else{
4874 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4876 return hr;
4880 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4882 static BOOL showfixmes = TRUE;
4883 if(nSegments != 0.0f) {
4884 if( showfixmes) {
4885 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4886 showfixmes = FALSE;
4889 return WINED3D_OK;
4892 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4894 static BOOL showfixmes = TRUE;
4895 if( showfixmes) {
4896 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4897 showfixmes = FALSE;
4899 return 0.0f;
4902 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4904 /** TODO: remove casts to IWineD3DSurfaceImpl
4905 * NOTE: move code to surface to accomplish this
4906 ****************************************/
4907 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4908 int srcWidth, srcHeight;
4909 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4910 WINED3DFORMAT destFormat, srcFormat;
4911 UINT destSize;
4912 int srcLeft, destLeft, destTop;
4913 WINED3DPOOL srcPool, destPool;
4914 int offset = 0;
4915 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4916 glDescriptor *glDescription = NULL;
4918 WINED3DSURFACE_DESC winedesc;
4920 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4921 memset(&winedesc, 0, sizeof(winedesc));
4922 winedesc.Width = &srcSurfaceWidth;
4923 winedesc.Height = &srcSurfaceHeight;
4924 winedesc.Pool = &srcPool;
4925 winedesc.Format = &srcFormat;
4927 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4929 winedesc.Width = &destSurfaceWidth;
4930 winedesc.Height = &destSurfaceHeight;
4931 winedesc.Pool = &destPool;
4932 winedesc.Format = &destFormat;
4933 winedesc.Size = &destSize;
4935 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4937 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4938 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4939 return WINED3DERR_INVALIDCALL;
4942 if (destFormat == WINED3DFMT_UNKNOWN) {
4943 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4944 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4946 /* Get the update surface description */
4947 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4950 ENTER_GL();
4952 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4954 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
4955 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4956 checkGLcall("glActiveTextureARB");
4959 /* Make sure the surface is loaded and up to date */
4960 IWineD3DSurface_PreLoad(pDestinationSurface);
4962 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4964 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4965 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4966 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
4967 srcLeft = pSourceRect ? pSourceRect->left : 0;
4968 destLeft = pDestPoint ? pDestPoint->x : 0;
4969 destTop = pDestPoint ? pDestPoint->y : 0;
4972 /* This function doesn't support compressed textures
4973 the pitch is just bytesPerPixel * width */
4974 if(srcWidth != srcSurfaceWidth || srcLeft ){
4975 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
4976 offset += srcLeft * pSrcSurface->bytesPerPixel;
4977 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4979 /* TODO DXT formats */
4981 if(pSourceRect != NULL && pSourceRect->top != 0){
4982 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
4984 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4985 ,This
4986 ,glDescription->level
4987 ,destLeft
4988 ,destTop
4989 ,srcWidth
4990 ,srcHeight
4991 ,glDescription->glFormat
4992 ,glDescription->glType
4993 ,IWineD3DSurface_GetData(pSourceSurface)
4996 /* Sanity check */
4997 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
4999 /* need to lock the surface to get the data */
5000 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5003 /* TODO: Cube and volume support */
5004 if(rowoffset != 0){
5005 /* not a whole row so we have to do it a line at a time */
5006 int j;
5008 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5009 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5011 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5013 glTexSubImage2D(glDescription->target
5014 ,glDescription->level
5015 ,destLeft
5017 ,srcWidth
5019 ,glDescription->glFormat
5020 ,glDescription->glType
5021 ,data /* could be quicker using */
5023 data += rowoffset;
5026 } else { /* Full width, so just write out the whole texture */
5028 if (WINED3DFMT_DXT1 == destFormat ||
5029 WINED3DFMT_DXT2 == destFormat ||
5030 WINED3DFMT_DXT3 == destFormat ||
5031 WINED3DFMT_DXT4 == destFormat ||
5032 WINED3DFMT_DXT5 == destFormat) {
5033 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5034 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5035 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5036 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5037 } if (destFormat != srcFormat) {
5038 FIXME("Updating mixed format compressed texture is not curretly support\n");
5039 } else {
5040 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5041 glDescription->level,
5042 glDescription->glFormatInternal,
5043 srcWidth,
5044 srcHeight,
5046 destSize,
5047 IWineD3DSurface_GetData(pSourceSurface));
5049 } else {
5050 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5054 } else {
5055 glTexSubImage2D(glDescription->target
5056 ,glDescription->level
5057 ,destLeft
5058 ,destTop
5059 ,srcWidth
5060 ,srcHeight
5061 ,glDescription->glFormat
5062 ,glDescription->glType
5063 ,IWineD3DSurface_GetData(pSourceSurface)
5067 checkGLcall("glTexSubImage2D");
5069 LEAVE_GL();
5071 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5072 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5073 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5075 return WINED3D_OK;
5078 /* Implementation details at http://developer.nvidia.com/attach/6494
5080 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5081 hmm.. no longer supported use
5082 OpenGL evaluators or tessellate surfaces within your application.
5085 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5086 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5088 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5089 FIXME("(%p) : Stub\n", This);
5090 return WINED3D_OK;
5094 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5095 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5097 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5098 FIXME("(%p) : Stub\n", This);
5099 return WINED3D_OK;
5102 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5104 TRACE("(%p) Handle(%d)\n", This, Handle);
5105 FIXME("(%p) : Stub\n", This);
5106 return WINED3D_OK;
5109 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5110 HRESULT hr;
5111 IWineD3DSwapChain *swapchain;
5113 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5114 if (SUCCEEDED(hr)) {
5115 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5116 return swapchain;
5119 return NULL;
5122 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5125 if (!*fbo) {
5126 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5127 checkGLcall("glGenFramebuffersEXT()");
5129 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5130 checkGLcall("glBindFramebuffer()");
5133 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5134 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5135 GLenum texttarget, target;
5136 GLint old_binding;
5138 texttarget = surface_impl->glDescription.target;
5139 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5140 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5142 IWineD3DSurface_PreLoad(surface);
5144 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5145 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5146 glBindTexture(target, old_binding);
5148 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5150 checkGLcall("attach_surface_fbo");
5153 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5155 IWineD3DSwapChain *swapchain;
5157 swapchain = get_swapchain(surface);
5158 if (swapchain) {
5159 GLenum buffer;
5161 TRACE("Surface %p is onscreen\n", surface);
5163 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5164 buffer = surface_get_gl_buffer(surface, swapchain);
5165 glDrawBuffer(buffer);
5166 checkGLcall("glDrawBuffer()");
5167 } else {
5168 TRACE("Surface %p is offscreen\n", surface);
5169 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5170 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, surface);
5173 if (rect) {
5174 glEnable(GL_SCISSOR_TEST);
5175 if(!swapchain) {
5176 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5177 } else {
5178 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5179 rect->x2 - rect->x1, rect->y2 - rect->y1);
5181 checkGLcall("glScissor");
5182 } else {
5183 glDisable(GL_SCISSOR_TEST);
5185 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5187 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5188 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5190 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5191 glClear(GL_COLOR_BUFFER_BIT);
5192 checkGLcall("glClear");
5194 if (This->render_offscreen) {
5195 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5196 } else {
5197 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5198 checkGLcall("glBindFramebuffer()");
5201 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5202 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5203 glDrawBuffer(GL_BACK);
5204 checkGLcall("glDrawBuffer()");
5208 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5210 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5211 WINEDDBLTFX BltFx;
5212 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
5214 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5215 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5216 return WINED3DERR_INVALIDCALL;
5219 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5220 color_fill_fbo(iface, pSurface, pRect, color);
5221 return WINED3D_OK;
5222 } else {
5223 /* Just forward this to the DirectDraw blitting engine */
5224 memset(&BltFx, 0, sizeof(BltFx));
5225 BltFx.dwSize = sizeof(BltFx);
5226 BltFx.u5.dwFillColor = color;
5227 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5231 /* rendertarget and deptth stencil functions */
5232 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5235 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5236 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5237 return WINED3DERR_INVALIDCALL;
5240 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5241 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5242 /* Note inc ref on returned surface */
5243 if(*ppRenderTarget != NULL)
5244 IWineD3DSurface_AddRef(*ppRenderTarget);
5245 return WINED3D_OK;
5248 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5250 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5251 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5252 IWineD3DSwapChainImpl *Swapchain;
5253 HRESULT hr;
5255 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5257 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5258 if(hr != WINED3D_OK) {
5259 ERR("Can't get the swapchain\n");
5260 return hr;
5263 /* Make sure to release the swapchain */
5264 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5266 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5267 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5268 return WINED3DERR_INVALIDCALL;
5270 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5271 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5272 return WINED3DERR_INVALIDCALL;
5275 if(Swapchain->frontBuffer != Front) {
5276 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5278 if(Swapchain->frontBuffer)
5279 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5280 Swapchain->frontBuffer = Front;
5282 if(Swapchain->frontBuffer) {
5283 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5287 if(Back && !Swapchain->backBuffer) {
5288 /* We need memory for the back buffer array - only one back buffer this way */
5289 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5290 if(!Swapchain->backBuffer) {
5291 ERR("Out of memory\n");
5292 return E_OUTOFMEMORY;
5296 if(Swapchain->backBuffer[0] != Back) {
5297 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5299 /* What to do about the context here in the case of multithreading? Not sure.
5300 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5302 ENTER_GL();
5303 if(!Swapchain->backBuffer[0]) {
5304 /* GL was told to draw to the front buffer at creation,
5305 * undo that
5307 glDrawBuffer(GL_BACK);
5308 checkGLcall("glDrawBuffer(GL_BACK)");
5309 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5310 Swapchain->presentParms.BackBufferCount = 1;
5311 } else if (!Back) {
5312 /* That makes problems - disable for now */
5313 /* glDrawBuffer(GL_FRONT); */
5314 checkGLcall("glDrawBuffer(GL_FRONT)");
5315 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5316 Swapchain->presentParms.BackBufferCount = 0;
5318 LEAVE_GL();
5320 if(Swapchain->backBuffer[0])
5321 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5322 Swapchain->backBuffer[0] = Back;
5324 if(Swapchain->backBuffer[0]) {
5325 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5326 } else {
5327 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5332 return WINED3D_OK;
5335 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5337 *ppZStencilSurface = This->depthStencilBuffer;
5338 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5340 if(*ppZStencilSurface != NULL) {
5341 /* Note inc ref on returned surface */
5342 IWineD3DSurface_AddRef(*ppZStencilSurface);
5344 return WINED3D_OK;
5347 /* TODO: Handle stencil attachments */
5348 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5350 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5352 TRACE("Set depth stencil to %p\n", depth_stencil);
5354 if (depth_stencil_impl) {
5355 if (depth_stencil_impl->current_renderbuffer) {
5356 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5357 checkGLcall("glFramebufferRenderbufferEXT()");
5358 } else {
5359 GLenum texttarget, target;
5360 GLint old_binding = 0;
5362 texttarget = depth_stencil_impl->glDescription.target;
5363 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5364 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5366 IWineD3DSurface_PreLoad(depth_stencil);
5368 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5369 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5370 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5371 glBindTexture(target, old_binding);
5373 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5374 checkGLcall("glFramebufferTexture2DEXT()");
5376 } else {
5377 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5378 checkGLcall("glFramebufferTexture2DEXT()");
5382 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5384 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5386 TRACE("Set render target %u to %p\n", idx, render_target);
5388 if (rtimpl) {
5389 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5390 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5391 } else {
5392 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5393 checkGLcall("glFramebufferTexture2DEXT()");
5395 This->draw_buffers[idx] = GL_NONE;
5399 static void check_fbo_status(IWineD3DDevice *iface) {
5400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5401 GLenum status;
5403 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5404 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5405 TRACE("FBO complete\n");
5406 } else {
5407 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5409 /* Dump the FBO attachments */
5410 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5411 IWineD3DSurfaceImpl *attachment;
5412 int i;
5414 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5415 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5416 if (attachment) {
5417 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5418 attachment->pow2Width, attachment->pow2Height);
5421 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5422 if (attachment) {
5423 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5424 attachment->pow2Width, attachment->pow2Height);
5430 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5432 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5433 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5435 if (!ds_impl) return FALSE;
5437 if (ds_impl->current_renderbuffer) {
5438 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5439 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5442 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5443 rt_impl->pow2Height != ds_impl->pow2Height);
5446 void apply_fbo_state(IWineD3DDevice *iface) {
5447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5448 unsigned int i;
5450 if (This->render_offscreen) {
5451 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5453 /* Apply render targets */
5454 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5455 IWineD3DSurface *render_target = This->render_targets[i];
5456 if (This->fbo_color_attachments[i] != render_target) {
5457 set_render_target_fbo(iface, i, render_target);
5458 This->fbo_color_attachments[i] = render_target;
5462 /* Apply depth targets */
5463 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5464 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5465 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5467 if (This->stencilBufferTarget) {
5468 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5470 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5471 This->fbo_depth_attachment = This->stencilBufferTarget;
5474 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5475 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5476 checkGLcall("glDrawBuffers()");
5477 } else {
5478 glDrawBuffer(This->draw_buffers[0]);
5479 checkGLcall("glDrawBuffer()");
5481 } else {
5482 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5485 check_fbo_status(iface);
5488 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5489 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5490 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5491 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5492 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5493 GLenum gl_filter;
5495 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5496 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5497 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5498 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5500 glDisable(GL_SCISSOR_TEST);
5501 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5503 switch (filter) {
5504 case WINED3DTEXF_LINEAR:
5505 gl_filter = GL_LINEAR;
5506 break;
5508 default:
5509 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5510 case WINED3DTEXF_NONE:
5511 case WINED3DTEXF_POINT:
5512 gl_filter = GL_NEAREST;
5513 break;
5516 /* Attach src surface to src fbo */
5517 src_swapchain = get_swapchain(src_surface);
5518 if (src_swapchain) {
5519 GLenum buffer;
5521 TRACE("Source surface %p is onscreen\n", src_surface);
5523 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5524 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5525 glReadBuffer(buffer);
5526 checkGLcall("glReadBuffer()");
5528 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5529 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5530 } else {
5531 TRACE("Source surface %p is offscreen\n", src_surface);
5532 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5533 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5534 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5535 checkGLcall("glReadBuffer()");
5538 /* Attach dst surface to dst fbo */
5539 dst_swapchain = get_swapchain(dst_surface);
5540 if (dst_swapchain) {
5541 GLenum buffer;
5543 TRACE("Destination surface %p is onscreen\n", dst_surface);
5545 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5546 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5547 glDrawBuffer(buffer);
5548 checkGLcall("glDrawBuffer()");
5550 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5551 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5552 } else {
5553 TRACE("Destination surface %p is offscreen\n", dst_surface);
5554 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5555 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5556 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5557 checkGLcall("glDrawBuffer()");
5560 if (flip) {
5561 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5562 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5563 } else {
5564 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5565 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5568 if (This->render_offscreen) {
5569 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5570 } else {
5571 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5572 checkGLcall("glBindFramebuffer()");
5575 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5576 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5577 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5578 glDrawBuffer(GL_BACK);
5579 checkGLcall("glDrawBuffer()");
5583 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5585 WINED3DVIEWPORT viewport;
5587 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5589 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5590 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5591 return WINED3DERR_INVALIDCALL;
5594 /* MSDN says that null disables the render target
5595 but a device must always be associated with a render target
5596 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5598 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5599 for more details
5601 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5602 FIXME("Trying to set render target 0 to NULL\n");
5603 return WINED3DERR_INVALIDCALL;
5605 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5606 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);
5607 return WINED3DERR_INVALIDCALL;
5610 /* If we are trying to set what we already have, don't bother */
5611 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5612 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5613 return WINED3D_OK;
5615 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5616 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5617 This->render_targets[RenderTargetIndex] = pRenderTarget;
5619 /* Render target 0 is special */
5620 if(RenderTargetIndex == 0) {
5621 /* Finally, reset the viewport as the MSDN states. */
5622 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5623 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5624 viewport.X = 0;
5625 viewport.Y = 0;
5626 viewport.MaxZ = 1.0f;
5627 viewport.MinZ = 0.0f;
5628 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5629 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5630 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5632 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5634 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5635 * ctx properly.
5636 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5637 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5639 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5641 return WINED3D_OK;
5644 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5646 HRESULT hr = WINED3D_OK;
5647 IWineD3DSurface *tmp;
5649 TRACE("(%p) Swapping z-buffer\n",This);
5651 if (pNewZStencil == This->stencilBufferTarget) {
5652 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5653 } else {
5654 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5655 * depending on the renter target implementation being used.
5656 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5657 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5658 * stencil buffer and incure an extra memory overhead
5659 ******************************************************/
5661 tmp = This->stencilBufferTarget;
5662 This->stencilBufferTarget = pNewZStencil;
5663 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5664 /* should we be calling the parent or the wined3d surface? */
5665 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5666 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5667 hr = WINED3D_OK;
5669 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5670 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5671 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5672 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5673 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5677 return hr;
5680 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5681 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5683 /* TODO: the use of Impl is deprecated. */
5684 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5686 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5688 /* some basic validation checks */
5689 if(This->cursorTexture) {
5690 ENTER_GL();
5691 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5692 glDeleteTextures(1, &This->cursorTexture);
5693 LEAVE_GL();
5694 This->cursorTexture = 0;
5697 if(pCursorBitmap) {
5698 WINED3DLOCKED_RECT rect;
5700 /* MSDN: Cursor must be A8R8G8B8 */
5701 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5702 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5703 return WINED3DERR_INVALIDCALL;
5706 /* MSDN: Cursor must be smaller than the display mode */
5707 if(pSur->currentDesc.Width > This->ddraw_width ||
5708 pSur->currentDesc.Height > This->ddraw_height) {
5709 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);
5710 return WINED3DERR_INVALIDCALL;
5713 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5715 /* Do not store the surface's pointer because the application may release
5716 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5717 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5719 This->cursorWidth = pSur->currentDesc.Width;
5720 This->cursorHeight = pSur->currentDesc.Height;
5721 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5723 const PixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8);
5724 char *mem, *bits = (char *)rect.pBits;
5725 GLint intfmt = tableEntry->glInternal;
5726 GLint format = tableEntry->glFormat;
5727 GLint type = tableEntry->glType;
5728 INT height = This->cursorHeight;
5729 INT width = This->cursorWidth;
5730 INT bpp = tableEntry->bpp;
5731 INT i;
5733 /* Reformat the texture memory (pitch and width can be different) */
5734 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5735 for(i = 0; i < height; i++)
5736 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5737 IWineD3DSurface_UnlockRect(pCursorBitmap);
5738 ENTER_GL();
5740 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5741 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5742 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5745 /* Make sure that a proper texture unit is selected */
5746 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5747 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5748 checkGLcall("glActiveTextureARB");
5750 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5751 /* Create a new cursor texture */
5752 glGenTextures(1, &This->cursorTexture);
5753 checkGLcall("glGenTextures");
5754 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5755 checkGLcall("glBindTexture");
5756 /* Copy the bitmap memory into the cursor texture */
5757 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5758 HeapFree(GetProcessHeap(), 0, mem);
5759 checkGLcall("glTexImage2D");
5761 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5762 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5763 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5766 LEAVE_GL();
5768 else
5770 FIXME("A cursor texture was not returned.\n");
5771 This->cursorTexture = 0;
5776 This->xHotSpot = XHotSpot;
5777 This->yHotSpot = YHotSpot;
5778 return WINED3D_OK;
5781 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5783 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5785 This->xScreenSpace = XScreenSpace;
5786 This->yScreenSpace = YScreenSpace;
5788 return;
5792 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5794 BOOL oldVisible = This->bCursorVisible;
5795 POINT pt;
5797 TRACE("(%p) : visible(%d)\n", This, bShow);
5799 if(This->cursorTexture)
5800 This->bCursorVisible = bShow;
5802 * When ShowCursor is first called it should make the cursor appear at the OS's last
5803 * known cursor position. Because of this, some applications just repetitively call
5804 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5806 GetCursorPos(&pt);
5807 This->xScreenSpace = pt.x;
5808 This->yScreenSpace = pt.y;
5810 return oldVisible;
5813 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5815 TRACE("(%p) : state (%u)\n", This, This->state);
5816 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5817 switch (This->state) {
5818 case WINED3D_OK:
5819 return WINED3D_OK;
5820 case WINED3DERR_DEVICELOST:
5822 ResourceList *resourceList = This->resources;
5823 while (NULL != resourceList) {
5824 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5825 return WINED3DERR_DEVICENOTRESET;
5826 resourceList = resourceList->next;
5828 return WINED3DERR_DEVICELOST;
5830 case WINED3DERR_DRIVERINTERNALERROR:
5831 return WINED3DERR_DRIVERINTERNALERROR;
5834 /* Unknown state */
5835 return WINED3DERR_DRIVERINTERNALERROR;
5839 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5841 /** FIXME: Resource tracking needs to be done,
5842 * The closes we can do to this is set the priorities of all managed textures low
5843 * and then reset them.
5844 ***********************************************************/
5845 FIXME("(%p) : stub\n", This);
5846 return WINED3D_OK;
5849 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5850 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5852 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5853 if(surface->Flags & SFLAG_DIBSECTION) {
5854 /* Release the DC */
5855 SelectObject(surface->hDC, surface->dib.holdbitmap);
5856 DeleteDC(surface->hDC);
5857 /* Release the DIB section */
5858 DeleteObject(surface->dib.DIBsection);
5859 surface->dib.bitmap_data = NULL;
5860 surface->resource.allocatedMemory = NULL;
5861 surface->Flags &= ~SFLAG_DIBSECTION;
5863 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5864 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5865 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5866 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5867 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5868 } else {
5869 surface->pow2Width = surface->pow2Height = 1;
5870 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5871 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5873 if(surface->glDescription.textureName) {
5874 ENTER_GL();
5875 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5876 glDeleteTextures(1, &surface->glDescription.textureName);
5877 LEAVE_GL();
5878 surface->glDescription.textureName = 0;
5879 surface->Flags &= ~SFLAG_CLIENT;
5881 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5882 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5883 surface->Flags |= SFLAG_NONPOW2;
5884 } else {
5885 surface->Flags &= ~SFLAG_NONPOW2;
5887 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5888 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5891 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5893 IWineD3DSwapChainImpl *swapchain;
5894 HRESULT hr;
5895 BOOL DisplayModeChanged = FALSE;
5896 WINED3DDISPLAYMODE mode;
5897 TRACE("(%p)\n", This);
5899 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5900 if(FAILED(hr)) {
5901 ERR("Failed to get the first implicit swapchain\n");
5902 return hr;
5905 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5906 * on an existing gl context, so there's no real need for recreation.
5908 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5910 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5912 TRACE("New params:\n");
5913 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5914 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5915 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5916 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5917 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
5918 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
5919 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
5920 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
5921 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
5922 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5923 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
5924 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
5925 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
5927 /* No special treatment of these parameters. Just store them */
5928 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
5929 swapchain->presentParms.Flags = pPresentationParameters->Flags;
5930 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
5931 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
5933 /* What to do about these? */
5934 if(pPresentationParameters->BackBufferCount != 0 &&
5935 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
5936 ERR("Cannot change the back buffer count yet\n");
5938 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5939 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5940 ERR("Cannot change the back buffer format yet\n");
5942 if(pPresentationParameters->hDeviceWindow != NULL &&
5943 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
5944 ERR("Cannot change the device window yet\n");
5946 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
5947 ERR("What do do about a changed auto depth stencil parameter?\n");
5950 if(pPresentationParameters->Windowed) {
5951 mode.Width = swapchain->orig_width;
5952 mode.Height = swapchain->orig_height;
5953 mode.RefreshRate = 0;
5954 mode.Format = swapchain->presentParms.BackBufferFormat;
5955 } else {
5956 mode.Width = pPresentationParameters->BackBufferWidth;
5957 mode.Height = pPresentationParameters->BackBufferHeight;
5958 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
5959 mode.Format = swapchain->presentParms.BackBufferFormat;
5962 /* Should Width == 800 && Height == 0 set 800x600? */
5963 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
5964 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
5965 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5967 WINED3DVIEWPORT vp;
5968 int i;
5970 vp.X = 0;
5971 vp.Y = 0;
5972 vp.Width = pPresentationParameters->BackBufferWidth;
5973 vp.Height = pPresentationParameters->BackBufferHeight;
5974 vp.MinZ = 0;
5975 vp.MaxZ = 1;
5977 if(!pPresentationParameters->Windowed) {
5978 DisplayModeChanged = TRUE;
5980 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
5981 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
5983 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
5984 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
5985 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
5988 /* Now set the new viewport */
5989 IWineD3DDevice_SetViewport(iface, &vp);
5992 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
5993 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
5994 DisplayModeChanged) {
5996 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
5997 if(!pPresentationParameters->Windowed) {
5998 IWineD3DDevice_SetFullscreen(iface, TRUE);
6001 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6003 /* Switching out of fullscreen mode? First set the original res, then change the window */
6004 if(pPresentationParameters->Windowed) {
6005 IWineD3DDevice_SetFullscreen(iface, FALSE);
6007 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6010 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6011 return WINED3D_OK;
6014 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6016 /** FIXME: always true at the moment **/
6017 if(!bEnableDialogs) {
6018 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6020 return WINED3D_OK;
6024 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6026 TRACE("(%p) : pParameters %p\n", This, pParameters);
6028 *pParameters = This->createParms;
6029 return WINED3D_OK;
6032 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6033 IWineD3DSwapChain *swapchain;
6034 HRESULT hrc = WINED3D_OK;
6036 TRACE("Relaying to swapchain\n");
6038 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6039 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6040 IWineD3DSwapChain_Release(swapchain);
6042 return;
6045 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6046 IWineD3DSwapChain *swapchain;
6047 HRESULT hrc = WINED3D_OK;
6049 TRACE("Relaying to swapchain\n");
6051 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6052 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6053 IWineD3DSwapChain_Release(swapchain);
6055 return;
6059 /** ********************************************************
6060 * Notification functions
6061 ** ********************************************************/
6062 /** This function must be called in the release of a resource when ref == 0,
6063 * the contents of resource must still be correct,
6064 * any handels to other resource held by the caller must be closed
6065 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6066 *****************************************************/
6067 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6069 ResourceList* resourceList;
6071 TRACE("(%p) : resource %p\n", This, resource);
6072 /* add a new texture to the frot of the linked list */
6073 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6074 resourceList->resource = resource;
6076 /* Get the old head */
6077 resourceList->next = This->resources;
6079 This->resources = resourceList;
6080 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6082 return;
6085 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6086 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6087 ResourceList* resourceList = NULL;
6088 ResourceList* previousResourceList = NULL;
6090 TRACE("(%p) : resource %p\n", This, resource);
6092 resourceList = This->resources;
6094 while (resourceList != NULL) {
6095 if(resourceList->resource == resource) break;
6096 previousResourceList = resourceList;
6097 resourceList = resourceList->next;
6100 if (resourceList == NULL) {
6101 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6102 return;
6103 } else {
6104 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6106 /* make sure we don't leave a hole in the list */
6107 if (previousResourceList != NULL) {
6108 previousResourceList->next = resourceList->next;
6109 } else {
6110 This->resources = resourceList->next;
6113 return;
6117 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6119 int counter;
6121 TRACE("(%p) : resource %p\n", This, resource);
6122 switch(IWineD3DResource_GetType(resource)){
6123 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6124 case WINED3DRTYPE_SURFACE: {
6125 unsigned int i;
6127 /* Cleanup any FBO attachments */
6128 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6129 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6130 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6131 set_render_target_fbo(iface, i, NULL);
6132 This->fbo_color_attachments[i] = NULL;
6135 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6136 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6137 set_depth_stencil_fbo(iface, NULL);
6138 This->fbo_depth_attachment = NULL;
6141 break;
6144 case WINED3DRTYPE_TEXTURE:
6145 case WINED3DRTYPE_CUBETEXTURE:
6146 case WINED3DRTYPE_VOLUMETEXTURE:
6147 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
6148 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6149 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6150 This->stateBlock->textures[counter] = NULL;
6152 if (This->updateStateBlock != This->stateBlock ){
6153 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6154 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6155 This->updateStateBlock->textures[counter] = NULL;
6159 break;
6160 case WINED3DRTYPE_VOLUME:
6161 /* TODO: nothing really? */
6162 break;
6163 case WINED3DRTYPE_VERTEXBUFFER:
6164 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6166 int streamNumber;
6167 TRACE("Cleaning up stream pointers\n");
6169 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6170 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6171 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6173 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6174 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6175 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6176 This->updateStateBlock->streamSource[streamNumber] = 0;
6177 /* Set changed flag? */
6180 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) */
6181 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6182 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6183 This->stateBlock->streamSource[streamNumber] = 0;
6186 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6187 else { /* This shouldn't happen */
6188 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6190 #endif
6194 break;
6195 case WINED3DRTYPE_INDEXBUFFER:
6196 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6197 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6198 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6199 This->updateStateBlock->pIndexData = NULL;
6202 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6203 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6204 This->stateBlock->pIndexData = NULL;
6208 break;
6209 default:
6210 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6211 break;
6215 /* Remove the resoruce from the resourceStore */
6216 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6218 TRACE("Resource released\n");
6222 /**********************************************************
6223 * IWineD3DDevice VTbl follows
6224 **********************************************************/
6226 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6228 /*** IUnknown methods ***/
6229 IWineD3DDeviceImpl_QueryInterface,
6230 IWineD3DDeviceImpl_AddRef,
6231 IWineD3DDeviceImpl_Release,
6232 /*** IWineD3DDevice methods ***/
6233 IWineD3DDeviceImpl_GetParent,
6234 /*** Creation methods**/
6235 IWineD3DDeviceImpl_CreateVertexBuffer,
6236 IWineD3DDeviceImpl_CreateIndexBuffer,
6237 IWineD3DDeviceImpl_CreateStateBlock,
6238 IWineD3DDeviceImpl_CreateSurface,
6239 IWineD3DDeviceImpl_CreateTexture,
6240 IWineD3DDeviceImpl_CreateVolumeTexture,
6241 IWineD3DDeviceImpl_CreateVolume,
6242 IWineD3DDeviceImpl_CreateCubeTexture,
6243 IWineD3DDeviceImpl_CreateQuery,
6244 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6245 IWineD3DDeviceImpl_CreateVertexDeclaration,
6246 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6247 IWineD3DDeviceImpl_CreateVertexShader,
6248 IWineD3DDeviceImpl_CreatePixelShader,
6249 IWineD3DDeviceImpl_CreatePalette,
6250 /*** Odd functions **/
6251 IWineD3DDeviceImpl_Init3D,
6252 IWineD3DDeviceImpl_Uninit3D,
6253 IWineD3DDeviceImpl_SetFullscreen,
6254 IWineD3DDeviceImpl_SetMultithreaded,
6255 IWineD3DDeviceImpl_EvictManagedResources,
6256 IWineD3DDeviceImpl_GetAvailableTextureMem,
6257 IWineD3DDeviceImpl_GetBackBuffer,
6258 IWineD3DDeviceImpl_GetCreationParameters,
6259 IWineD3DDeviceImpl_GetDeviceCaps,
6260 IWineD3DDeviceImpl_GetDirect3D,
6261 IWineD3DDeviceImpl_GetDisplayMode,
6262 IWineD3DDeviceImpl_SetDisplayMode,
6263 IWineD3DDeviceImpl_GetHWND,
6264 IWineD3DDeviceImpl_SetHWND,
6265 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6266 IWineD3DDeviceImpl_GetRasterStatus,
6267 IWineD3DDeviceImpl_GetSwapChain,
6268 IWineD3DDeviceImpl_Reset,
6269 IWineD3DDeviceImpl_SetDialogBoxMode,
6270 IWineD3DDeviceImpl_SetCursorProperties,
6271 IWineD3DDeviceImpl_SetCursorPosition,
6272 IWineD3DDeviceImpl_ShowCursor,
6273 IWineD3DDeviceImpl_TestCooperativeLevel,
6274 /*** Getters and setters **/
6275 IWineD3DDeviceImpl_SetClipPlane,
6276 IWineD3DDeviceImpl_GetClipPlane,
6277 IWineD3DDeviceImpl_SetClipStatus,
6278 IWineD3DDeviceImpl_GetClipStatus,
6279 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6280 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6281 IWineD3DDeviceImpl_SetDepthStencilSurface,
6282 IWineD3DDeviceImpl_GetDepthStencilSurface,
6283 IWineD3DDeviceImpl_SetFVF,
6284 IWineD3DDeviceImpl_GetFVF,
6285 IWineD3DDeviceImpl_SetGammaRamp,
6286 IWineD3DDeviceImpl_GetGammaRamp,
6287 IWineD3DDeviceImpl_SetIndices,
6288 IWineD3DDeviceImpl_GetIndices,
6289 IWineD3DDeviceImpl_SetBasevertexIndex,
6290 IWineD3DDeviceImpl_SetLight,
6291 IWineD3DDeviceImpl_GetLight,
6292 IWineD3DDeviceImpl_SetLightEnable,
6293 IWineD3DDeviceImpl_GetLightEnable,
6294 IWineD3DDeviceImpl_SetMaterial,
6295 IWineD3DDeviceImpl_GetMaterial,
6296 IWineD3DDeviceImpl_SetNPatchMode,
6297 IWineD3DDeviceImpl_GetNPatchMode,
6298 IWineD3DDeviceImpl_SetPaletteEntries,
6299 IWineD3DDeviceImpl_GetPaletteEntries,
6300 IWineD3DDeviceImpl_SetPixelShader,
6301 IWineD3DDeviceImpl_GetPixelShader,
6302 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6303 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6304 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6305 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6306 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6307 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6308 IWineD3DDeviceImpl_SetRenderState,
6309 IWineD3DDeviceImpl_GetRenderState,
6310 IWineD3DDeviceImpl_SetRenderTarget,
6311 IWineD3DDeviceImpl_GetRenderTarget,
6312 IWineD3DDeviceImpl_SetFrontBackBuffers,
6313 IWineD3DDeviceImpl_SetSamplerState,
6314 IWineD3DDeviceImpl_GetSamplerState,
6315 IWineD3DDeviceImpl_SetScissorRect,
6316 IWineD3DDeviceImpl_GetScissorRect,
6317 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6318 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6319 IWineD3DDeviceImpl_SetStreamSource,
6320 IWineD3DDeviceImpl_GetStreamSource,
6321 IWineD3DDeviceImpl_SetStreamSourceFreq,
6322 IWineD3DDeviceImpl_GetStreamSourceFreq,
6323 IWineD3DDeviceImpl_SetTexture,
6324 IWineD3DDeviceImpl_GetTexture,
6325 IWineD3DDeviceImpl_SetTextureStageState,
6326 IWineD3DDeviceImpl_GetTextureStageState,
6327 IWineD3DDeviceImpl_SetTransform,
6328 IWineD3DDeviceImpl_GetTransform,
6329 IWineD3DDeviceImpl_SetVertexDeclaration,
6330 IWineD3DDeviceImpl_GetVertexDeclaration,
6331 IWineD3DDeviceImpl_SetVertexShader,
6332 IWineD3DDeviceImpl_GetVertexShader,
6333 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6334 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6335 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6336 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6337 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6338 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6339 IWineD3DDeviceImpl_SetViewport,
6340 IWineD3DDeviceImpl_GetViewport,
6341 IWineD3DDeviceImpl_MultiplyTransform,
6342 IWineD3DDeviceImpl_ValidateDevice,
6343 IWineD3DDeviceImpl_ProcessVertices,
6344 /*** State block ***/
6345 IWineD3DDeviceImpl_BeginStateBlock,
6346 IWineD3DDeviceImpl_EndStateBlock,
6347 /*** Scene management ***/
6348 IWineD3DDeviceImpl_BeginScene,
6349 IWineD3DDeviceImpl_EndScene,
6350 IWineD3DDeviceImpl_Present,
6351 IWineD3DDeviceImpl_Clear,
6352 /*** Drawing ***/
6353 IWineD3DDeviceImpl_DrawPrimitive,
6354 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6355 IWineD3DDeviceImpl_DrawPrimitiveUP,
6356 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6357 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6358 IWineD3DDeviceImpl_DrawRectPatch,
6359 IWineD3DDeviceImpl_DrawTriPatch,
6360 IWineD3DDeviceImpl_DeletePatch,
6361 IWineD3DDeviceImpl_ColorFill,
6362 IWineD3DDeviceImpl_UpdateTexture,
6363 IWineD3DDeviceImpl_UpdateSurface,
6364 IWineD3DDeviceImpl_GetFrontBufferData,
6365 /*** object tracking ***/
6366 IWineD3DDeviceImpl_ResourceReleased
6370 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6371 WINED3DRS_ALPHABLENDENABLE ,
6372 WINED3DRS_ALPHAFUNC ,
6373 WINED3DRS_ALPHAREF ,
6374 WINED3DRS_ALPHATESTENABLE ,
6375 WINED3DRS_BLENDOP ,
6376 WINED3DRS_COLORWRITEENABLE ,
6377 WINED3DRS_DESTBLEND ,
6378 WINED3DRS_DITHERENABLE ,
6379 WINED3DRS_FILLMODE ,
6380 WINED3DRS_FOGDENSITY ,
6381 WINED3DRS_FOGEND ,
6382 WINED3DRS_FOGSTART ,
6383 WINED3DRS_LASTPIXEL ,
6384 WINED3DRS_SHADEMODE ,
6385 WINED3DRS_SRCBLEND ,
6386 WINED3DRS_STENCILENABLE ,
6387 WINED3DRS_STENCILFAIL ,
6388 WINED3DRS_STENCILFUNC ,
6389 WINED3DRS_STENCILMASK ,
6390 WINED3DRS_STENCILPASS ,
6391 WINED3DRS_STENCILREF ,
6392 WINED3DRS_STENCILWRITEMASK ,
6393 WINED3DRS_STENCILZFAIL ,
6394 WINED3DRS_TEXTUREFACTOR ,
6395 WINED3DRS_WRAP0 ,
6396 WINED3DRS_WRAP1 ,
6397 WINED3DRS_WRAP2 ,
6398 WINED3DRS_WRAP3 ,
6399 WINED3DRS_WRAP4 ,
6400 WINED3DRS_WRAP5 ,
6401 WINED3DRS_WRAP6 ,
6402 WINED3DRS_WRAP7 ,
6403 WINED3DRS_ZENABLE ,
6404 WINED3DRS_ZFUNC ,
6405 WINED3DRS_ZWRITEENABLE
6408 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6409 WINED3DTSS_ADDRESSW ,
6410 WINED3DTSS_ALPHAARG0 ,
6411 WINED3DTSS_ALPHAARG1 ,
6412 WINED3DTSS_ALPHAARG2 ,
6413 WINED3DTSS_ALPHAOP ,
6414 WINED3DTSS_BUMPENVLOFFSET ,
6415 WINED3DTSS_BUMPENVLSCALE ,
6416 WINED3DTSS_BUMPENVMAT00 ,
6417 WINED3DTSS_BUMPENVMAT01 ,
6418 WINED3DTSS_BUMPENVMAT10 ,
6419 WINED3DTSS_BUMPENVMAT11 ,
6420 WINED3DTSS_COLORARG0 ,
6421 WINED3DTSS_COLORARG1 ,
6422 WINED3DTSS_COLORARG2 ,
6423 WINED3DTSS_COLOROP ,
6424 WINED3DTSS_RESULTARG ,
6425 WINED3DTSS_TEXCOORDINDEX ,
6426 WINED3DTSS_TEXTURETRANSFORMFLAGS
6429 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6430 WINED3DSAMP_ADDRESSU ,
6431 WINED3DSAMP_ADDRESSV ,
6432 WINED3DSAMP_ADDRESSW ,
6433 WINED3DSAMP_BORDERCOLOR ,
6434 WINED3DSAMP_MAGFILTER ,
6435 WINED3DSAMP_MINFILTER ,
6436 WINED3DSAMP_MIPFILTER ,
6437 WINED3DSAMP_MIPMAPLODBIAS ,
6438 WINED3DSAMP_MAXMIPLEVEL ,
6439 WINED3DSAMP_MAXANISOTROPY ,
6440 WINED3DSAMP_SRGBTEXTURE ,
6441 WINED3DSAMP_ELEMENTINDEX
6444 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6445 WINED3DRS_AMBIENT ,
6446 WINED3DRS_AMBIENTMATERIALSOURCE ,
6447 WINED3DRS_CLIPPING ,
6448 WINED3DRS_CLIPPLANEENABLE ,
6449 WINED3DRS_COLORVERTEX ,
6450 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6451 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6452 WINED3DRS_FOGDENSITY ,
6453 WINED3DRS_FOGEND ,
6454 WINED3DRS_FOGSTART ,
6455 WINED3DRS_FOGTABLEMODE ,
6456 WINED3DRS_FOGVERTEXMODE ,
6457 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6458 WINED3DRS_LIGHTING ,
6459 WINED3DRS_LOCALVIEWER ,
6460 WINED3DRS_MULTISAMPLEANTIALIAS ,
6461 WINED3DRS_MULTISAMPLEMASK ,
6462 WINED3DRS_NORMALIZENORMALS ,
6463 WINED3DRS_PATCHEDGESTYLE ,
6464 WINED3DRS_POINTSCALE_A ,
6465 WINED3DRS_POINTSCALE_B ,
6466 WINED3DRS_POINTSCALE_C ,
6467 WINED3DRS_POINTSCALEENABLE ,
6468 WINED3DRS_POINTSIZE ,
6469 WINED3DRS_POINTSIZE_MAX ,
6470 WINED3DRS_POINTSIZE_MIN ,
6471 WINED3DRS_POINTSPRITEENABLE ,
6472 WINED3DRS_RANGEFOGENABLE ,
6473 WINED3DRS_SPECULARMATERIALSOURCE ,
6474 WINED3DRS_TWEENFACTOR ,
6475 WINED3DRS_VERTEXBLEND
6478 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6479 WINED3DTSS_TEXCOORDINDEX ,
6480 WINED3DTSS_TEXTURETRANSFORMFLAGS
6483 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6484 WINED3DSAMP_DMAPOFFSET
6487 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6488 DWORD rep = StateTable[state].representative;
6489 DWORD idx;
6490 BYTE shift;
6491 UINT i;
6492 WineD3DContext *context;
6494 if(!rep) return;
6495 for(i = 0; i < This->numContexts; i++) {
6496 context = This->contexts[i];
6497 if(isStateDirty(context, rep)) continue;
6499 context->dirtyArray[context->numDirtyEntries++] = rep;
6500 idx = rep >> 5;
6501 shift = rep & 0x1f;
6502 context->isStateDirty[idx] |= (1 << shift);