wined3d: Remove resourceStoreCriticalSection.
[wine/hacks.git] / dlls / wined3d / device.c
blobdd9d3200d5f8266a8385d1a9c5088f4a8eb039e7
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, &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, Width, Height, Depth, 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 */, &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 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1581 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1583 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1584 HRESULT hr = WINED3D_OK;
1585 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1586 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1588 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1590 if (vertex_declaration) {
1591 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1594 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1596 if (WINED3D_OK != hr) {
1597 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1598 IWineD3DVertexShader_Release(*ppVertexShader);
1599 return WINED3DERR_INVALIDCALL;
1602 return WINED3D_OK;
1605 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1607 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1608 HRESULT hr = WINED3D_OK;
1610 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1611 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1612 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1613 if (WINED3D_OK == hr) {
1614 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1615 } else {
1616 WARN("(%p) : Failed to create pixel shader\n", This);
1619 return hr;
1622 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1624 IWineD3DPaletteImpl *object;
1625 HRESULT hr;
1626 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1628 /* Create the new object */
1629 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1630 if(!object) {
1631 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1632 return E_OUTOFMEMORY;
1635 object->lpVtbl = &IWineD3DPalette_Vtbl;
1636 object->ref = 1;
1637 object->Flags = Flags;
1638 object->parent = Parent;
1639 object->wineD3DDevice = This;
1640 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1642 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1644 if(!object->hpal) {
1645 HeapFree( GetProcessHeap(), 0, object);
1646 return E_OUTOFMEMORY;
1649 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1650 if(FAILED(hr)) {
1651 IWineD3DPalette_Release((IWineD3DPalette *) object);
1652 return hr;
1655 *Palette = (IWineD3DPalette *) object;
1657 return WINED3D_OK;
1660 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1662 IWineD3DSwapChainImpl *swapchain;
1663 DWORD state;
1665 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1666 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1668 /* TODO: Test if OpenGL is compiled in and loaded */
1670 /* Initialize the texture unit mapping to a 1:1 mapping */
1671 for(state = 0; state < MAX_SAMPLERS; state++) {
1672 This->texUnitMap[state] = state;
1674 This->oneToOneTexUnitMap = TRUE;
1676 /* Setup the implicit swapchain */
1677 TRACE("Creating implicit swapchain\n");
1678 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain)) || !swapchain) {
1679 WARN("Failed to create implicit swapchain\n");
1680 return WINED3DERR_INVALIDCALL;
1683 This->NumberOfSwapChains = 1;
1684 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1685 if(!This->swapchains) {
1686 ERR("Out of memory!\n");
1687 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1688 return E_OUTOFMEMORY;
1690 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1692 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1694 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1695 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1696 This->render_targets[0] = swapchain->backBuffer[0];
1697 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1699 else {
1700 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1701 This->render_targets[0] = swapchain->frontBuffer;
1702 This->lastActiveRenderTarget = swapchain->frontBuffer;
1704 IWineD3DSurface_AddRef(This->render_targets[0]);
1705 This->activeContext = swapchain->context[0];
1707 /* Depth Stencil support */
1708 This->stencilBufferTarget = This->depthStencilBuffer;
1709 if (NULL != This->stencilBufferTarget) {
1710 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1713 /* Set up some starting GL setup */
1714 ENTER_GL();
1716 * Initialize openGL extension related variables
1717 * with Default values
1720 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps(This->wineD3D, swapchain->context[0]->display);
1721 /* Setup all the devices defaults */
1722 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1723 #if 0
1724 IWineD3DImpl_CheckGraphicsMemory();
1725 #endif
1727 { /* Set a default viewport */
1728 WINED3DVIEWPORT vp;
1729 vp.X = 0;
1730 vp.Y = 0;
1731 vp.Width = pPresentationParameters->BackBufferWidth;
1732 vp.Height = pPresentationParameters->BackBufferHeight;
1733 vp.MinZ = 0.0f;
1734 vp.MaxZ = 1.0f;
1735 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1738 /* Initialize the current view state */
1739 This->view_ident = 1;
1740 This->contexts[0]->last_was_rhw = 0;
1741 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1742 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1744 switch(wined3d_settings.offscreen_rendering_mode) {
1745 case ORM_FBO:
1746 case ORM_PBUFFER:
1747 This->offscreenBuffer = GL_BACK;
1748 break;
1750 case ORM_BACKBUFFER:
1752 if(GL_LIMITS(aux_buffers) > 0) {
1753 TRACE("Using auxilliary buffer for offscreen rendering\n");
1754 This->offscreenBuffer = GL_AUX0;
1755 } else {
1756 TRACE("Using back buffer for offscreen rendering\n");
1757 This->offscreenBuffer = GL_BACK;
1762 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1763 LEAVE_GL();
1765 /* Clear the screen */
1766 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1767 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1768 0x00, 1.0, 0);
1770 This->d3d_initialized = TRUE;
1771 return WINED3D_OK;
1774 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1776 int sampler;
1777 uint i;
1778 TRACE("(%p)\n", This);
1780 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1782 ENTER_GL();
1783 /* I don't think that the interface guarants that the device is destroyed from the same thread
1784 * it was created. Thus make sure a context is active for the glDelete* calls
1786 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1787 LEAVE_GL();
1789 /* Delete the pbuffer context if there is any */
1790 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1792 /* Delete the mouse cursor texture */
1793 if(This->cursorTexture) {
1794 ENTER_GL();
1795 glDeleteTextures(1, &This->cursorTexture);
1796 LEAVE_GL();
1797 This->cursorTexture = 0;
1800 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1801 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1804 /* Release the buffers (with sanity checks)*/
1805 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1806 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1807 if(This->depthStencilBuffer != This->stencilBufferTarget)
1808 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1810 This->stencilBufferTarget = NULL;
1812 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1813 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1814 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1816 TRACE("Setting rendertarget to NULL\n");
1817 This->render_targets[0] = NULL;
1819 if (This->depthStencilBuffer) {
1820 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1821 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1823 This->depthStencilBuffer = NULL;
1826 for(i=0; i < This->NumberOfSwapChains; i++) {
1827 TRACE("Releasing the implicit swapchain %d\n", i);
1828 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1829 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1833 HeapFree(GetProcessHeap(), 0, This->swapchains);
1834 This->swapchains = NULL;
1835 This->NumberOfSwapChains = 0;
1837 This->d3d_initialized = FALSE;
1838 return WINED3D_OK;
1841 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1843 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1845 /* Setup the window for fullscreen mode */
1846 if(fullscreen && !This->ddraw_fullscreen) {
1847 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1848 } else if(!fullscreen && This->ddraw_fullscreen) {
1849 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1852 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1853 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1854 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1855 * separately.
1857 This->ddraw_fullscreen = fullscreen;
1860 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
1861 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1862 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1864 * There is no way to deactivate thread safety once it is enabled
1866 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1868 FIXME("No thread safety in wined3d yet\n");
1870 /*For now just store the flag(needed in case of ddraw) */
1871 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1873 return;
1876 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
1877 DEVMODEW devmode;
1878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1879 LONG ret;
1880 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
1881 RECT clip_rc;
1883 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1885 /* Resize the screen even without a window:
1886 * The app could have unset it with SetCooperativeLevel, but not called
1887 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1888 * but we don't have any hwnd
1891 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1892 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1893 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
1894 devmode.dmPelsWidth = pMode->Width;
1895 devmode.dmPelsHeight = pMode->Height;
1897 devmode.dmDisplayFrequency = pMode->RefreshRate;
1898 if (pMode->RefreshRate != 0) {
1899 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1902 /* Only change the mode if necessary */
1903 if( (This->ddraw_width == pMode->Width) &&
1904 (This->ddraw_height == pMode->Height) &&
1905 (This->ddraw_format == pMode->Format) &&
1906 (pMode->RefreshRate == 0) ) {
1907 return WINED3D_OK;
1910 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1911 if (ret != DISP_CHANGE_SUCCESSFUL) {
1912 if(devmode.dmDisplayFrequency != 0) {
1913 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1914 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1915 devmode.dmDisplayFrequency = 0;
1916 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1918 if(ret != DISP_CHANGE_SUCCESSFUL) {
1919 return WINED3DERR_NOTAVAILABLE;
1923 /* Store the new values */
1924 This->ddraw_width = pMode->Width;
1925 This->ddraw_height = pMode->Height;
1926 This->ddraw_format = pMode->Format;
1928 /* Only do this with a window of course */
1929 if(This->ddraw_window)
1930 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
1932 /* And finally clip mouse to our screen */
1933 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1934 ClipCursor(&clip_rc);
1936 return WINED3D_OK;
1939 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1941 *ppD3D= This->wineD3D;
1942 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
1943 IWineD3D_AddRef(*ppD3D);
1944 return WINED3D_OK;
1947 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1948 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
1949 * into the video ram as possible and seeing how many fit
1950 * you can also get the correct initial value from nvidia and ATI's driver via X
1951 * texture memory is video memory + AGP memory
1952 *******************/
1953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1954 static BOOL showfixmes = TRUE;
1955 if (showfixmes) {
1956 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
1957 (wined3d_settings.emulated_textureram/(1024*1024)),
1958 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1959 showfixmes = FALSE;
1961 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1962 (wined3d_settings.emulated_textureram/(1024*1024)),
1963 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1964 /* return simulated texture memory left */
1965 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
1970 /*****
1971 * Get / Set FVF
1972 *****/
1973 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
1974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1976 /* Update the current state block */
1977 This->updateStateBlock->changed.fvf = TRUE;
1978 This->updateStateBlock->set.fvf = TRUE;
1980 if(This->updateStateBlock->fvf == fvf) {
1981 TRACE("Application is setting the old fvf over, nothing to do\n");
1982 return WINED3D_OK;
1985 This->updateStateBlock->fvf = fvf;
1986 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
1987 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
1988 return WINED3D_OK;
1992 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
1993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1994 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
1995 *pfvf = This->stateBlock->fvf;
1996 return WINED3D_OK;
1999 /*****
2000 * Get / Set Stream Source
2001 *****/
2002 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2004 IWineD3DVertexBuffer *oldSrc;
2006 if (StreamNumber >= MAX_STREAMS) {
2007 WARN("Stream out of range %d\n", StreamNumber);
2008 return WINED3DERR_INVALIDCALL;
2011 oldSrc = This->stateBlock->streamSource[StreamNumber];
2012 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2014 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2015 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2017 if(oldSrc == pStreamData &&
2018 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2019 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2020 TRACE("Application is setting the old values over, nothing to do\n");
2021 return WINED3D_OK;
2024 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2025 if (pStreamData) {
2026 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2027 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2030 /* Handle recording of state blocks */
2031 if (This->isRecordingState) {
2032 TRACE("Recording... not performing anything\n");
2033 return WINED3D_OK;
2036 /* Need to do a getParent and pass the reffs up */
2037 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2038 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2039 so for now, just count internally */
2040 if (pStreamData != NULL) {
2041 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2042 InterlockedIncrement(&vbImpl->bindCount);
2044 if (oldSrc != NULL) {
2045 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2048 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2050 return WINED3D_OK;
2053 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2056 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2057 This->stateBlock->streamSource[StreamNumber],
2058 This->stateBlock->streamOffset[StreamNumber],
2059 This->stateBlock->streamStride[StreamNumber]);
2061 if (StreamNumber >= MAX_STREAMS) {
2062 WARN("Stream out of range %d\n", StreamNumber);
2063 return WINED3DERR_INVALIDCALL;
2065 *pStream = This->stateBlock->streamSource[StreamNumber];
2066 *pStride = This->stateBlock->streamStride[StreamNumber];
2067 if (pOffset) {
2068 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2071 if (*pStream != NULL) {
2072 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2074 return WINED3D_OK;
2077 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2079 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2080 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2082 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2083 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2085 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2086 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2087 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2089 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2090 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2091 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2094 return WINED3D_OK;
2097 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2098 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2100 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2101 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2103 TRACE("(%p) : returning %d\n", This, *Divider);
2105 return WINED3D_OK;
2108 /*****
2109 * Get / Set & Multiply Transform
2110 *****/
2111 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2114 /* Most of this routine, comments included copied from ddraw tree initially: */
2115 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2117 /* Handle recording of state blocks */
2118 if (This->isRecordingState) {
2119 TRACE("Recording... not performing anything\n");
2120 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2121 This->updateStateBlock->set.transform[d3dts] = TRUE;
2122 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2123 return WINED3D_OK;
2127 * If the new matrix is the same as the current one,
2128 * we cut off any further processing. this seems to be a reasonable
2129 * optimization because as was noticed, some apps (warcraft3 for example)
2130 * tend towards setting the same matrix repeatedly for some reason.
2132 * From here on we assume that the new matrix is different, wherever it matters.
2134 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2135 TRACE("The app is setting the same matrix over again\n");
2136 return WINED3D_OK;
2137 } else {
2138 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2142 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2143 where ViewMat = Camera space, WorldMat = world space.
2145 In OpenGL, camera and world space is combined into GL_MODELVIEW
2146 matrix. The Projection matrix stay projection matrix.
2149 /* Capture the times we can just ignore the change for now */
2150 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2151 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2152 /* Handled by the state manager */
2155 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2156 return WINED3D_OK;
2159 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2161 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2162 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2163 return WINED3D_OK;
2166 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2167 WINED3DMATRIX *mat = NULL;
2168 WINED3DMATRIX temp;
2170 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2171 * below means it will be recorded in a state block change, but it
2172 * works regardless where it is recorded.
2173 * If this is found to be wrong, change to StateBlock.
2175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2176 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2178 if (State < HIGHEST_TRANSFORMSTATE)
2180 mat = &This->updateStateBlock->transforms[State];
2181 } else {
2182 FIXME("Unhandled transform state!!\n");
2185 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2187 /* Apply change via set transform - will reapply to eg. lights this way */
2188 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2191 /*****
2192 * Get / Set Light
2193 *****/
2194 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2195 you can reference any indexes you want as long as that number max are enabled at any
2196 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2197 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2198 but when recording, just build a chain pretty much of commands to be replayed. */
2200 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2201 float rho;
2202 PLIGHTINFOEL *object = NULL;
2203 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2204 struct list *e;
2206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2207 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2209 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2210 * the gl driver.
2212 if(!pLight) {
2213 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2214 return WINED3DERR_INVALIDCALL;
2217 switch(pLight->Type) {
2218 case WINED3DLIGHT_POINT:
2219 case WINED3DLIGHT_SPOT:
2220 case WINED3DLIGHT_PARALLELPOINT:
2221 case WINED3DLIGHT_GLSPOT:
2222 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2223 * most wanted
2225 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2226 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2227 return WINED3DERR_INVALIDCALL;
2229 break;
2231 case WINED3DLIGHT_DIRECTIONAL:
2232 /* Ignores attenuation */
2233 break;
2235 default:
2236 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2237 return WINED3DERR_INVALIDCALL;
2240 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2241 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2242 if(object->OriginalIndex == Index) break;
2243 object = NULL;
2246 if(!object) {
2247 TRACE("Adding new light\n");
2248 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2249 if(!object) {
2250 ERR("Out of memory error when allocating a light\n");
2251 return E_OUTOFMEMORY;
2253 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2254 object->glIndex = -1;
2255 object->OriginalIndex = Index;
2256 object->changed = TRUE;
2259 /* Initialize the object */
2260 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,
2261 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2262 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2263 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2264 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2265 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2266 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2268 /* Save away the information */
2269 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2271 switch (pLight->Type) {
2272 case WINED3DLIGHT_POINT:
2273 /* Position */
2274 object->lightPosn[0] = pLight->Position.x;
2275 object->lightPosn[1] = pLight->Position.y;
2276 object->lightPosn[2] = pLight->Position.z;
2277 object->lightPosn[3] = 1.0f;
2278 object->cutoff = 180.0f;
2279 /* FIXME: Range */
2280 break;
2282 case WINED3DLIGHT_DIRECTIONAL:
2283 /* Direction */
2284 object->lightPosn[0] = -pLight->Direction.x;
2285 object->lightPosn[1] = -pLight->Direction.y;
2286 object->lightPosn[2] = -pLight->Direction.z;
2287 object->lightPosn[3] = 0.0;
2288 object->exponent = 0.0f;
2289 object->cutoff = 180.0f;
2290 break;
2292 case WINED3DLIGHT_SPOT:
2293 /* Position */
2294 object->lightPosn[0] = pLight->Position.x;
2295 object->lightPosn[1] = pLight->Position.y;
2296 object->lightPosn[2] = pLight->Position.z;
2297 object->lightPosn[3] = 1.0;
2299 /* Direction */
2300 object->lightDirn[0] = pLight->Direction.x;
2301 object->lightDirn[1] = pLight->Direction.y;
2302 object->lightDirn[2] = pLight->Direction.z;
2303 object->lightDirn[3] = 1.0;
2306 * opengl-ish and d3d-ish spot lights use too different models for the
2307 * light "intensity" as a function of the angle towards the main light direction,
2308 * so we only can approximate very roughly.
2309 * however spot lights are rather rarely used in games (if ever used at all).
2310 * furthermore if still used, probably nobody pays attention to such details.
2312 if (pLight->Falloff == 0) {
2313 rho = 6.28f;
2314 } else {
2315 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2317 if (rho < 0.0001) rho = 0.0001f;
2318 object->exponent = -0.3/log(cos(rho/2));
2319 if (object->exponent > 128.0) {
2320 object->exponent = 128.0;
2322 object->cutoff = pLight->Phi*90/M_PI;
2324 /* FIXME: Range */
2325 break;
2327 default:
2328 FIXME("Unrecognized light type %d\n", pLight->Type);
2331 /* Update the live definitions if the light is currently assigned a glIndex */
2332 if (object->glIndex != -1 && !This->isRecordingState) {
2333 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2335 return WINED3D_OK;
2338 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2339 PLIGHTINFOEL *lightInfo = NULL;
2340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2341 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2342 struct list *e;
2343 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2345 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2346 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2347 if(lightInfo->OriginalIndex == Index) break;
2348 lightInfo = NULL;
2351 if (lightInfo == NULL) {
2352 TRACE("Light information requested but light not defined\n");
2353 return WINED3DERR_INVALIDCALL;
2356 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2357 return WINED3D_OK;
2360 /*****
2361 * Get / Set Light Enable
2362 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2363 *****/
2364 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2365 PLIGHTINFOEL *lightInfo = NULL;
2366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2367 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2368 struct list *e;
2369 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2371 /* Tests show true = 128...not clear why */
2372 Enable = Enable? 128: 0;
2374 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2375 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2376 if(lightInfo->OriginalIndex == Index) break;
2377 lightInfo = NULL;
2379 TRACE("Found light: %p\n", lightInfo);
2381 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2382 if (lightInfo == NULL) {
2384 TRACE("Light enabled requested but light not defined, so defining one!\n");
2385 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2387 /* Search for it again! Should be fairly quick as near head of list */
2388 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2389 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2390 if(lightInfo->OriginalIndex == Index) break;
2391 lightInfo = NULL;
2393 if (lightInfo == NULL) {
2394 FIXME("Adding default lights has failed dismally\n");
2395 return WINED3DERR_INVALIDCALL;
2399 lightInfo->enabledChanged = TRUE;
2400 if(!Enable) {
2401 if(lightInfo->glIndex != -1) {
2402 if(!This->isRecordingState) {
2403 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2406 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2407 lightInfo->glIndex = -1;
2408 } else {
2409 TRACE("Light already disabled, nothing to do\n");
2411 } else {
2412 if (lightInfo->glIndex != -1) {
2413 /* nop */
2414 TRACE("Nothing to do as light was enabled\n");
2415 } else {
2416 int i;
2417 /* Find a free gl light */
2418 for(i = 0; i < This->maxConcurrentLights; i++) {
2419 if(This->stateBlock->activeLights[i] == NULL) {
2420 This->stateBlock->activeLights[i] = lightInfo;
2421 lightInfo->glIndex = i;
2422 break;
2425 if(lightInfo->glIndex == -1) {
2426 ERR("Too many concurrently active lights\n");
2427 return WINED3DERR_INVALIDCALL;
2430 /* i == lightInfo->glIndex */
2431 if(!This->isRecordingState) {
2432 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2437 return WINED3D_OK;
2440 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2442 PLIGHTINFOEL *lightInfo = NULL;
2443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2444 struct list *e;
2445 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2446 TRACE("(%p) : for idx(%d)\n", This, Index);
2448 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2449 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2450 if(lightInfo->OriginalIndex == Index) break;
2451 lightInfo = NULL;
2454 if (lightInfo == NULL) {
2455 TRACE("Light enabled state requested but light not defined\n");
2456 return WINED3DERR_INVALIDCALL;
2458 /* true is 128 according to SetLightEnable */
2459 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2460 return WINED3D_OK;
2463 /*****
2464 * Get / Set Clip Planes
2465 *****/
2466 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2467 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2468 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2470 /* Validate Index */
2471 if (Index >= GL_LIMITS(clipplanes)) {
2472 TRACE("Application has requested clipplane this device doesn't support\n");
2473 return WINED3DERR_INVALIDCALL;
2476 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2477 This->updateStateBlock->set.clipplane[Index] = TRUE;
2479 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2480 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2481 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2482 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2483 TRACE("Application is setting old values over, nothing to do\n");
2484 return WINED3D_OK;
2487 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2488 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2489 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2490 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2492 /* Handle recording of state blocks */
2493 if (This->isRecordingState) {
2494 TRACE("Recording... not performing anything\n");
2495 return WINED3D_OK;
2498 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2500 return WINED3D_OK;
2503 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2505 TRACE("(%p) : for idx %d\n", This, Index);
2507 /* Validate Index */
2508 if (Index >= GL_LIMITS(clipplanes)) {
2509 TRACE("Application has requested clipplane this device doesn't support\n");
2510 return WINED3DERR_INVALIDCALL;
2513 pPlane[0] = This->stateBlock->clipplane[Index][0];
2514 pPlane[1] = This->stateBlock->clipplane[Index][1];
2515 pPlane[2] = This->stateBlock->clipplane[Index][2];
2516 pPlane[3] = This->stateBlock->clipplane[Index][3];
2517 return WINED3D_OK;
2520 /*****
2521 * Get / Set Clip Plane Status
2522 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2523 *****/
2524 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2525 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2526 FIXME("(%p) : stub\n", This);
2527 if (NULL == pClipStatus) {
2528 return WINED3DERR_INVALIDCALL;
2530 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2531 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2532 return WINED3D_OK;
2535 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2537 FIXME("(%p) : stub\n", This);
2538 if (NULL == pClipStatus) {
2539 return WINED3DERR_INVALIDCALL;
2541 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2542 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2543 return WINED3D_OK;
2546 /*****
2547 * Get / Set Material
2548 *****/
2549 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2552 This->updateStateBlock->changed.material = TRUE;
2553 This->updateStateBlock->set.material = TRUE;
2554 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2556 /* Handle recording of state blocks */
2557 if (This->isRecordingState) {
2558 TRACE("Recording... not performing anything\n");
2559 return WINED3D_OK;
2562 ENTER_GL();
2563 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2564 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2565 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2566 pMaterial->Ambient.b, pMaterial->Ambient.a);
2567 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2568 pMaterial->Specular.b, pMaterial->Specular.a);
2569 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2570 pMaterial->Emissive.b, pMaterial->Emissive.a);
2571 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2573 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2574 checkGLcall("glMaterialfv(GL_AMBIENT)");
2575 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2576 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2578 /* Only change material color if specular is enabled, otherwise it is set to black */
2579 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2580 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2581 checkGLcall("glMaterialfv(GL_SPECULAR");
2582 } else {
2583 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2584 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2585 checkGLcall("glMaterialfv(GL_SPECULAR");
2587 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2588 checkGLcall("glMaterialfv(GL_EMISSION)");
2589 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2590 checkGLcall("glMaterialf(GL_SHININESS");
2592 LEAVE_GL();
2593 return WINED3D_OK;
2596 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2598 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2599 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2600 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2601 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2602 pMaterial->Ambient.b, pMaterial->Ambient.a);
2603 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2604 pMaterial->Specular.b, pMaterial->Specular.a);
2605 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2606 pMaterial->Emissive.b, pMaterial->Emissive.a);
2607 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2609 return WINED3D_OK;
2612 /*****
2613 * Get / Set Indices
2614 *****/
2615 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2616 UINT BaseVertexIndex) {
2617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2618 IWineD3DIndexBuffer *oldIdxs;
2619 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2621 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2622 oldIdxs = This->updateStateBlock->pIndexData;
2624 This->updateStateBlock->changed.indices = TRUE;
2625 This->updateStateBlock->set.indices = TRUE;
2626 This->updateStateBlock->pIndexData = pIndexData;
2627 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2629 /* Handle recording of state blocks */
2630 if (This->isRecordingState) {
2631 TRACE("Recording... not performing anything\n");
2632 return WINED3D_OK;
2635 /* The base vertex index affects the stream sources, while
2636 * The index buffer is a seperate index buffer state
2638 if(BaseVertexIndex != oldBaseIndex) {
2639 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2641 if(oldIdxs != pIndexData) {
2642 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2644 return WINED3D_OK;
2647 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2650 *ppIndexData = This->stateBlock->pIndexData;
2652 /* up ref count on ppindexdata */
2653 if (*ppIndexData) {
2654 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2655 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2656 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2657 }else{
2658 TRACE("(%p) No index data set\n", This);
2660 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2662 return WINED3D_OK;
2665 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2666 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2668 TRACE("(%p)->(%d)\n", This, BaseIndex);
2670 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2671 TRACE("Application is setting the old value over, nothing to do\n");
2672 return WINED3D_OK;
2675 This->updateStateBlock->baseVertexIndex = BaseIndex;
2677 if (This->isRecordingState) {
2678 TRACE("Recording... not performing anything\n");
2679 return WINED3D_OK;
2681 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2682 return WINED3D_OK;
2685 /*****
2686 * Get / Set Viewports
2687 *****/
2688 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2691 TRACE("(%p)\n", This);
2692 This->updateStateBlock->changed.viewport = TRUE;
2693 This->updateStateBlock->set.viewport = TRUE;
2694 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2696 /* Handle recording of state blocks */
2697 if (This->isRecordingState) {
2698 TRACE("Recording... not performing anything\n");
2699 return WINED3D_OK;
2702 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2703 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2705 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2706 return WINED3D_OK;
2710 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2712 TRACE("(%p)\n", This);
2713 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2714 return WINED3D_OK;
2717 /*****
2718 * Get / Set Render States
2719 * TODO: Verify against dx9 definitions
2720 *****/
2721 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2724 DWORD oldValue = This->stateBlock->renderState[State];
2726 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2728 This->updateStateBlock->changed.renderState[State] = TRUE;
2729 This->updateStateBlock->set.renderState[State] = TRUE;
2730 This->updateStateBlock->renderState[State] = Value;
2732 /* Handle recording of state blocks */
2733 if (This->isRecordingState) {
2734 TRACE("Recording... not performing anything\n");
2735 return WINED3D_OK;
2738 /* Compared here and not before the assignment to allow proper stateblock recording */
2739 if(Value == oldValue) {
2740 TRACE("Application is setting the old value over, nothing to do\n");
2741 } else {
2742 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2745 return WINED3D_OK;
2748 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2750 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2751 *pValue = This->stateBlock->renderState[State];
2752 return WINED3D_OK;
2755 /*****
2756 * Get / Set Sampler States
2757 * TODO: Verify against dx9 definitions
2758 *****/
2760 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2762 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2765 * SetSampler is designed to allow for more than the standard up to 8 textures
2766 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2767 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2769 * http://developer.nvidia.com/object/General_FAQ.html#t6
2771 * There are two new settings for GForce
2772 * the sampler one:
2773 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2774 * and the texture one:
2775 * GL_MAX_TEXTURE_COORDS_ARB.
2776 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2777 ******************/
2779 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2780 debug_d3dsamplerstate(Type), Type, Value);
2781 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2782 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2783 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2785 /* Handle recording of state blocks */
2786 if (This->isRecordingState) {
2787 TRACE("Recording... not performing anything\n");
2788 return WINED3D_OK;
2791 if(oldValue == Value) {
2792 TRACE("Application is setting the old value over, nothing to do\n");
2793 return WINED3D_OK;
2796 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2798 return WINED3D_OK;
2801 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2803 *Value = This->stateBlock->samplerState[Sampler][Type];
2804 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2806 return WINED3D_OK;
2809 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2812 This->updateStateBlock->set.scissorRect = TRUE;
2813 This->updateStateBlock->changed.scissorRect = TRUE;
2814 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2815 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2816 return WINED3D_OK;
2818 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2820 if(This->isRecordingState) {
2821 TRACE("Recording... not performing anything\n");
2822 return WINED3D_OK;
2825 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2827 return WINED3D_OK;
2830 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2833 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2834 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2835 return WINED3D_OK;
2838 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2840 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2842 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2844 This->updateStateBlock->vertexDecl = pDecl;
2845 This->updateStateBlock->changed.vertexDecl = TRUE;
2846 This->updateStateBlock->set.vertexDecl = TRUE;
2848 if (This->isRecordingState) {
2849 TRACE("Recording... not performing anything\n");
2850 return WINED3D_OK;
2851 } else if(pDecl == oldDecl) {
2852 /* Checked after the assignment to allow proper stateblock recording */
2853 TRACE("Application is setting the old declaration over, nothing to do\n");
2854 return WINED3D_OK;
2857 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2858 return WINED3D_OK;
2861 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2864 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2866 *ppDecl = This->stateBlock->vertexDecl;
2867 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2868 return WINED3D_OK;
2871 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2873 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2875 This->updateStateBlock->vertexShader = pShader;
2876 This->updateStateBlock->changed.vertexShader = TRUE;
2877 This->updateStateBlock->set.vertexShader = TRUE;
2879 if (This->isRecordingState) {
2880 TRACE("Recording... not performing anything\n");
2881 return WINED3D_OK;
2882 } else if(oldShader == pShader) {
2883 /* Checked here to allow proper stateblock recording */
2884 TRACE("App is setting the old shader over, nothing to do\n");
2885 return WINED3D_OK;
2888 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2890 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2892 return WINED3D_OK;
2895 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2898 if (NULL == ppShader) {
2899 return WINED3DERR_INVALIDCALL;
2901 *ppShader = This->stateBlock->vertexShader;
2902 if( NULL != *ppShader)
2903 IWineD3DVertexShader_AddRef(*ppShader);
2905 TRACE("(%p) : returning %p\n", This, *ppShader);
2906 return WINED3D_OK;
2909 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2910 IWineD3DDevice *iface,
2911 UINT start,
2912 CONST BOOL *srcData,
2913 UINT count) {
2915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2916 int i, cnt = min(count, MAX_CONST_B - start);
2918 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2919 iface, srcData, start, count);
2921 if (srcData == NULL || cnt < 0)
2922 return WINED3DERR_INVALIDCALL;
2924 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2925 for (i = 0; i < cnt; i++)
2926 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2928 for (i = start; i < cnt + start; ++i) {
2929 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
2930 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
2933 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2935 return WINED3D_OK;
2938 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2939 IWineD3DDevice *iface,
2940 UINT start,
2941 BOOL *dstData,
2942 UINT count) {
2944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2945 int cnt = min(count, MAX_CONST_B - start);
2947 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2948 iface, dstData, start, count);
2950 if (dstData == NULL || cnt < 0)
2951 return WINED3DERR_INVALIDCALL;
2953 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2954 return WINED3D_OK;
2957 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2958 IWineD3DDevice *iface,
2959 UINT start,
2960 CONST int *srcData,
2961 UINT count) {
2963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2964 int i, cnt = min(count, MAX_CONST_I - start);
2966 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2967 iface, srcData, start, count);
2969 if (srcData == NULL || cnt < 0)
2970 return WINED3DERR_INVALIDCALL;
2972 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2973 for (i = 0; i < cnt; i++)
2974 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2975 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2977 for (i = start; i < cnt + start; ++i) {
2978 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
2979 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
2982 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2984 return WINED3D_OK;
2987 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2988 IWineD3DDevice *iface,
2989 UINT start,
2990 int *dstData,
2991 UINT count) {
2993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2994 int cnt = min(count, MAX_CONST_I - start);
2996 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2997 iface, dstData, start, count);
2999 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3000 return WINED3DERR_INVALIDCALL;
3002 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3003 return WINED3D_OK;
3006 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3007 IWineD3DDevice *iface,
3008 UINT start,
3009 CONST float *srcData,
3010 UINT count) {
3012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3013 int i;
3015 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3016 iface, srcData, start, count);
3018 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3019 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3020 return WINED3DERR_INVALIDCALL;
3022 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3023 if(TRACE_ON(d3d)) {
3024 for (i = 0; i < count; i++)
3025 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3026 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3029 for (i = start; i < count + start; ++i) {
3030 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3031 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3032 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3033 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3034 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3036 ptr->idx[ptr->count++] = i;
3037 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3039 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3042 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3044 return WINED3D_OK;
3047 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3048 IWineD3DDevice *iface,
3049 UINT start,
3050 float *dstData,
3051 UINT count) {
3053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3054 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3056 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3057 iface, dstData, start, count);
3059 if (dstData == NULL || cnt < 0)
3060 return WINED3DERR_INVALIDCALL;
3062 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3063 return WINED3D_OK;
3066 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3067 DWORD i;
3068 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3069 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3073 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3074 DWORD i, tex;
3075 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3076 * it is never called.
3078 * Rules are:
3079 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3080 * that would be really messy and require shader recompilation
3081 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3082 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3083 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3084 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3086 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3087 if(This->oneToOneTexUnitMap) {
3088 TRACE("Not touching 1:1 map\n");
3089 return;
3091 TRACE("Restoring 1:1 texture unit mapping\n");
3092 /* Restore a 1:1 mapping */
3093 for(i = 0; i < MAX_SAMPLERS; i++) {
3094 if(This->texUnitMap[i] != i) {
3095 This->texUnitMap[i] = i;
3096 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3097 markTextureStagesDirty(This, i);
3100 This->oneToOneTexUnitMap = TRUE;
3101 return;
3102 } else {
3103 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3104 * First, see if we can succeed at all
3106 tex = 0;
3107 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3108 if(This->stateBlock->textures[i] == NULL) tex++;
3111 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3112 FIXME("Too many bound textures to support the combiner settings\n");
3113 return;
3116 /* Now work out the mapping */
3117 tex = 0;
3118 This->oneToOneTexUnitMap = FALSE;
3119 WARN("Non 1:1 mapping UNTESTED!\n");
3120 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3121 /* Skip NULL textures */
3122 if (!This->stateBlock->textures[i]) {
3123 /* Map to -1, so the check below doesn't fail if a non-NULL
3124 * texture is set on this stage */
3125 TRACE("Mapping texture stage %d to -1\n", i);
3126 This->texUnitMap[i] = -1;
3128 continue;
3131 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3132 if(This->texUnitMap[i] != tex) {
3133 This->texUnitMap[i] = tex;
3134 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3135 markTextureStagesDirty(This, i);
3138 ++tex;
3143 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3145 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3146 This->updateStateBlock->pixelShader = pShader;
3147 This->updateStateBlock->changed.pixelShader = TRUE;
3148 This->updateStateBlock->set.pixelShader = TRUE;
3150 /* Handle recording of state blocks */
3151 if (This->isRecordingState) {
3152 TRACE("Recording... not performing anything\n");
3155 if (This->isRecordingState) {
3156 TRACE("Recording... not performing anything\n");
3157 return WINED3D_OK;
3160 if(pShader == oldShader) {
3161 TRACE("App is setting the old pixel shader over, nothing to do\n");
3162 return WINED3D_OK;
3165 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3166 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3168 /* Rebuild the texture unit mapping if nvrc's are supported */
3169 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3170 IWineD3DDeviceImpl_FindTexUnitMap(This);
3173 return WINED3D_OK;
3176 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3179 if (NULL == ppShader) {
3180 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3181 return WINED3DERR_INVALIDCALL;
3184 *ppShader = This->stateBlock->pixelShader;
3185 if (NULL != *ppShader) {
3186 IWineD3DPixelShader_AddRef(*ppShader);
3188 TRACE("(%p) : returning %p\n", This, *ppShader);
3189 return WINED3D_OK;
3192 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3193 IWineD3DDevice *iface,
3194 UINT start,
3195 CONST BOOL *srcData,
3196 UINT count) {
3198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3199 int i, cnt = min(count, MAX_CONST_B - start);
3201 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3202 iface, srcData, start, count);
3204 if (srcData == NULL || cnt < 0)
3205 return WINED3DERR_INVALIDCALL;
3207 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3208 for (i = 0; i < cnt; i++)
3209 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3211 for (i = start; i < cnt + start; ++i) {
3212 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3213 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3216 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3218 return WINED3D_OK;
3221 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3222 IWineD3DDevice *iface,
3223 UINT start,
3224 BOOL *dstData,
3225 UINT count) {
3227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3228 int cnt = min(count, MAX_CONST_B - start);
3230 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3231 iface, dstData, start, count);
3233 if (dstData == NULL || cnt < 0)
3234 return WINED3DERR_INVALIDCALL;
3236 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3237 return WINED3D_OK;
3240 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3241 IWineD3DDevice *iface,
3242 UINT start,
3243 CONST int *srcData,
3244 UINT count) {
3246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3247 int i, cnt = min(count, MAX_CONST_I - start);
3249 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3250 iface, srcData, start, count);
3252 if (srcData == NULL || cnt < 0)
3253 return WINED3DERR_INVALIDCALL;
3255 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3256 for (i = 0; i < cnt; i++)
3257 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3258 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3260 for (i = start; i < cnt + start; ++i) {
3261 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3262 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3265 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3267 return WINED3D_OK;
3270 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3271 IWineD3DDevice *iface,
3272 UINT start,
3273 int *dstData,
3274 UINT count) {
3276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3277 int cnt = min(count, MAX_CONST_I - start);
3279 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3280 iface, dstData, start, count);
3282 if (dstData == NULL || cnt < 0)
3283 return WINED3DERR_INVALIDCALL;
3285 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3286 return WINED3D_OK;
3289 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3290 IWineD3DDevice *iface,
3291 UINT start,
3292 CONST float *srcData,
3293 UINT count) {
3295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3296 int i;
3298 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3299 iface, srcData, start, count);
3301 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3302 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3303 return WINED3DERR_INVALIDCALL;
3305 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3306 if(TRACE_ON(d3d)) {
3307 for (i = 0; i < count; i++)
3308 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3309 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3312 for (i = start; i < count + start; ++i) {
3313 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3314 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3315 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3316 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3317 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3319 ptr->idx[ptr->count++] = i;
3320 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3322 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3325 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3327 return WINED3D_OK;
3330 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3331 IWineD3DDevice *iface,
3332 UINT start,
3333 float *dstData,
3334 UINT count) {
3336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3337 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3339 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3340 iface, dstData, start, count);
3342 if (dstData == NULL || cnt < 0)
3343 return WINED3DERR_INVALIDCALL;
3345 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3346 return WINED3D_OK;
3349 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3350 static HRESULT
3351 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3352 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3353 unsigned int i;
3354 DWORD DestFVF = dest->fvf;
3355 WINED3DVIEWPORT vp;
3356 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3357 BOOL doClip;
3358 int numTextures;
3360 if (SrcFVF & WINED3DFVF_NORMAL) {
3361 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3364 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3365 ERR("Source has no position mask\n");
3366 return WINED3DERR_INVALIDCALL;
3369 /* We might access VBOs from this code, so hold the lock */
3370 ENTER_GL();
3372 if (dest->resource.allocatedMemory == NULL) {
3373 /* This may happen if we do direct locking into a vbo. Unlikely,
3374 * but theoretically possible(ddraw processvertices test)
3376 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3377 if(!dest->resource.allocatedMemory) {
3378 LEAVE_GL();
3379 ERR("Out of memory\n");
3380 return E_OUTOFMEMORY;
3382 if(dest->vbo) {
3383 void *src;
3384 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3385 checkGLcall("glBindBufferARB");
3386 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3387 if(src) {
3388 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3390 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3391 checkGLcall("glUnmapBufferARB");
3395 /* Get a pointer into the destination vbo(create one if none exists) and
3396 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3398 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3399 CreateVBO(dest);
3402 if(dest->vbo) {
3403 dest_conv_addr = HeapAlloc(GetProcessHeap(), 0, dwCount * get_flexible_vertex_size(DestFVF));
3404 if(!dest_conv_addr) {
3405 ERR("Out of memory\n");
3406 /* Continue without storing converted vertices */
3408 dest_conv = dest_conv_addr;
3411 /* Should I clip?
3412 * a) WINED3DRS_CLIPPING is enabled
3413 * b) WINED3DVOP_CLIP is passed
3415 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3416 static BOOL warned = FALSE;
3418 * The clipping code is not quite correct. Some things need
3419 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3420 * so disable clipping for now.
3421 * (The graphics in Half-Life are broken, and my processvertices
3422 * test crashes with IDirect3DDevice3)
3423 doClip = TRUE;
3425 doClip = FALSE;
3426 if(!warned) {
3427 warned = TRUE;
3428 FIXME("Clipping is broken and disabled for now\n");
3430 } else doClip = FALSE;
3431 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3433 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3434 WINED3DTS_VIEW,
3435 &view_mat);
3436 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3437 WINED3DTS_PROJECTION,
3438 &proj_mat);
3439 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3440 WINED3DTS_WORLDMATRIX(0),
3441 &world_mat);
3443 TRACE("View mat:\n");
3444 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);
3445 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);
3446 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);
3447 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);
3449 TRACE("Proj mat:\n");
3450 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);
3451 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);
3452 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);
3453 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);
3455 TRACE("World mat:\n");
3456 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);
3457 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);
3458 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);
3459 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);
3461 /* Get the viewport */
3462 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3463 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3464 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3466 multiply_matrix(&mat,&view_mat,&world_mat);
3467 multiply_matrix(&mat,&proj_mat,&mat);
3469 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3471 for (i = 0; i < dwCount; i+= 1) {
3472 unsigned int tex_index;
3474 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3475 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3476 /* The position first */
3477 float *p =
3478 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3479 float x, y, z, rhw;
3480 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3482 /* Multiplication with world, view and projection matrix */
3483 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);
3484 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);
3485 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);
3486 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);
3488 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3490 /* WARNING: The following things are taken from d3d7 and were not yet checked
3491 * against d3d8 or d3d9!
3494 /* Clipping conditions: From
3495 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3497 * A vertex is clipped if it does not match the following requirements
3498 * -rhw < x <= rhw
3499 * -rhw < y <= rhw
3500 * 0 < z <= rhw
3501 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3503 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3504 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3508 if( !doClip ||
3509 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3510 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3511 ( rhw > eps ) ) ) {
3513 /* "Normal" viewport transformation (not clipped)
3514 * 1) The values are divided by rhw
3515 * 2) The y axis is negative, so multiply it with -1
3516 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3517 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3518 * 4) Multiply x with Width/2 and add Width/2
3519 * 5) The same for the height
3520 * 6) Add the viewpoint X and Y to the 2D coordinates and
3521 * The minimum Z value to z
3522 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3524 * Well, basically it's simply a linear transformation into viewport
3525 * coordinates
3528 x /= rhw;
3529 y /= rhw;
3530 z /= rhw;
3532 y *= -1;
3534 x *= vp.Width / 2;
3535 y *= vp.Height / 2;
3536 z *= vp.MaxZ - vp.MinZ;
3538 x += vp.Width / 2 + vp.X;
3539 y += vp.Height / 2 + vp.Y;
3540 z += vp.MinZ;
3542 rhw = 1 / rhw;
3543 } else {
3544 /* That vertex got clipped
3545 * Contrary to OpenGL it is not dropped completely, it just
3546 * undergoes a different calculation.
3548 TRACE("Vertex got clipped\n");
3549 x += rhw;
3550 y += rhw;
3552 x /= 2;
3553 y /= 2;
3555 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3556 * outside of the main vertex buffer memory. That needs some more
3557 * investigation...
3561 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3564 ( (float *) dest_ptr)[0] = x;
3565 ( (float *) dest_ptr)[1] = y;
3566 ( (float *) dest_ptr)[2] = z;
3567 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3569 dest_ptr += 3 * sizeof(float);
3571 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3572 dest_ptr += sizeof(float);
3575 if(dest_conv) {
3576 float w = 1 / rhw;
3577 ( (float *) dest_conv)[0] = x * w;
3578 ( (float *) dest_conv)[1] = y * w;
3579 ( (float *) dest_conv)[2] = z * w;
3580 ( (float *) dest_conv)[3] = w;
3582 dest_conv += 3 * sizeof(float);
3584 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3585 dest_conv += sizeof(float);
3589 if (DestFVF & WINED3DFVF_PSIZE) {
3590 dest_ptr += sizeof(DWORD);
3591 if(dest_conv) dest_conv += sizeof(DWORD);
3593 if (DestFVF & WINED3DFVF_NORMAL) {
3594 float *normal =
3595 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3596 /* AFAIK this should go into the lighting information */
3597 FIXME("Didn't expect the destination to have a normal\n");
3598 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3599 if(dest_conv) {
3600 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3604 if (DestFVF & WINED3DFVF_DIFFUSE) {
3605 DWORD *color_d =
3606 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3607 if(!color_d) {
3608 static BOOL warned = FALSE;
3610 if(!warned) {
3611 ERR("No diffuse color in source, but destination has one\n");
3612 warned = TRUE;
3615 *( (DWORD *) dest_ptr) = 0xffffffff;
3616 dest_ptr += sizeof(DWORD);
3618 if(dest_conv) {
3619 *( (DWORD *) dest_conv) = 0xffffffff;
3620 dest_conv += sizeof(DWORD);
3623 else {
3624 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3625 if(dest_conv) {
3626 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3627 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3628 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3629 dest_conv += sizeof(DWORD);
3634 if (DestFVF & WINED3DFVF_SPECULAR) {
3635 /* What's the color value in the feedback buffer? */
3636 DWORD *color_s =
3637 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3638 if(!color_s) {
3639 static BOOL warned = FALSE;
3641 if(!warned) {
3642 ERR("No specular color in source, but destination has one\n");
3643 warned = TRUE;
3646 *( (DWORD *) dest_ptr) = 0xFF000000;
3647 dest_ptr += sizeof(DWORD);
3649 if(dest_conv) {
3650 *( (DWORD *) dest_conv) = 0xFF000000;
3651 dest_conv += sizeof(DWORD);
3654 else {
3655 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3656 if(dest_conv) {
3657 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3658 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3659 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3660 dest_conv += sizeof(DWORD);
3665 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3666 float *tex_coord =
3667 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3668 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3669 if(!tex_coord) {
3670 ERR("No source texture, but destination requests one\n");
3671 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3672 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3674 else {
3675 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3676 if(dest_conv) {
3677 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3683 if(dest_conv) {
3684 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3685 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3686 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3687 dwCount * get_flexible_vertex_size(DestFVF),
3688 dest_conv_addr));
3689 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3690 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3693 LEAVE_GL();
3695 return WINED3D_OK;
3697 #undef copy_and_next
3699 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
3700 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3701 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
3702 WineDirect3DVertexStridedData strided;
3703 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3705 if (!SrcImpl) {
3706 WARN("NULL source vertex buffer\n");
3707 return WINED3DERR_INVALIDCALL;
3710 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3711 * and this call is quite performance critical, so don't call needlessly
3713 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3714 ENTER_GL();
3715 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3716 LEAVE_GL();
3719 /* We don't need the source vbo because this buffer is only used as
3720 * a source for ProcessVertices. Avoid wasting resources by converting the
3721 * buffer and loading the VBO
3723 if(SrcImpl->vbo) {
3724 TRACE("Releasing the source vbo, it won't be needed\n");
3726 if(!SrcImpl->resource.allocatedMemory) {
3727 /* Rescue the data from the buffer */
3728 void *src;
3729 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
3730 if(!SrcImpl->resource.allocatedMemory) {
3731 ERR("Out of memory\n");
3732 return E_OUTOFMEMORY;
3735 ENTER_GL();
3736 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
3737 checkGLcall("glBindBufferARB");
3739 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3740 if(src) {
3741 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
3744 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3745 checkGLcall("glUnmapBufferARB");
3746 } else {
3747 ENTER_GL();
3750 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
3751 checkGLcall("glBindBufferARB");
3752 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
3753 checkGLcall("glDeleteBuffersARB");
3754 LEAVE_GL();
3756 SrcImpl->vbo = 0;
3759 memset(&strided, 0, sizeof(strided));
3760 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0, 0);
3762 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3765 /*****
3766 * Get / Set Texture Stage States
3767 * TODO: Verify against dx9 definitions
3768 *****/
3769 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3771 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3773 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3775 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3777 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3778 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3779 This->updateStateBlock->textureState[Stage][Type] = Value;
3781 if (This->isRecordingState) {
3782 TRACE("Recording... not performing anything\n");
3783 return WINED3D_OK;
3786 /* Checked after the assignments to allow proper stateblock recording */
3787 if(oldValue == Value) {
3788 TRACE("App is setting the old value over, nothing to do\n");
3789 return WINED3D_OK;
3792 if(Stage > This->stateBlock->lowest_disabled_stage &&
3793 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3794 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3795 * Changes in other states are important on disabled stages too
3797 return WINED3D_OK;
3800 if(Type == WINED3DTSS_COLOROP) {
3801 int i;
3803 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3804 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3805 * they have to be disabled
3807 * The current stage is dirtified below.
3809 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3810 TRACE("Additionally dirtifying stage %d\n", i);
3811 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3813 This->stateBlock->lowest_disabled_stage = Stage;
3814 TRACE("New lowest disabled: %d\n", Stage);
3815 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3816 /* Previously disabled stage enabled. Stages above it may need enabling
3817 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3818 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3820 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3823 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3824 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3825 break;
3827 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3828 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3830 This->stateBlock->lowest_disabled_stage = i;
3831 TRACE("New lowest disabled: %d\n", i);
3833 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3834 /* TODO: Built a stage -> texture unit mapping for register combiners */
3838 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3840 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3841 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3842 * will call FindTexUnitMap too.
3844 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3845 IWineD3DDeviceImpl_FindTexUnitMap(This);
3847 return WINED3D_OK;
3850 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3852 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3853 *pValue = This->updateStateBlock->textureState[Stage][Type];
3854 return WINED3D_OK;
3857 /*****
3858 * Get / Set Texture
3859 *****/
3860 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
3862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3863 IWineD3DBaseTexture *oldTexture;
3865 oldTexture = This->updateStateBlock->textures[Stage];
3866 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
3868 #if 0 /* TODO: check so vertex textures */
3869 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
3870 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
3871 return WINED3D_OK;
3873 #endif
3875 if(pTexture != NULL) {
3876 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
3878 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
3879 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
3880 return WINED3DERR_INVALIDCALL;
3882 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
3885 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
3886 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
3888 This->updateStateBlock->set.textures[Stage] = TRUE;
3889 This->updateStateBlock->changed.textures[Stage] = TRUE;
3890 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
3891 This->updateStateBlock->textures[Stage] = pTexture;
3893 /* Handle recording of state blocks */
3894 if (This->isRecordingState) {
3895 TRACE("Recording... not performing anything\n");
3896 return WINED3D_OK;
3899 if(oldTexture == pTexture) {
3900 TRACE("App is setting the same texture again, nothing to do\n");
3901 return WINED3D_OK;
3904 /** NOTE: MSDN says that setTexture increases the reference count,
3905 * and the the application nust set the texture back to null (or have a leaky application),
3906 * This means we should pass the refcount up to the parent
3907 *******************************/
3908 if (NULL != This->updateStateBlock->textures[Stage]) {
3909 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
3910 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
3912 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
3913 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
3914 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
3915 * so the COLOROP and ALPHAOP have to be dirtified.
3917 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3918 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3920 if(bindCount == 1) {
3921 new->baseTexture.sampler = Stage;
3923 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
3927 if (NULL != oldTexture) {
3928 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
3929 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
3931 IWineD3DBaseTexture_Release(oldTexture);
3932 if(pTexture == NULL && Stage < MAX_TEXTURES) {
3933 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3934 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3937 if(bindCount && old->baseTexture.sampler == Stage) {
3938 int i;
3939 /* Have to do a search for the other sampler(s) where the texture is bound to
3940 * Shouldn't happen as long as apps bind a texture only to one stage
3942 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
3943 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
3944 if(This->updateStateBlock->textures[i] == oldTexture) {
3945 old->baseTexture.sampler = i;
3946 break;
3952 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
3954 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
3955 * pixel shader is used
3957 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3958 IWineD3DDeviceImpl_FindTexUnitMap(This);
3961 return WINED3D_OK;
3964 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3966 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
3968 *ppTexture=This->stateBlock->textures[Stage];
3969 if (*ppTexture)
3970 IWineD3DBaseTexture_AddRef(*ppTexture);
3972 return WINED3D_OK;
3975 /*****
3976 * Get Back Buffer
3977 *****/
3978 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
3979 IWineD3DSurface **ppBackBuffer) {
3980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3981 IWineD3DSwapChain *swapChain;
3982 HRESULT hr;
3984 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
3986 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
3987 if (hr == WINED3D_OK) {
3988 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
3989 IWineD3DSwapChain_Release(swapChain);
3990 } else {
3991 *ppBackBuffer = NULL;
3993 return hr;
3996 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
3997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3998 WARN("(%p) : stub, calling idirect3d for now\n", This);
3999 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4002 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4004 IWineD3DSwapChain *swapChain;
4005 HRESULT hr;
4007 if(iSwapChain > 0) {
4008 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4009 if (hr == WINED3D_OK) {
4010 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4011 IWineD3DSwapChain_Release(swapChain);
4012 } else {
4013 FIXME("(%p) Error getting display mode\n", This);
4015 } else {
4016 /* Don't read the real display mode,
4017 but return the stored mode instead. X11 can't change the color
4018 depth, and some apps are pretty angry if they SetDisplayMode from
4019 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4021 Also don't relay to the swapchain because with ddraw it's possible
4022 that there isn't a swapchain at all */
4023 pMode->Width = This->ddraw_width;
4024 pMode->Height = This->ddraw_height;
4025 pMode->Format = This->ddraw_format;
4026 pMode->RefreshRate = 0;
4027 hr = WINED3D_OK;
4030 return hr;
4033 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4035 TRACE("(%p)->(%p)\n", This, hWnd);
4037 if(This->ddraw_fullscreen) {
4038 if(This->ddraw_window && This->ddraw_window != hWnd) {
4039 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4041 if(hWnd && This->ddraw_window != hWnd) {
4042 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4046 This->ddraw_window = hWnd;
4047 return WINED3D_OK;
4050 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4052 TRACE("(%p)->(%p)\n", This, hWnd);
4054 *hWnd = This->ddraw_window;
4055 return WINED3D_OK;
4058 /*****
4059 * Stateblock related functions
4060 *****/
4062 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4064 IWineD3DStateBlockImpl *object;
4065 HRESULT temp_result;
4066 int i;
4068 TRACE("(%p)\n", This);
4070 if (This->isRecordingState) {
4071 return WINED3DERR_INVALIDCALL;
4074 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4075 if (NULL == object ) {
4076 FIXME("(%p)Error allocating memory for stateblock\n", This);
4077 return E_OUTOFMEMORY;
4079 TRACE("(%p) created object %p\n", This, object);
4080 object->wineD3DDevice= This;
4081 /** FIXME: object->parent = parent; **/
4082 object->parent = NULL;
4083 object->blockType = WINED3DSBT_ALL;
4084 object->ref = 1;
4085 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4087 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4088 list_init(&object->lightMap[i]);
4091 temp_result = allocate_shader_constants(object);
4092 if (WINED3D_OK != temp_result)
4093 return temp_result;
4095 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4096 This->updateStateBlock = object;
4097 This->isRecordingState = TRUE;
4099 TRACE("(%p) recording stateblock %p\n",This , object);
4100 return WINED3D_OK;
4103 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4106 if (!This->isRecordingState) {
4107 FIXME("(%p) not recording! returning error\n", This);
4108 *ppStateBlock = NULL;
4109 return WINED3DERR_INVALIDCALL;
4112 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4113 This->isRecordingState = FALSE;
4114 This->updateStateBlock = This->stateBlock;
4115 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4116 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4117 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4118 return WINED3D_OK;
4121 /*****
4122 * Scene related functions
4123 *****/
4124 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4125 /* At the moment we have no need for any functionality at the beginning
4126 of a scene */
4127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4128 TRACE("(%p)\n", This);
4130 if(This->inScene) {
4131 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4132 return WINED3DERR_INVALIDCALL;
4134 This->inScene = TRUE;
4135 return WINED3D_OK;
4138 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4140 TRACE("(%p)\n", This);
4142 if(!This->inScene) {
4143 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4144 return WINED3DERR_INVALIDCALL;
4147 ENTER_GL();
4148 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4149 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4151 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4152 glFlush();
4153 checkGLcall("glFlush");
4154 LEAVE_GL();
4156 This->inScene = FALSE;
4157 return WINED3D_OK;
4160 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4161 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4162 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4164 IWineD3DSwapChain *swapChain = NULL;
4165 int i;
4166 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4168 TRACE("(%p) Presenting the frame\n", This);
4170 for(i = 0 ; i < swapchains ; i ++) {
4172 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4173 TRACE("presentinng chain %d, %p\n", i, swapChain);
4174 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4175 IWineD3DSwapChain_Release(swapChain);
4178 return WINED3D_OK;
4181 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4182 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4184 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4186 GLbitfield glMask = 0;
4187 unsigned int i;
4188 CONST WINED3DRECT* curRect;
4190 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4191 Count, pRects, Flags, Z, Stencil);
4193 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4194 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4195 /* TODO: What about depth stencil buffers without stencil bits? */
4196 return WINED3DERR_INVALIDCALL;
4199 ENTER_GL();
4200 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4201 * and not the last active one.
4204 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4205 apply_fbo_state(iface);
4208 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
4210 glEnable(GL_SCISSOR_TEST);
4211 checkGLcall("glEnable GL_SCISSOR_TEST");
4212 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4213 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4215 if (Count > 0 && pRects) {
4216 curRect = pRects;
4217 } else {
4218 curRect = NULL;
4221 /* Only set the values up once, as they are not changing */
4222 if (Flags & WINED3DCLEAR_STENCIL) {
4223 glClearStencil(Stencil);
4224 checkGLcall("glClearStencil");
4225 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4226 glStencilMask(0xFFFFFFFF);
4229 if (Flags & WINED3DCLEAR_ZBUFFER) {
4230 glDepthMask(GL_TRUE);
4231 glClearDepth(Z);
4232 checkGLcall("glClearDepth");
4233 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4234 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4237 if (Flags & WINED3DCLEAR_TARGET) {
4238 TRACE("Clearing screen with glClear to color %x\n", Color);
4239 glClearColor(D3DCOLOR_R(Color),
4240 D3DCOLOR_G(Color),
4241 D3DCOLOR_B(Color),
4242 D3DCOLOR_A(Color));
4243 checkGLcall("glClearColor");
4245 /* Clear ALL colors! */
4246 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4247 glMask = glMask | GL_COLOR_BUFFER_BIT;
4250 if (!curRect) {
4251 /* In drawable flag is set below */
4253 glScissor(This->stateBlock->viewport.X,
4254 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4255 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4256 This->stateBlock->viewport.Width,
4257 This->stateBlock->viewport.Height);
4258 checkGLcall("glScissor");
4259 glClear(glMask);
4260 checkGLcall("glClear");
4261 } else {
4262 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4263 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4265 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4266 curRect[0].x2 < target->currentDesc.Width ||
4267 curRect[0].y2 < target->currentDesc.Height) {
4268 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4269 blt_to_drawable(This, target);
4273 /* Now process each rect in turn */
4274 for (i = 0; i < Count; i++) {
4275 /* Note gl uses lower left, width/height */
4276 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4277 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4278 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4279 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4281 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4282 * The rectangle is not cleared, no error is returned, but further rectanlges are
4283 * still cleared if they are valid
4285 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4286 TRACE("Rectangle with negative dimensions, ignoring\n");
4287 continue;
4290 if(This->render_offscreen) {
4291 glScissor(curRect[i].x1, curRect[i].y1,
4292 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4293 } else {
4294 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4295 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4297 checkGLcall("glScissor");
4299 glClear(glMask);
4300 checkGLcall("glClear");
4304 /* Restore the old values (why..?) */
4305 if (Flags & WINED3DCLEAR_STENCIL) {
4306 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4308 if (Flags & WINED3DCLEAR_TARGET) {
4309 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4310 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4311 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4312 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4313 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4316 LEAVE_GL();
4318 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4319 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4321 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4322 target->Flags |= SFLAG_INTEXTURE;
4323 target->Flags &= ~SFLAG_INSYSMEM;
4324 } else {
4325 target->Flags |= SFLAG_INDRAWABLE;
4326 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4328 return WINED3D_OK;
4331 /*****
4332 * Drawing functions
4333 *****/
4334 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4335 UINT PrimitiveCount) {
4337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4339 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4340 debug_d3dprimitivetype(PrimitiveType),
4341 StartVertex, PrimitiveCount);
4343 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4344 if(This->stateBlock->streamIsUP) {
4345 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4346 This->stateBlock->streamIsUP = FALSE;
4349 if(This->stateBlock->loadBaseVertexIndex != 0) {
4350 This->stateBlock->loadBaseVertexIndex = 0;
4351 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4353 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4354 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4355 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4356 return WINED3D_OK;
4359 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4360 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4361 WINED3DPRIMITIVETYPE PrimitiveType,
4362 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4365 UINT idxStride = 2;
4366 IWineD3DIndexBuffer *pIB;
4367 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4368 GLuint vbo;
4370 if(This->stateBlock->streamIsUP) {
4371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4372 This->stateBlock->streamIsUP = FALSE;
4374 pIB = This->stateBlock->pIndexData;
4375 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4377 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4378 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4379 minIndex, NumVertices, startIndex, primCount);
4381 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4382 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4383 idxStride = 2;
4384 } else {
4385 idxStride = 4;
4388 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4389 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4390 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4393 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4394 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4396 return WINED3D_OK;
4399 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4400 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4401 UINT VertexStreamZeroStride) {
4402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4404 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4405 debug_d3dprimitivetype(PrimitiveType),
4406 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4408 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4409 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4410 This->stateBlock->streamOffset[0] = 0;
4411 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4412 This->stateBlock->streamIsUP = TRUE;
4413 This->stateBlock->loadBaseVertexIndex = 0;
4415 /* TODO: Only mark dirty if drawing from a different UP address */
4416 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4418 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4419 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4421 /* MSDN specifies stream zero settings must be set to NULL */
4422 This->stateBlock->streamStride[0] = 0;
4423 This->stateBlock->streamSource[0] = NULL;
4425 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4426 * the new stream sources or use UP drawing again
4428 return WINED3D_OK;
4431 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4432 UINT MinVertexIndex, UINT NumVertices,
4433 UINT PrimitiveCount, CONST void* pIndexData,
4434 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4435 UINT VertexStreamZeroStride) {
4436 int idxStride;
4437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4439 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4440 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4441 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4442 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4444 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4445 idxStride = 2;
4446 } else {
4447 idxStride = 4;
4450 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4451 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4452 This->stateBlock->streamIsUP = TRUE;
4453 This->stateBlock->streamOffset[0] = 0;
4454 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4456 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4457 This->stateBlock->baseVertexIndex = 0;
4458 This->stateBlock->loadBaseVertexIndex = 0;
4459 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4460 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4461 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4463 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4465 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4466 This->stateBlock->streamSource[0] = NULL;
4467 This->stateBlock->streamStride[0] = 0;
4468 This->stateBlock->pIndexData = NULL;
4469 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4470 * SetStreamSource to specify a vertex buffer
4473 return WINED3D_OK;
4476 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4479 /* Mark the state dirty until we have nicer tracking
4480 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4481 * that value.
4483 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4484 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4485 This->stateBlock->baseVertexIndex = 0;
4486 This->up_strided = DrawPrimStrideData;
4487 This->stateBlock->streamIsUP = TRUE;
4488 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4489 This->up_strided = NULL;
4490 return WINED3D_OK;
4492 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4493 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4495 HRESULT hr = WINED3D_OK;
4496 WINED3DRESOURCETYPE sourceType;
4497 WINED3DRESOURCETYPE destinationType;
4498 int i ,levels;
4500 /* TODO: think about moving the code into IWineD3DBaseTexture */
4502 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4504 /* verify that the source and destination textures aren't NULL */
4505 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4506 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4507 This, pSourceTexture, pDestinationTexture);
4508 hr = WINED3DERR_INVALIDCALL;
4511 if (pSourceTexture == pDestinationTexture) {
4512 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4513 This, pSourceTexture, pDestinationTexture);
4514 hr = WINED3DERR_INVALIDCALL;
4516 /* Verify that the source and destination textures are the same type */
4517 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4518 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4520 if (sourceType != destinationType) {
4521 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4522 This);
4523 hr = WINED3DERR_INVALIDCALL;
4526 /* check that both textures have the identical numbers of levels */
4527 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4528 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4529 hr = WINED3DERR_INVALIDCALL;
4532 if (WINED3D_OK == hr) {
4534 /* Make sure that the destination texture is loaded */
4535 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4537 /* Update every surface level of the texture */
4538 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4540 switch (sourceType) {
4541 case WINED3DRTYPE_TEXTURE:
4543 IWineD3DSurface *srcSurface;
4544 IWineD3DSurface *destSurface;
4546 for (i = 0 ; i < levels ; ++i) {
4547 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4548 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4549 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4550 IWineD3DSurface_Release(srcSurface);
4551 IWineD3DSurface_Release(destSurface);
4552 if (WINED3D_OK != hr) {
4553 WARN("(%p) : Call to update surface failed\n", This);
4554 return hr;
4558 break;
4559 case WINED3DRTYPE_CUBETEXTURE:
4561 IWineD3DSurface *srcSurface;
4562 IWineD3DSurface *destSurface;
4563 WINED3DCUBEMAP_FACES faceType;
4565 for (i = 0 ; i < levels ; ++i) {
4566 /* Update each cube face */
4567 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4568 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4569 if (WINED3D_OK != hr) {
4570 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4571 } else {
4572 TRACE("Got srcSurface %p\n", srcSurface);
4574 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4575 if (WINED3D_OK != hr) {
4576 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4577 } else {
4578 TRACE("Got desrSurface %p\n", destSurface);
4580 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4581 IWineD3DSurface_Release(srcSurface);
4582 IWineD3DSurface_Release(destSurface);
4583 if (WINED3D_OK != hr) {
4584 WARN("(%p) : Call to update surface failed\n", This);
4585 return hr;
4590 break;
4591 #if 0 /* TODO: Add support for volume textures */
4592 case WINED3DRTYPE_VOLUMETEXTURE:
4594 IWineD3DVolume srcVolume = NULL;
4595 IWineD3DSurface destVolume = NULL;
4597 for (i = 0 ; i < levels ; ++i) {
4598 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4599 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4600 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4601 IWineD3DVolume_Release(srcSurface);
4602 IWineD3DVolume_Release(destSurface);
4603 if (WINED3D_OK != hr) {
4604 WARN("(%p) : Call to update volume failed\n", This);
4605 return hr;
4609 break;
4610 #endif
4611 default:
4612 FIXME("(%p) : Unsupported source and destination type\n", This);
4613 hr = WINED3DERR_INVALIDCALL;
4617 return hr;
4620 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4621 IWineD3DSwapChain *swapChain;
4622 HRESULT hr;
4623 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4624 if(hr == WINED3D_OK) {
4625 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4626 IWineD3DSwapChain_Release(swapChain);
4628 return hr;
4631 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4633 /* return a sensible default */
4634 *pNumPasses = 1;
4635 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4636 FIXME("(%p) : stub\n", This);
4637 return WINED3D_OK;
4640 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4642 int j;
4643 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4644 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4645 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4646 return WINED3DERR_INVALIDCALL;
4648 for (j = 0; j < 256; ++j) {
4649 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4650 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4651 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4652 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4654 TRACE("(%p) : returning\n", This);
4655 return WINED3D_OK;
4658 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4660 int j;
4661 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4662 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4663 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4664 return WINED3DERR_INVALIDCALL;
4666 for (j = 0; j < 256; ++j) {
4667 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4668 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4669 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4670 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4672 TRACE("(%p) : returning\n", This);
4673 return WINED3D_OK;
4676 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4678 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4679 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4680 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4681 return WINED3DERR_INVALIDCALL;
4683 /*TODO: stateblocks */
4684 This->currentPalette = PaletteNumber;
4685 TRACE("(%p) : returning\n", This);
4686 return WINED3D_OK;
4689 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4691 if (PaletteNumber == NULL) {
4692 WARN("(%p) : returning Invalid Call\n", This);
4693 return WINED3DERR_INVALIDCALL;
4695 /*TODO: stateblocks */
4696 *PaletteNumber = This->currentPalette;
4697 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4698 return WINED3D_OK;
4701 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4703 static BOOL showFixmes = TRUE;
4704 if (showFixmes) {
4705 FIXME("(%p) : stub\n", This);
4706 showFixmes = FALSE;
4709 This->softwareVertexProcessing = bSoftware;
4710 return WINED3D_OK;
4714 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4716 static BOOL showFixmes = TRUE;
4717 if (showFixmes) {
4718 FIXME("(%p) : stub\n", This);
4719 showFixmes = FALSE;
4721 return This->softwareVertexProcessing;
4725 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4727 IWineD3DSwapChain *swapChain;
4728 HRESULT hr;
4730 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4732 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4733 if(hr == WINED3D_OK){
4734 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4735 IWineD3DSwapChain_Release(swapChain);
4736 }else{
4737 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4739 return hr;
4743 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4745 static BOOL showfixmes = TRUE;
4746 if(nSegments != 0.0f) {
4747 if( showfixmes) {
4748 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4749 showfixmes = FALSE;
4752 return WINED3D_OK;
4755 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4757 static BOOL showfixmes = TRUE;
4758 if( showfixmes) {
4759 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4760 showfixmes = FALSE;
4762 return 0.0f;
4765 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4767 /** TODO: remove casts to IWineD3DSurfaceImpl
4768 * NOTE: move code to surface to accomplish this
4769 ****************************************/
4770 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4771 int srcWidth, srcHeight;
4772 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4773 WINED3DFORMAT destFormat, srcFormat;
4774 UINT destSize;
4775 int srcLeft, destLeft, destTop;
4776 WINED3DPOOL srcPool, destPool;
4777 int offset = 0;
4778 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4779 glDescriptor *glDescription = NULL;
4781 WINED3DSURFACE_DESC winedesc;
4783 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4784 memset(&winedesc, 0, sizeof(winedesc));
4785 winedesc.Width = &srcSurfaceWidth;
4786 winedesc.Height = &srcSurfaceHeight;
4787 winedesc.Pool = &srcPool;
4788 winedesc.Format = &srcFormat;
4790 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4792 winedesc.Width = &destSurfaceWidth;
4793 winedesc.Height = &destSurfaceHeight;
4794 winedesc.Pool = &destPool;
4795 winedesc.Format = &destFormat;
4796 winedesc.Size = &destSize;
4798 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4800 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4801 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4802 return WINED3DERR_INVALIDCALL;
4805 if (destFormat == WINED3DFMT_UNKNOWN) {
4806 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4807 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4809 /* Get the update surface description */
4810 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4813 ENTER_GL();
4815 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4817 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
4818 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4819 checkGLcall("glActiveTextureARB");
4822 /* Make sure the surface is loaded and up to date */
4823 IWineD3DSurface_PreLoad(pDestinationSurface);
4825 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4827 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4828 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4829 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
4830 srcLeft = pSourceRect ? pSourceRect->left : 0;
4831 destLeft = pDestPoint ? pDestPoint->x : 0;
4832 destTop = pDestPoint ? pDestPoint->y : 0;
4835 /* This function doesn't support compressed textures
4836 the pitch is just bytesPerPixel * width */
4837 if(srcWidth != srcSurfaceWidth || srcLeft ){
4838 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
4839 offset += srcLeft * pSrcSurface->bytesPerPixel;
4840 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4842 /* TODO DXT formats */
4844 if(pSourceRect != NULL && pSourceRect->top != 0){
4845 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
4847 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4848 ,This
4849 ,glDescription->level
4850 ,destLeft
4851 ,destTop
4852 ,srcWidth
4853 ,srcHeight
4854 ,glDescription->glFormat
4855 ,glDescription->glType
4856 ,IWineD3DSurface_GetData(pSourceSurface)
4859 /* Sanity check */
4860 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
4862 /* need to lock the surface to get the data */
4863 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
4866 /* TODO: Cube and volume support */
4867 if(rowoffset != 0){
4868 /* not a whole row so we have to do it a line at a time */
4869 int j;
4871 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
4872 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
4874 for(j = destTop ; j < (srcHeight + destTop) ; j++){
4876 glTexSubImage2D(glDescription->target
4877 ,glDescription->level
4878 ,destLeft
4880 ,srcWidth
4882 ,glDescription->glFormat
4883 ,glDescription->glType
4884 ,data /* could be quicker using */
4886 data += rowoffset;
4889 } else { /* Full width, so just write out the whole texture */
4891 if (WINED3DFMT_DXT1 == destFormat ||
4892 WINED3DFMT_DXT2 == destFormat ||
4893 WINED3DFMT_DXT3 == destFormat ||
4894 WINED3DFMT_DXT4 == destFormat ||
4895 WINED3DFMT_DXT5 == destFormat) {
4896 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
4897 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
4898 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
4899 FIXME("Updating part of a compressed texture is not supported at the moment\n");
4900 } if (destFormat != srcFormat) {
4901 FIXME("Updating mixed format compressed texture is not curretly support\n");
4902 } else {
4903 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
4904 glDescription->level,
4905 glDescription->glFormatInternal,
4906 srcWidth,
4907 srcHeight,
4909 destSize,
4910 IWineD3DSurface_GetData(pSourceSurface));
4912 } else {
4913 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
4917 } else {
4918 glTexSubImage2D(glDescription->target
4919 ,glDescription->level
4920 ,destLeft
4921 ,destTop
4922 ,srcWidth
4923 ,srcHeight
4924 ,glDescription->glFormat
4925 ,glDescription->glType
4926 ,IWineD3DSurface_GetData(pSourceSurface)
4930 checkGLcall("glTexSubImage2D");
4932 LEAVE_GL();
4934 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
4935 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
4936 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
4938 return WINED3D_OK;
4941 /* Implementation details at http://developer.nvidia.com/attach/6494
4943 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
4944 hmm.. no longer supported use
4945 OpenGL evaluators or tessellate surfaces within your application.
4948 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
4949 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
4950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4951 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
4952 FIXME("(%p) : Stub\n", This);
4953 return WINED3D_OK;
4957 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
4958 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
4959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4960 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
4961 FIXME("(%p) : Stub\n", This);
4962 return WINED3D_OK;
4965 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
4966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4967 TRACE("(%p) Handle(%d)\n", This, Handle);
4968 FIXME("(%p) : Stub\n", This);
4969 return WINED3D_OK;
4972 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
4973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4974 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
4975 WINEDDBLTFX BltFx;
4976 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
4978 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
4979 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
4980 return WINED3DERR_INVALIDCALL;
4983 /* Just forward this to the DirectDraw blitting engine */
4984 memset(&BltFx, 0, sizeof(BltFx));
4985 BltFx.dwSize = sizeof(BltFx);
4986 BltFx.u5.dwFillColor = color;
4987 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
4990 /* rendertarget and deptth stencil functions */
4991 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
4992 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4994 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
4995 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
4996 return WINED3DERR_INVALIDCALL;
4999 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5000 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5001 /* Note inc ref on returned surface */
5002 if(*ppRenderTarget != NULL)
5003 IWineD3DSurface_AddRef(*ppRenderTarget);
5004 return WINED3D_OK;
5007 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5009 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5010 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5011 IWineD3DSwapChainImpl *Swapchain;
5012 HRESULT hr;
5014 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5016 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5017 if(hr != WINED3D_OK) {
5018 ERR("Can't get the swapchain\n");
5019 return hr;
5022 /* Make sure to release the swapchain */
5023 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5025 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5026 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5027 return WINED3DERR_INVALIDCALL;
5029 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5030 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5031 return WINED3DERR_INVALIDCALL;
5034 if(Swapchain->frontBuffer != Front) {
5035 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5037 if(Swapchain->frontBuffer)
5038 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5039 Swapchain->frontBuffer = Front;
5041 if(Swapchain->frontBuffer) {
5042 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5046 if(Back && !Swapchain->backBuffer) {
5047 /* We need memory for the back buffer array - only one back buffer this way */
5048 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5049 if(!Swapchain->backBuffer) {
5050 ERR("Out of memory\n");
5051 return E_OUTOFMEMORY;
5055 if(Swapchain->backBuffer[0] != Back) {
5056 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5058 /* What to do about the context here in the case of multithreading? Not sure.
5059 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5061 ENTER_GL();
5062 if(!Swapchain->backBuffer[0]) {
5063 /* GL was told to draw to the front buffer at creation,
5064 * undo that
5066 glDrawBuffer(GL_BACK);
5067 checkGLcall("glDrawBuffer(GL_BACK)");
5068 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5069 Swapchain->presentParms.BackBufferCount = 1;
5070 } else if (!Back) {
5071 /* That makes problems - disable for now */
5072 /* glDrawBuffer(GL_FRONT); */
5073 checkGLcall("glDrawBuffer(GL_FRONT)");
5074 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5075 Swapchain->presentParms.BackBufferCount = 0;
5077 LEAVE_GL();
5079 if(Swapchain->backBuffer[0])
5080 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5081 Swapchain->backBuffer[0] = Back;
5083 if(Swapchain->backBuffer[0]) {
5084 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5085 } else {
5086 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5091 return WINED3D_OK;
5094 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5096 *ppZStencilSurface = This->depthStencilBuffer;
5097 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5099 if(*ppZStencilSurface != NULL) {
5100 /* Note inc ref on returned surface */
5101 IWineD3DSurface_AddRef(*ppZStencilSurface);
5103 return WINED3D_OK;
5106 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5109 if (!*fbo) {
5110 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5111 checkGLcall("glGenFramebuffersEXT()");
5113 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5114 checkGLcall("glBindFramebuffer()");
5117 /* TODO: Handle stencil attachments */
5118 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5120 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5122 TRACE("Set depth stencil to %p\n", depth_stencil);
5124 if (depth_stencil_impl) {
5125 if (depth_stencil_impl->current_renderbuffer) {
5126 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5127 checkGLcall("glFramebufferRenderbufferEXT()");
5128 } else {
5129 GLenum texttarget, target;
5130 GLint old_binding = 0;
5132 texttarget = depth_stencil_impl->glDescription.target;
5133 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5134 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5136 IWineD3DSurface_PreLoad(depth_stencil);
5138 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5139 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5140 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5141 glBindTexture(target, old_binding);
5143 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5144 checkGLcall("glFramebufferTexture2DEXT()");
5146 } else {
5147 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5148 checkGLcall("glFramebufferTexture2DEXT()");
5152 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5153 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5154 GLenum texttarget, target;
5155 GLint old_binding;
5157 texttarget = surface_impl->glDescription.target;
5158 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5159 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5161 IWineD3DSurface_PreLoad(surface);
5163 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5164 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5165 glBindTexture(target, old_binding);
5167 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5169 checkGLcall("attach_surface_fbo");
5172 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5174 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5176 TRACE("Set render target %u to %p\n", idx, render_target);
5178 if (rtimpl) {
5179 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5180 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5181 } else {
5182 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5183 checkGLcall("glFramebufferTexture2DEXT()");
5185 This->draw_buffers[idx] = GL_NONE;
5189 static void check_fbo_status(IWineD3DDevice *iface) {
5190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5191 GLenum status;
5193 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5194 switch(status) {
5195 case GL_FRAMEBUFFER_COMPLETE_EXT: TRACE("FBO complete.\n"); break;
5196 default: FIXME("FBO status %#x.\n", status); break;
5200 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5202 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5203 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5205 if (!ds_impl) return FALSE;
5207 if (ds_impl->current_renderbuffer) {
5208 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5209 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5212 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5213 rt_impl->pow2Height != ds_impl->pow2Height);
5216 void apply_fbo_state(IWineD3DDevice *iface) {
5217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5218 unsigned int i;
5220 if (This->render_offscreen) {
5221 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5223 /* Apply render targets */
5224 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5225 IWineD3DSurface *render_target = This->render_targets[i];
5226 if (This->fbo_color_attachments[i] != render_target) {
5227 set_render_target_fbo(iface, i, render_target);
5228 This->fbo_color_attachments[i] = render_target;
5232 /* Apply depth targets */
5233 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5234 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5235 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5237 if (This->stencilBufferTarget) {
5238 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5240 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5241 This->fbo_depth_attachment = This->stencilBufferTarget;
5244 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5245 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5246 checkGLcall("glDrawBuffers()");
5248 } else {
5249 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5252 check_fbo_status(iface);
5255 static BOOL is_onscreen(IWineD3DSurface *target) {
5256 HRESULT hr;
5257 void *tmp;
5259 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, &tmp);
5260 if (SUCCEEDED(hr)) {
5261 IWineD3DSwapChain_Release((IUnknown *)tmp);
5262 return TRUE;
5265 return FALSE;
5268 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, const WINED3DRECT *src_rect,
5269 IWineD3DSurface *dst_surface, const WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5271 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5272 GLenum gl_filter;
5274 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5275 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5276 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5277 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5279 glDisable(GL_SCISSOR_TEST);
5280 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5282 switch (filter) {
5283 case WINED3DTEXF_LINEAR:
5284 gl_filter = GL_LINEAR;
5285 break;
5287 default:
5288 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5289 case WINED3DTEXF_NONE:
5290 case WINED3DTEXF_POINT:
5291 gl_filter = GL_NEAREST;
5292 break;
5295 /* Attach src surface to src fbo */
5296 if (is_onscreen(src_surface)) {
5297 TRACE("Source surface %p is onscreen\n", src_surface);
5298 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5299 flip = !flip;
5300 } else {
5301 TRACE("Source surface %p is offscreen\n", src_surface);
5302 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5303 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5306 /* Attach dst surface to dst fbo */
5307 if (is_onscreen(dst_surface)) {
5308 TRACE("Destination surface %p is onscreen\n", dst_surface);
5309 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5310 flip = !flip;
5311 } else {
5312 TRACE("Destination surface %p is offscreen\n", dst_surface);
5313 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5314 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5317 if (flip) {
5318 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5319 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5320 } else {
5321 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5322 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5325 if (This->render_offscreen) {
5326 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5327 } else {
5328 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5329 checkGLcall("glBindFramebuffer()");
5333 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5335 WINED3DVIEWPORT viewport;
5337 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5339 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5340 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5341 return WINED3DERR_INVALIDCALL;
5344 /* MSDN says that null disables the render target
5345 but a device must always be associated with a render target
5346 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5348 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5349 for more details
5351 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5352 FIXME("Trying to set render target 0 to NULL\n");
5353 return WINED3DERR_INVALIDCALL;
5355 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5356 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);
5357 return WINED3DERR_INVALIDCALL;
5360 /* If we are trying to set what we already have, don't bother */
5361 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5362 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5363 return WINED3D_OK;
5365 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5366 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5367 This->render_targets[RenderTargetIndex] = pRenderTarget;
5369 /* Render target 0 is special */
5370 if(RenderTargetIndex == 0) {
5371 /* Finally, reset the viewport as the MSDN states. */
5372 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5373 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5374 viewport.X = 0;
5375 viewport.Y = 0;
5376 viewport.MaxZ = 1.0f;
5377 viewport.MinZ = 0.0f;
5378 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5379 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5380 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5382 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5384 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5385 * ctx properly.
5386 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5387 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5389 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5391 return WINED3D_OK;
5394 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5396 HRESULT hr = WINED3D_OK;
5397 IWineD3DSurface *tmp;
5399 TRACE("(%p) Swapping z-buffer\n",This);
5401 if (pNewZStencil == This->stencilBufferTarget) {
5402 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5403 } else {
5404 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5405 * depending on the renter target implementation being used.
5406 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5407 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5408 * stencil buffer and incure an extra memory overhead
5409 ******************************************************/
5411 tmp = This->stencilBufferTarget;
5412 This->stencilBufferTarget = pNewZStencil;
5413 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5414 /* should we be calling the parent or the wined3d surface? */
5415 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5416 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5417 hr = WINED3D_OK;
5419 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5420 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5421 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5422 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5423 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5427 return hr;
5430 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5431 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5433 /* TODO: the use of Impl is deprecated. */
5434 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5436 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5438 /* some basic validation checks */
5439 if(This->cursorTexture) {
5440 ENTER_GL();
5441 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5442 glDeleteTextures(1, &This->cursorTexture);
5443 LEAVE_GL();
5444 This->cursorTexture = 0;
5447 if(pCursorBitmap) {
5448 WINED3DLOCKED_RECT rect;
5450 /* MSDN: Cursor must be A8R8G8B8 */
5451 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5452 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5453 return WINED3DERR_INVALIDCALL;
5456 /* MSDN: Cursor must be smaller than the display mode */
5457 if(pSur->currentDesc.Width > This->ddraw_width ||
5458 pSur->currentDesc.Height > This->ddraw_height) {
5459 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);
5460 return WINED3DERR_INVALIDCALL;
5463 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5465 /* Do not store the surface's pointer because the application may release
5466 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5467 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5469 This->cursorWidth = pSur->currentDesc.Width;
5470 This->cursorHeight = pSur->currentDesc.Height;
5471 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5473 const PixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8);
5474 char *mem, *bits = (char *)rect.pBits;
5475 GLint intfmt = tableEntry->glInternal;
5476 GLint format = tableEntry->glFormat;
5477 GLint type = tableEntry->glType;
5478 INT height = This->cursorHeight;
5479 INT width = This->cursorWidth;
5480 INT bpp = tableEntry->bpp;
5481 INT i;
5483 /* Reformat the texture memory (pitch and width can be different) */
5484 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5485 for(i = 0; i < height; i++)
5486 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5487 IWineD3DSurface_UnlockRect(pCursorBitmap);
5488 ENTER_GL();
5489 /* Make sure that a proper texture unit is selected */
5490 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5491 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5492 checkGLcall("glActiveTextureARB");
5494 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5495 /* Create a new cursor texture */
5496 glGenTextures(1, &This->cursorTexture);
5497 checkGLcall("glGenTextures");
5498 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5499 checkGLcall("glBindTexture");
5500 /* Copy the bitmap memory into the cursor texture */
5501 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5502 HeapFree(GetProcessHeap(), 0, mem);
5503 checkGLcall("glTexImage2D");
5504 LEAVE_GL();
5506 else
5508 FIXME("A cursor texture was not returned.\n");
5509 This->cursorTexture = 0;
5514 This->xHotSpot = XHotSpot;
5515 This->yHotSpot = YHotSpot;
5516 return WINED3D_OK;
5519 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5521 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5523 This->xScreenSpace = XScreenSpace;
5524 This->yScreenSpace = YScreenSpace;
5526 return;
5530 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5532 BOOL oldVisible = This->bCursorVisible;
5533 POINT pt;
5535 TRACE("(%p) : visible(%d)\n", This, bShow);
5537 if(This->cursorTexture)
5538 This->bCursorVisible = bShow;
5540 * When ShowCursor is first called it should make the cursor appear at the OS's last
5541 * known cursor position. Because of this, some applications just repetitively call
5542 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5544 GetCursorPos(&pt);
5545 This->xScreenSpace = pt.x;
5546 This->yScreenSpace = pt.y;
5548 return oldVisible;
5551 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5553 TRACE("(%p) : state (%u)\n", This, This->state);
5554 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5555 switch (This->state) {
5556 case WINED3D_OK:
5557 return WINED3D_OK;
5558 case WINED3DERR_DEVICELOST:
5560 ResourceList *resourceList = This->resources;
5561 while (NULL != resourceList) {
5562 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5563 return WINED3DERR_DEVICENOTRESET;
5564 resourceList = resourceList->next;
5566 return WINED3DERR_DEVICELOST;
5568 case WINED3DERR_DRIVERINTERNALERROR:
5569 return WINED3DERR_DRIVERINTERNALERROR;
5572 /* Unknown state */
5573 return WINED3DERR_DRIVERINTERNALERROR;
5577 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5579 /** FIXME: Resource tracking needs to be done,
5580 * The closes we can do to this is set the priorities of all managed textures low
5581 * and then reset them.
5582 ***********************************************************/
5583 FIXME("(%p) : stub\n", This);
5584 return WINED3D_OK;
5587 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5588 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5590 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5591 if(surface->Flags & SFLAG_DIBSECTION) {
5592 /* Release the DC */
5593 SelectObject(surface->hDC, surface->dib.holdbitmap);
5594 DeleteDC(surface->hDC);
5595 /* Release the DIB section */
5596 DeleteObject(surface->dib.DIBsection);
5597 surface->dib.bitmap_data = NULL;
5598 surface->resource.allocatedMemory = NULL;
5599 surface->Flags &= ~SFLAG_DIBSECTION;
5601 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5602 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5603 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5604 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5605 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5606 } else {
5607 surface->pow2Width = surface->pow2Height = 1;
5608 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5609 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5611 if(surface->glDescription.textureName) {
5612 ENTER_GL();
5613 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5614 glDeleteTextures(1, &surface->glDescription.textureName);
5615 LEAVE_GL();
5616 surface->glDescription.textureName = 0;
5617 surface->Flags &= ~SFLAG_CLIENT;
5619 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5620 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5621 surface->Flags |= SFLAG_NONPOW2;
5622 } else {
5623 surface->Flags &= ~SFLAG_NONPOW2;
5625 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5626 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5629 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5631 IWineD3DSwapChainImpl *swapchain;
5632 HRESULT hr;
5633 BOOL DisplayModeChanged = FALSE;
5634 WINED3DDISPLAYMODE mode;
5635 TRACE("(%p)\n", This);
5637 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5638 if(FAILED(hr)) {
5639 ERR("Failed to get the first implicit swapchain\n");
5640 return hr;
5643 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5644 * on an existing gl context, so there's no real need for recreation.
5646 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5648 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5650 TRACE("New params:\n");
5651 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5652 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5653 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5654 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5655 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
5656 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
5657 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
5658 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
5659 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
5660 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5661 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
5662 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
5663 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
5665 /* No special treatment of these parameters. Just store them */
5666 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
5667 swapchain->presentParms.Flags = pPresentationParameters->Flags;
5668 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
5669 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
5671 /* What to do about these? */
5672 if(pPresentationParameters->BackBufferCount != 0 &&
5673 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
5674 ERR("Cannot change the back buffer count yet\n");
5676 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5677 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5678 ERR("Cannot change the back buffer format yet\n");
5680 if(pPresentationParameters->hDeviceWindow != NULL &&
5681 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
5682 ERR("Cannot change the device window yet\n");
5684 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
5685 ERR("What do do about a changed auto depth stencil parameter?\n");
5688 if(pPresentationParameters->Windowed) {
5689 mode.Width = swapchain->orig_width;
5690 mode.Height = swapchain->orig_height;
5691 mode.RefreshRate = 0;
5692 mode.Format = swapchain->presentParms.BackBufferFormat;
5693 } else {
5694 mode.Width = pPresentationParameters->BackBufferWidth;
5695 mode.Height = pPresentationParameters->BackBufferHeight;
5696 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
5697 mode.Format = swapchain->presentParms.BackBufferFormat;
5700 /* Should Width == 800 && Height == 0 set 800x600? */
5701 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
5702 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
5703 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5705 WINED3DVIEWPORT vp;
5706 int i;
5708 vp.X = 0;
5709 vp.Y = 0;
5710 vp.Width = pPresentationParameters->BackBufferWidth;
5711 vp.Height = pPresentationParameters->BackBufferHeight;
5712 vp.MinZ = 0;
5713 vp.MaxZ = 1;
5715 if(!pPresentationParameters->Windowed) {
5716 DisplayModeChanged = TRUE;
5718 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
5719 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
5721 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
5722 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
5723 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
5726 /* Now set the new viewport */
5727 IWineD3DDevice_SetViewport(iface, &vp);
5730 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
5731 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
5732 DisplayModeChanged) {
5734 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
5735 if(!pPresentationParameters->Windowed) {
5736 IWineD3DDevice_SetFullscreen(iface, TRUE);
5739 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
5741 /* Switching out of fullscreen mode? First set the original res, then change the window */
5742 if(pPresentationParameters->Windowed) {
5743 IWineD3DDevice_SetFullscreen(iface, FALSE);
5745 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
5748 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5749 return WINED3D_OK;
5752 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
5753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5754 /** FIXME: always true at the moment **/
5755 if(!bEnableDialogs) {
5756 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
5758 return WINED3D_OK;
5762 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
5763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5764 TRACE("(%p) : pParameters %p\n", This, pParameters);
5766 *pParameters = This->createParms;
5767 return WINED3D_OK;
5770 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
5771 IWineD3DSwapChain *swapchain;
5772 HRESULT hrc = WINED3D_OK;
5774 TRACE("Relaying to swapchain\n");
5776 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5777 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
5778 IWineD3DSwapChain_Release(swapchain);
5780 return;
5783 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
5784 IWineD3DSwapChain *swapchain;
5785 HRESULT hrc = WINED3D_OK;
5787 TRACE("Relaying to swapchain\n");
5789 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5790 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
5791 IWineD3DSwapChain_Release(swapchain);
5793 return;
5797 /** ********************************************************
5798 * Notification functions
5799 ** ********************************************************/
5800 /** This function must be called in the release of a resource when ref == 0,
5801 * the contents of resource must still be correct,
5802 * any handels to other resource held by the caller must be closed
5803 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
5804 *****************************************************/
5805 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5807 ResourceList* resourceList;
5809 TRACE("(%p) : resource %p\n", This, resource);
5810 /* add a new texture to the frot of the linked list */
5811 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
5812 resourceList->resource = resource;
5814 /* Get the old head */
5815 resourceList->next = This->resources;
5817 This->resources = resourceList;
5818 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
5820 return;
5823 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5825 ResourceList* resourceList = NULL;
5826 ResourceList* previousResourceList = NULL;
5828 TRACE("(%p) : resource %p\n", This, resource);
5830 resourceList = This->resources;
5832 while (resourceList != NULL) {
5833 if(resourceList->resource == resource) break;
5834 previousResourceList = resourceList;
5835 resourceList = resourceList->next;
5838 if (resourceList == NULL) {
5839 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
5840 return;
5841 } else {
5842 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
5844 /* make sure we don't leave a hole in the list */
5845 if (previousResourceList != NULL) {
5846 previousResourceList->next = resourceList->next;
5847 } else {
5848 This->resources = resourceList->next;
5851 return;
5855 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
5856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5857 int counter;
5859 TRACE("(%p) : resource %p\n", This, resource);
5860 switch(IWineD3DResource_GetType(resource)){
5861 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
5862 case WINED3DRTYPE_SURFACE: {
5863 unsigned int i;
5865 /* Cleanup any FBO attachments */
5866 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5867 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
5868 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5869 set_render_target_fbo(iface, i, NULL);
5870 This->fbo_color_attachments[i] = NULL;
5873 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
5874 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5875 set_depth_stencil_fbo(iface, NULL);
5876 This->fbo_depth_attachment = NULL;
5879 break;
5882 case WINED3DRTYPE_TEXTURE:
5883 case WINED3DRTYPE_CUBETEXTURE:
5884 case WINED3DRTYPE_VOLUMETEXTURE:
5885 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
5886 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5887 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5888 This->stateBlock->textures[counter] = NULL;
5890 if (This->updateStateBlock != This->stateBlock ){
5891 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5892 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5893 This->updateStateBlock->textures[counter] = NULL;
5897 break;
5898 case WINED3DRTYPE_VOLUME:
5899 /* TODO: nothing really? */
5900 break;
5901 case WINED3DRTYPE_VERTEXBUFFER:
5902 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
5904 int streamNumber;
5905 TRACE("Cleaning up stream pointers\n");
5907 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
5908 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
5909 FINDOUT: should changes.streamSource[StreamNumber] be set ?
5911 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5912 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
5913 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5914 This->updateStateBlock->streamSource[streamNumber] = 0;
5915 /* Set changed flag? */
5918 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) */
5919 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
5920 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5921 This->stateBlock->streamSource[streamNumber] = 0;
5924 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
5925 else { /* This shouldn't happen */
5926 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
5928 #endif
5932 break;
5933 case WINED3DRTYPE_INDEXBUFFER:
5934 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
5935 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5936 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5937 This->updateStateBlock->pIndexData = NULL;
5940 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
5941 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5942 This->stateBlock->pIndexData = NULL;
5946 break;
5947 default:
5948 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
5949 break;
5953 /* Remove the resoruce from the resourceStore */
5954 IWineD3DDeviceImpl_RemoveResource(iface, resource);
5956 TRACE("Resource released\n");
5960 /**********************************************************
5961 * IWineD3DDevice VTbl follows
5962 **********************************************************/
5964 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
5966 /*** IUnknown methods ***/
5967 IWineD3DDeviceImpl_QueryInterface,
5968 IWineD3DDeviceImpl_AddRef,
5969 IWineD3DDeviceImpl_Release,
5970 /*** IWineD3DDevice methods ***/
5971 IWineD3DDeviceImpl_GetParent,
5972 /*** Creation methods**/
5973 IWineD3DDeviceImpl_CreateVertexBuffer,
5974 IWineD3DDeviceImpl_CreateIndexBuffer,
5975 IWineD3DDeviceImpl_CreateStateBlock,
5976 IWineD3DDeviceImpl_CreateSurface,
5977 IWineD3DDeviceImpl_CreateTexture,
5978 IWineD3DDeviceImpl_CreateVolumeTexture,
5979 IWineD3DDeviceImpl_CreateVolume,
5980 IWineD3DDeviceImpl_CreateCubeTexture,
5981 IWineD3DDeviceImpl_CreateQuery,
5982 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
5983 IWineD3DDeviceImpl_CreateVertexDeclaration,
5984 IWineD3DDeviceImpl_CreateVertexShader,
5985 IWineD3DDeviceImpl_CreatePixelShader,
5986 IWineD3DDeviceImpl_CreatePalette,
5987 /*** Odd functions **/
5988 IWineD3DDeviceImpl_Init3D,
5989 IWineD3DDeviceImpl_Uninit3D,
5990 IWineD3DDeviceImpl_SetFullscreen,
5991 IWineD3DDeviceImpl_SetMultithreaded,
5992 IWineD3DDeviceImpl_EvictManagedResources,
5993 IWineD3DDeviceImpl_GetAvailableTextureMem,
5994 IWineD3DDeviceImpl_GetBackBuffer,
5995 IWineD3DDeviceImpl_GetCreationParameters,
5996 IWineD3DDeviceImpl_GetDeviceCaps,
5997 IWineD3DDeviceImpl_GetDirect3D,
5998 IWineD3DDeviceImpl_GetDisplayMode,
5999 IWineD3DDeviceImpl_SetDisplayMode,
6000 IWineD3DDeviceImpl_GetHWND,
6001 IWineD3DDeviceImpl_SetHWND,
6002 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6003 IWineD3DDeviceImpl_GetRasterStatus,
6004 IWineD3DDeviceImpl_GetSwapChain,
6005 IWineD3DDeviceImpl_Reset,
6006 IWineD3DDeviceImpl_SetDialogBoxMode,
6007 IWineD3DDeviceImpl_SetCursorProperties,
6008 IWineD3DDeviceImpl_SetCursorPosition,
6009 IWineD3DDeviceImpl_ShowCursor,
6010 IWineD3DDeviceImpl_TestCooperativeLevel,
6011 /*** Getters and setters **/
6012 IWineD3DDeviceImpl_SetClipPlane,
6013 IWineD3DDeviceImpl_GetClipPlane,
6014 IWineD3DDeviceImpl_SetClipStatus,
6015 IWineD3DDeviceImpl_GetClipStatus,
6016 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6017 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6018 IWineD3DDeviceImpl_SetDepthStencilSurface,
6019 IWineD3DDeviceImpl_GetDepthStencilSurface,
6020 IWineD3DDeviceImpl_SetFVF,
6021 IWineD3DDeviceImpl_GetFVF,
6022 IWineD3DDeviceImpl_SetGammaRamp,
6023 IWineD3DDeviceImpl_GetGammaRamp,
6024 IWineD3DDeviceImpl_SetIndices,
6025 IWineD3DDeviceImpl_GetIndices,
6026 IWineD3DDeviceImpl_SetBasevertexIndex,
6027 IWineD3DDeviceImpl_SetLight,
6028 IWineD3DDeviceImpl_GetLight,
6029 IWineD3DDeviceImpl_SetLightEnable,
6030 IWineD3DDeviceImpl_GetLightEnable,
6031 IWineD3DDeviceImpl_SetMaterial,
6032 IWineD3DDeviceImpl_GetMaterial,
6033 IWineD3DDeviceImpl_SetNPatchMode,
6034 IWineD3DDeviceImpl_GetNPatchMode,
6035 IWineD3DDeviceImpl_SetPaletteEntries,
6036 IWineD3DDeviceImpl_GetPaletteEntries,
6037 IWineD3DDeviceImpl_SetPixelShader,
6038 IWineD3DDeviceImpl_GetPixelShader,
6039 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6040 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6041 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6042 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6043 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6044 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6045 IWineD3DDeviceImpl_SetRenderState,
6046 IWineD3DDeviceImpl_GetRenderState,
6047 IWineD3DDeviceImpl_SetRenderTarget,
6048 IWineD3DDeviceImpl_GetRenderTarget,
6049 IWineD3DDeviceImpl_SetFrontBackBuffers,
6050 IWineD3DDeviceImpl_SetSamplerState,
6051 IWineD3DDeviceImpl_GetSamplerState,
6052 IWineD3DDeviceImpl_SetScissorRect,
6053 IWineD3DDeviceImpl_GetScissorRect,
6054 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6055 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6056 IWineD3DDeviceImpl_SetStreamSource,
6057 IWineD3DDeviceImpl_GetStreamSource,
6058 IWineD3DDeviceImpl_SetStreamSourceFreq,
6059 IWineD3DDeviceImpl_GetStreamSourceFreq,
6060 IWineD3DDeviceImpl_SetTexture,
6061 IWineD3DDeviceImpl_GetTexture,
6062 IWineD3DDeviceImpl_SetTextureStageState,
6063 IWineD3DDeviceImpl_GetTextureStageState,
6064 IWineD3DDeviceImpl_SetTransform,
6065 IWineD3DDeviceImpl_GetTransform,
6066 IWineD3DDeviceImpl_SetVertexDeclaration,
6067 IWineD3DDeviceImpl_GetVertexDeclaration,
6068 IWineD3DDeviceImpl_SetVertexShader,
6069 IWineD3DDeviceImpl_GetVertexShader,
6070 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6071 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6072 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6073 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6074 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6075 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6076 IWineD3DDeviceImpl_SetViewport,
6077 IWineD3DDeviceImpl_GetViewport,
6078 IWineD3DDeviceImpl_MultiplyTransform,
6079 IWineD3DDeviceImpl_ValidateDevice,
6080 IWineD3DDeviceImpl_ProcessVertices,
6081 /*** State block ***/
6082 IWineD3DDeviceImpl_BeginStateBlock,
6083 IWineD3DDeviceImpl_EndStateBlock,
6084 /*** Scene management ***/
6085 IWineD3DDeviceImpl_BeginScene,
6086 IWineD3DDeviceImpl_EndScene,
6087 IWineD3DDeviceImpl_Present,
6088 IWineD3DDeviceImpl_Clear,
6089 /*** Drawing ***/
6090 IWineD3DDeviceImpl_DrawPrimitive,
6091 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6092 IWineD3DDeviceImpl_DrawPrimitiveUP,
6093 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6094 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6095 IWineD3DDeviceImpl_DrawRectPatch,
6096 IWineD3DDeviceImpl_DrawTriPatch,
6097 IWineD3DDeviceImpl_DeletePatch,
6098 IWineD3DDeviceImpl_ColorFill,
6099 IWineD3DDeviceImpl_UpdateTexture,
6100 IWineD3DDeviceImpl_UpdateSurface,
6101 IWineD3DDeviceImpl_GetFrontBufferData,
6102 /*** object tracking ***/
6103 IWineD3DDeviceImpl_ResourceReleased
6107 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6108 WINED3DRS_ALPHABLENDENABLE ,
6109 WINED3DRS_ALPHAFUNC ,
6110 WINED3DRS_ALPHAREF ,
6111 WINED3DRS_ALPHATESTENABLE ,
6112 WINED3DRS_BLENDOP ,
6113 WINED3DRS_COLORWRITEENABLE ,
6114 WINED3DRS_DESTBLEND ,
6115 WINED3DRS_DITHERENABLE ,
6116 WINED3DRS_FILLMODE ,
6117 WINED3DRS_FOGDENSITY ,
6118 WINED3DRS_FOGEND ,
6119 WINED3DRS_FOGSTART ,
6120 WINED3DRS_LASTPIXEL ,
6121 WINED3DRS_SHADEMODE ,
6122 WINED3DRS_SRCBLEND ,
6123 WINED3DRS_STENCILENABLE ,
6124 WINED3DRS_STENCILFAIL ,
6125 WINED3DRS_STENCILFUNC ,
6126 WINED3DRS_STENCILMASK ,
6127 WINED3DRS_STENCILPASS ,
6128 WINED3DRS_STENCILREF ,
6129 WINED3DRS_STENCILWRITEMASK ,
6130 WINED3DRS_STENCILZFAIL ,
6131 WINED3DRS_TEXTUREFACTOR ,
6132 WINED3DRS_WRAP0 ,
6133 WINED3DRS_WRAP1 ,
6134 WINED3DRS_WRAP2 ,
6135 WINED3DRS_WRAP3 ,
6136 WINED3DRS_WRAP4 ,
6137 WINED3DRS_WRAP5 ,
6138 WINED3DRS_WRAP6 ,
6139 WINED3DRS_WRAP7 ,
6140 WINED3DRS_ZENABLE ,
6141 WINED3DRS_ZFUNC ,
6142 WINED3DRS_ZWRITEENABLE
6145 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6146 WINED3DTSS_ADDRESSW ,
6147 WINED3DTSS_ALPHAARG0 ,
6148 WINED3DTSS_ALPHAARG1 ,
6149 WINED3DTSS_ALPHAARG2 ,
6150 WINED3DTSS_ALPHAOP ,
6151 WINED3DTSS_BUMPENVLOFFSET ,
6152 WINED3DTSS_BUMPENVLSCALE ,
6153 WINED3DTSS_BUMPENVMAT00 ,
6154 WINED3DTSS_BUMPENVMAT01 ,
6155 WINED3DTSS_BUMPENVMAT10 ,
6156 WINED3DTSS_BUMPENVMAT11 ,
6157 WINED3DTSS_COLORARG0 ,
6158 WINED3DTSS_COLORARG1 ,
6159 WINED3DTSS_COLORARG2 ,
6160 WINED3DTSS_COLOROP ,
6161 WINED3DTSS_RESULTARG ,
6162 WINED3DTSS_TEXCOORDINDEX ,
6163 WINED3DTSS_TEXTURETRANSFORMFLAGS
6166 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6167 WINED3DSAMP_ADDRESSU ,
6168 WINED3DSAMP_ADDRESSV ,
6169 WINED3DSAMP_ADDRESSW ,
6170 WINED3DSAMP_BORDERCOLOR ,
6171 WINED3DSAMP_MAGFILTER ,
6172 WINED3DSAMP_MINFILTER ,
6173 WINED3DSAMP_MIPFILTER ,
6174 WINED3DSAMP_MIPMAPLODBIAS ,
6175 WINED3DSAMP_MAXMIPLEVEL ,
6176 WINED3DSAMP_MAXANISOTROPY ,
6177 WINED3DSAMP_SRGBTEXTURE ,
6178 WINED3DSAMP_ELEMENTINDEX
6181 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6182 WINED3DRS_AMBIENT ,
6183 WINED3DRS_AMBIENTMATERIALSOURCE ,
6184 WINED3DRS_CLIPPING ,
6185 WINED3DRS_CLIPPLANEENABLE ,
6186 WINED3DRS_COLORVERTEX ,
6187 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6188 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6189 WINED3DRS_FOGDENSITY ,
6190 WINED3DRS_FOGEND ,
6191 WINED3DRS_FOGSTART ,
6192 WINED3DRS_FOGTABLEMODE ,
6193 WINED3DRS_FOGVERTEXMODE ,
6194 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6195 WINED3DRS_LIGHTING ,
6196 WINED3DRS_LOCALVIEWER ,
6197 WINED3DRS_MULTISAMPLEANTIALIAS ,
6198 WINED3DRS_MULTISAMPLEMASK ,
6199 WINED3DRS_NORMALIZENORMALS ,
6200 WINED3DRS_PATCHEDGESTYLE ,
6201 WINED3DRS_POINTSCALE_A ,
6202 WINED3DRS_POINTSCALE_B ,
6203 WINED3DRS_POINTSCALE_C ,
6204 WINED3DRS_POINTSCALEENABLE ,
6205 WINED3DRS_POINTSIZE ,
6206 WINED3DRS_POINTSIZE_MAX ,
6207 WINED3DRS_POINTSIZE_MIN ,
6208 WINED3DRS_POINTSPRITEENABLE ,
6209 WINED3DRS_RANGEFOGENABLE ,
6210 WINED3DRS_SPECULARMATERIALSOURCE ,
6211 WINED3DRS_TWEENFACTOR ,
6212 WINED3DRS_VERTEXBLEND
6215 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6216 WINED3DTSS_TEXCOORDINDEX ,
6217 WINED3DTSS_TEXTURETRANSFORMFLAGS
6220 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6221 WINED3DSAMP_DMAPOFFSET
6224 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6225 DWORD rep = StateTable[state].representative;
6226 DWORD idx;
6227 BYTE shift;
6228 UINT i;
6229 WineD3DContext *context;
6231 if(!rep) return;
6232 for(i = 0; i < This->numContexts; i++) {
6233 context = This->contexts[i];
6234 if(isStateDirty(context, rep)) continue;
6236 context->dirtyArray[context->numDirtyEntries++] = rep;
6237 idx = rep >> 5;
6238 shift = rep & 0x1f;
6239 context->isStateDirty[idx] |= (1 << shift);