wined3d: Use the framebuffer blit extension to implement StretchRect.
[wine/wine64.git] / dlls / wined3d / device.c
blob580fcd0d3186262b887d44e556385cbb92ffd749
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 DDERR_INVALIDMODE;
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: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, 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: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2057 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2059 if (StreamNumber >= MAX_STREAMS) {
2060 WARN("Stream out of range %d\n", StreamNumber);
2061 return WINED3DERR_INVALIDCALL;
2063 *pStream = This->stateBlock->streamSource[StreamNumber];
2064 *pStride = This->stateBlock->streamStride[StreamNumber];
2065 if (pOffset) {
2066 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2069 if (*pStream != NULL) {
2070 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2072 return WINED3D_OK;
2075 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2077 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2078 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2080 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2081 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2083 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2084 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2085 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2087 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2088 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2089 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2092 return WINED3D_OK;
2095 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2098 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2099 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2101 TRACE("(%p) : returning %d\n", This, *Divider);
2103 return WINED3D_OK;
2106 /*****
2107 * Get / Set & Multiply Transform
2108 *****/
2109 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2112 /* Most of this routine, comments included copied from ddraw tree initially: */
2113 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2115 /* Handle recording of state blocks */
2116 if (This->isRecordingState) {
2117 TRACE("Recording... not performing anything\n");
2118 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2119 This->updateStateBlock->set.transform[d3dts] = TRUE;
2120 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2121 return WINED3D_OK;
2125 * If the new matrix is the same as the current one,
2126 * we cut off any further processing. this seems to be a reasonable
2127 * optimization because as was noticed, some apps (warcraft3 for example)
2128 * tend towards setting the same matrix repeatedly for some reason.
2130 * From here on we assume that the new matrix is different, wherever it matters.
2132 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2133 TRACE("The app is setting the same matrix over again\n");
2134 return WINED3D_OK;
2135 } else {
2136 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2140 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2141 where ViewMat = Camera space, WorldMat = world space.
2143 In OpenGL, camera and world space is combined into GL_MODELVIEW
2144 matrix. The Projection matrix stay projection matrix.
2147 /* Capture the times we can just ignore the change for now */
2148 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2149 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2150 /* Handled by the state manager */
2153 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2154 return WINED3D_OK;
2157 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2159 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2160 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2161 return WINED3D_OK;
2164 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2165 WINED3DMATRIX *mat = NULL;
2166 WINED3DMATRIX temp;
2168 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2169 * below means it will be recorded in a state block change, but it
2170 * works regardless where it is recorded.
2171 * If this is found to be wrong, change to StateBlock.
2173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2174 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2176 if (State < HIGHEST_TRANSFORMSTATE)
2178 mat = &This->updateStateBlock->transforms[State];
2179 } else {
2180 FIXME("Unhandled transform state!!\n");
2183 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2185 /* Apply change via set transform - will reapply to eg. lights this way */
2186 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2189 /*****
2190 * Get / Set Light
2191 *****/
2192 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2193 you can reference any indexes you want as long as that number max are enabled at any
2194 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2195 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2196 but when recording, just build a chain pretty much of commands to be replayed. */
2198 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2199 float rho;
2200 PLIGHTINFOEL *object = NULL;
2201 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2202 struct list *e;
2204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2205 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2207 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2208 * the gl driver.
2210 if(!pLight) {
2211 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2212 return WINED3DERR_INVALIDCALL;
2215 switch(pLight->Type) {
2216 case WINED3DLIGHT_POINT:
2217 case WINED3DLIGHT_SPOT:
2218 case WINED3DLIGHT_PARALLELPOINT:
2219 case WINED3DLIGHT_GLSPOT:
2220 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2221 * most wanted
2223 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2224 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2225 return WINED3DERR_INVALIDCALL;
2227 break;
2229 case WINED3DLIGHT_DIRECTIONAL:
2230 /* Ignores attenuation */
2231 break;
2233 default:
2234 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2235 return WINED3DERR_INVALIDCALL;
2238 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2239 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2240 if(object->OriginalIndex == Index) break;
2241 object = NULL;
2244 if(!object) {
2245 TRACE("Adding new light\n");
2246 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2247 if(!object) {
2248 ERR("Out of memory error when allocating a light\n");
2249 return E_OUTOFMEMORY;
2251 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2252 object->glIndex = -1;
2253 object->OriginalIndex = Index;
2254 object->changed = TRUE;
2257 /* Initialize the object */
2258 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,
2259 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2260 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2261 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2262 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2263 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2264 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2266 /* Save away the information */
2267 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2269 switch (pLight->Type) {
2270 case WINED3DLIGHT_POINT:
2271 /* Position */
2272 object->lightPosn[0] = pLight->Position.x;
2273 object->lightPosn[1] = pLight->Position.y;
2274 object->lightPosn[2] = pLight->Position.z;
2275 object->lightPosn[3] = 1.0f;
2276 object->cutoff = 180.0f;
2277 /* FIXME: Range */
2278 break;
2280 case WINED3DLIGHT_DIRECTIONAL:
2281 /* Direction */
2282 object->lightPosn[0] = -pLight->Direction.x;
2283 object->lightPosn[1] = -pLight->Direction.y;
2284 object->lightPosn[2] = -pLight->Direction.z;
2285 object->lightPosn[3] = 0.0;
2286 object->exponent = 0.0f;
2287 object->cutoff = 180.0f;
2288 break;
2290 case WINED3DLIGHT_SPOT:
2291 /* Position */
2292 object->lightPosn[0] = pLight->Position.x;
2293 object->lightPosn[1] = pLight->Position.y;
2294 object->lightPosn[2] = pLight->Position.z;
2295 object->lightPosn[3] = 1.0;
2297 /* Direction */
2298 object->lightDirn[0] = pLight->Direction.x;
2299 object->lightDirn[1] = pLight->Direction.y;
2300 object->lightDirn[2] = pLight->Direction.z;
2301 object->lightDirn[3] = 1.0;
2304 * opengl-ish and d3d-ish spot lights use too different models for the
2305 * light "intensity" as a function of the angle towards the main light direction,
2306 * so we only can approximate very roughly.
2307 * however spot lights are rather rarely used in games (if ever used at all).
2308 * furthermore if still used, probably nobody pays attention to such details.
2310 if (pLight->Falloff == 0) {
2311 rho = 6.28f;
2312 } else {
2313 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2315 if (rho < 0.0001) rho = 0.0001f;
2316 object->exponent = -0.3/log(cos(rho/2));
2317 if (object->exponent > 128.0) {
2318 object->exponent = 128.0;
2320 object->cutoff = pLight->Phi*90/M_PI;
2322 /* FIXME: Range */
2323 break;
2325 default:
2326 FIXME("Unrecognized light type %d\n", pLight->Type);
2329 /* Update the live definitions if the light is currently assigned a glIndex */
2330 if (object->glIndex != -1 && !This->isRecordingState) {
2331 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2333 return WINED3D_OK;
2336 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2337 PLIGHTINFOEL *lightInfo = NULL;
2338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2339 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2340 struct list *e;
2341 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2343 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2344 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2345 if(lightInfo->OriginalIndex == Index) break;
2346 lightInfo = NULL;
2349 if (lightInfo == NULL) {
2350 TRACE("Light information requested but light not defined\n");
2351 return WINED3DERR_INVALIDCALL;
2354 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2355 return WINED3D_OK;
2358 /*****
2359 * Get / Set Light Enable
2360 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2361 *****/
2362 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2363 PLIGHTINFOEL *lightInfo = NULL;
2364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2365 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2366 struct list *e;
2367 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2369 /* Tests show true = 128...not clear why */
2370 Enable = Enable? 128: 0;
2372 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2373 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2374 if(lightInfo->OriginalIndex == Index) break;
2375 lightInfo = NULL;
2377 TRACE("Found light: %p\n", lightInfo);
2379 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2380 if (lightInfo == NULL) {
2382 TRACE("Light enabled requested but light not defined, so defining one!\n");
2383 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2385 /* Search for it again! Should be fairly quick as near head of list */
2386 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2387 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2388 if(lightInfo->OriginalIndex == Index) break;
2389 lightInfo = NULL;
2391 if (lightInfo == NULL) {
2392 FIXME("Adding default lights has failed dismally\n");
2393 return WINED3DERR_INVALIDCALL;
2397 lightInfo->enabledChanged = TRUE;
2398 if(!Enable) {
2399 if(lightInfo->glIndex != -1) {
2400 if(!This->isRecordingState) {
2401 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2404 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2405 lightInfo->glIndex = -1;
2406 } else {
2407 TRACE("Light already disabled, nothing to do\n");
2409 } else {
2410 if (lightInfo->glIndex != -1) {
2411 /* nop */
2412 TRACE("Nothing to do as light was enabled\n");
2413 } else {
2414 int i;
2415 /* Find a free gl light */
2416 for(i = 0; i < This->maxConcurrentLights; i++) {
2417 if(This->stateBlock->activeLights[i] == NULL) {
2418 This->stateBlock->activeLights[i] = lightInfo;
2419 lightInfo->glIndex = i;
2420 break;
2423 if(lightInfo->glIndex == -1) {
2424 ERR("Too many concurrently active lights\n");
2425 return WINED3DERR_INVALIDCALL;
2428 /* i == lightInfo->glIndex */
2429 if(!This->isRecordingState) {
2430 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2435 return WINED3D_OK;
2438 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2440 PLIGHTINFOEL *lightInfo = NULL;
2441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2442 struct list *e;
2443 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2444 TRACE("(%p) : for idx(%d)\n", This, Index);
2446 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2447 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2448 if(lightInfo->OriginalIndex == Index) break;
2449 lightInfo = NULL;
2452 if (lightInfo == NULL) {
2453 TRACE("Light enabled state requested but light not defined\n");
2454 return WINED3DERR_INVALIDCALL;
2456 /* true is 128 according to SetLightEnable */
2457 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2458 return WINED3D_OK;
2461 /*****
2462 * Get / Set Clip Planes
2463 *****/
2464 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2465 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2466 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2468 /* Validate Index */
2469 if (Index >= GL_LIMITS(clipplanes)) {
2470 TRACE("Application has requested clipplane this device doesn't support\n");
2471 return WINED3DERR_INVALIDCALL;
2474 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2475 This->updateStateBlock->set.clipplane[Index] = TRUE;
2477 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2478 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2479 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2480 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2481 TRACE("Application is setting old values over, nothing to do\n");
2482 return WINED3D_OK;
2485 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2486 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2487 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2488 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2490 /* Handle recording of state blocks */
2491 if (This->isRecordingState) {
2492 TRACE("Recording... not performing anything\n");
2493 return WINED3D_OK;
2496 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2498 return WINED3D_OK;
2501 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2503 TRACE("(%p) : for idx %d\n", This, Index);
2505 /* Validate Index */
2506 if (Index >= GL_LIMITS(clipplanes)) {
2507 TRACE("Application has requested clipplane this device doesn't support\n");
2508 return WINED3DERR_INVALIDCALL;
2511 pPlane[0] = This->stateBlock->clipplane[Index][0];
2512 pPlane[1] = This->stateBlock->clipplane[Index][1];
2513 pPlane[2] = This->stateBlock->clipplane[Index][2];
2514 pPlane[3] = This->stateBlock->clipplane[Index][3];
2515 return WINED3D_OK;
2518 /*****
2519 * Get / Set Clip Plane Status
2520 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2521 *****/
2522 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2524 FIXME("(%p) : stub\n", This);
2525 if (NULL == pClipStatus) {
2526 return WINED3DERR_INVALIDCALL;
2528 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2529 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2530 return WINED3D_OK;
2533 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2535 FIXME("(%p) : stub\n", This);
2536 if (NULL == pClipStatus) {
2537 return WINED3DERR_INVALIDCALL;
2539 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2540 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2541 return WINED3D_OK;
2544 /*****
2545 * Get / Set Material
2546 *****/
2547 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2550 This->updateStateBlock->changed.material = TRUE;
2551 This->updateStateBlock->set.material = TRUE;
2552 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2554 /* Handle recording of state blocks */
2555 if (This->isRecordingState) {
2556 TRACE("Recording... not performing anything\n");
2557 return WINED3D_OK;
2560 ENTER_GL();
2561 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2562 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2563 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2564 pMaterial->Ambient.b, pMaterial->Ambient.a);
2565 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2566 pMaterial->Specular.b, pMaterial->Specular.a);
2567 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2568 pMaterial->Emissive.b, pMaterial->Emissive.a);
2569 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2571 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2572 checkGLcall("glMaterialfv(GL_AMBIENT)");
2573 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2574 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2576 /* Only change material color if specular is enabled, otherwise it is set to black */
2577 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2578 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2579 checkGLcall("glMaterialfv(GL_SPECULAR");
2580 } else {
2581 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2582 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2583 checkGLcall("glMaterialfv(GL_SPECULAR");
2585 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2586 checkGLcall("glMaterialfv(GL_EMISSION)");
2587 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2588 checkGLcall("glMaterialf(GL_SHININESS");
2590 LEAVE_GL();
2591 return WINED3D_OK;
2594 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2596 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2597 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2598 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2599 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2600 pMaterial->Ambient.b, pMaterial->Ambient.a);
2601 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2602 pMaterial->Specular.b, pMaterial->Specular.a);
2603 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2604 pMaterial->Emissive.b, pMaterial->Emissive.a);
2605 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2607 return WINED3D_OK;
2610 /*****
2611 * Get / Set Indices
2612 *****/
2613 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2614 UINT BaseVertexIndex) {
2615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2616 IWineD3DIndexBuffer *oldIdxs;
2617 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2619 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2620 oldIdxs = This->updateStateBlock->pIndexData;
2622 This->updateStateBlock->changed.indices = TRUE;
2623 This->updateStateBlock->set.indices = TRUE;
2624 This->updateStateBlock->pIndexData = pIndexData;
2625 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2627 /* Handle recording of state blocks */
2628 if (This->isRecordingState) {
2629 TRACE("Recording... not performing anything\n");
2630 return WINED3D_OK;
2633 /* The base vertex index affects the stream sources, while
2634 * The index buffer is a seperate index buffer state
2636 if(BaseVertexIndex != oldBaseIndex) {
2637 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2639 if(oldIdxs != pIndexData) {
2640 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2642 return WINED3D_OK;
2645 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2648 *ppIndexData = This->stateBlock->pIndexData;
2650 /* up ref count on ppindexdata */
2651 if (*ppIndexData) {
2652 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2653 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2654 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2655 }else{
2656 TRACE("(%p) No index data set\n", This);
2658 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2660 return WINED3D_OK;
2663 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2664 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2666 TRACE("(%p)->(%d)\n", This, BaseIndex);
2668 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2669 TRACE("Application is setting the old value over, nothing to do\n");
2670 return WINED3D_OK;
2673 This->updateStateBlock->baseVertexIndex = BaseIndex;
2675 if (This->isRecordingState) {
2676 TRACE("Recording... not performing anything\n");
2677 return WINED3D_OK;
2679 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2680 return WINED3D_OK;
2683 /*****
2684 * Get / Set Viewports
2685 *****/
2686 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2689 TRACE("(%p)\n", This);
2690 This->updateStateBlock->changed.viewport = TRUE;
2691 This->updateStateBlock->set.viewport = TRUE;
2692 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2694 /* Handle recording of state blocks */
2695 if (This->isRecordingState) {
2696 TRACE("Recording... not performing anything\n");
2697 return WINED3D_OK;
2700 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2701 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2703 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2704 return WINED3D_OK;
2708 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2710 TRACE("(%p)\n", This);
2711 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2712 return WINED3D_OK;
2715 /*****
2716 * Get / Set Render States
2717 * TODO: Verify against dx9 definitions
2718 *****/
2719 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2722 DWORD oldValue = This->stateBlock->renderState[State];
2724 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2726 This->updateStateBlock->changed.renderState[State] = TRUE;
2727 This->updateStateBlock->set.renderState[State] = TRUE;
2728 This->updateStateBlock->renderState[State] = Value;
2730 /* Handle recording of state blocks */
2731 if (This->isRecordingState) {
2732 TRACE("Recording... not performing anything\n");
2733 return WINED3D_OK;
2736 /* Compared here and not before the assignment to allow proper stateblock recording */
2737 if(Value == oldValue) {
2738 TRACE("Application is setting the old value over, nothing to do\n");
2739 } else {
2740 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2743 return WINED3D_OK;
2746 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2748 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2749 *pValue = This->stateBlock->renderState[State];
2750 return WINED3D_OK;
2753 /*****
2754 * Get / Set Sampler States
2755 * TODO: Verify against dx9 definitions
2756 *****/
2758 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2760 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2763 * SetSampler is designed to allow for more than the standard up to 8 textures
2764 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2765 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2767 * http://developer.nvidia.com/object/General_FAQ.html#t6
2769 * There are two new settings for GForce
2770 * the sampler one:
2771 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2772 * and the texture one:
2773 * GL_MAX_TEXTURE_COORDS_ARB.
2774 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2775 ******************/
2777 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2778 debug_d3dsamplerstate(Type), Type, Value);
2779 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2780 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2781 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2783 /* Handle recording of state blocks */
2784 if (This->isRecordingState) {
2785 TRACE("Recording... not performing anything\n");
2786 return WINED3D_OK;
2789 if(oldValue == Value) {
2790 TRACE("Application is setting the old value over, nothing to do\n");
2791 return WINED3D_OK;
2794 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2796 return WINED3D_OK;
2799 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2801 *Value = This->stateBlock->samplerState[Sampler][Type];
2802 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2804 return WINED3D_OK;
2807 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2810 This->updateStateBlock->set.scissorRect = TRUE;
2811 This->updateStateBlock->changed.scissorRect = TRUE;
2812 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2813 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2814 return WINED3D_OK;
2816 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2818 if(This->isRecordingState) {
2819 TRACE("Recording... not performing anything\n");
2820 return WINED3D_OK;
2823 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2825 return WINED3D_OK;
2828 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2831 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2832 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2833 return WINED3D_OK;
2836 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2838 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2840 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2842 This->updateStateBlock->vertexDecl = pDecl;
2843 This->updateStateBlock->changed.vertexDecl = TRUE;
2844 This->updateStateBlock->set.vertexDecl = TRUE;
2846 if (This->isRecordingState) {
2847 TRACE("Recording... not performing anything\n");
2848 return WINED3D_OK;
2849 } else if(pDecl == oldDecl) {
2850 /* Checked after the assignment to allow proper stateblock recording */
2851 TRACE("Application is setting the old declaration over, nothing to do\n");
2852 return WINED3D_OK;
2855 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2856 return WINED3D_OK;
2859 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2862 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2864 *ppDecl = This->stateBlock->vertexDecl;
2865 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2866 return WINED3D_OK;
2869 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2871 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2873 This->updateStateBlock->vertexShader = pShader;
2874 This->updateStateBlock->changed.vertexShader = TRUE;
2875 This->updateStateBlock->set.vertexShader = TRUE;
2877 if (This->isRecordingState) {
2878 TRACE("Recording... not performing anything\n");
2879 return WINED3D_OK;
2880 } else if(oldShader == pShader) {
2881 /* Checked here to allow proper stateblock recording */
2882 TRACE("App is setting the old shader over, nothing to do\n");
2883 return WINED3D_OK;
2886 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2888 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2890 return WINED3D_OK;
2893 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2896 if (NULL == ppShader) {
2897 return WINED3DERR_INVALIDCALL;
2899 *ppShader = This->stateBlock->vertexShader;
2900 if( NULL != *ppShader)
2901 IWineD3DVertexShader_AddRef(*ppShader);
2903 TRACE("(%p) : returning %p\n", This, *ppShader);
2904 return WINED3D_OK;
2907 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2908 IWineD3DDevice *iface,
2909 UINT start,
2910 CONST BOOL *srcData,
2911 UINT count) {
2913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2914 int i, cnt = min(count, MAX_CONST_B - start);
2916 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2917 iface, srcData, start, count);
2919 if (srcData == NULL || cnt < 0)
2920 return WINED3DERR_INVALIDCALL;
2922 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2923 for (i = 0; i < cnt; i++)
2924 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2926 for (i = start; i < cnt + start; ++i) {
2927 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
2928 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
2931 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2933 return WINED3D_OK;
2936 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2937 IWineD3DDevice *iface,
2938 UINT start,
2939 BOOL *dstData,
2940 UINT count) {
2942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2943 int cnt = min(count, MAX_CONST_B - start);
2945 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2946 iface, dstData, start, count);
2948 if (dstData == NULL || cnt < 0)
2949 return WINED3DERR_INVALIDCALL;
2951 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2952 return WINED3D_OK;
2955 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2956 IWineD3DDevice *iface,
2957 UINT start,
2958 CONST int *srcData,
2959 UINT count) {
2961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2962 int i, cnt = min(count, MAX_CONST_I - start);
2964 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2965 iface, srcData, start, count);
2967 if (srcData == NULL || cnt < 0)
2968 return WINED3DERR_INVALIDCALL;
2970 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2971 for (i = 0; i < cnt; i++)
2972 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2973 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2975 for (i = start; i < cnt + start; ++i) {
2976 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
2977 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
2980 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2982 return WINED3D_OK;
2985 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2986 IWineD3DDevice *iface,
2987 UINT start,
2988 int *dstData,
2989 UINT count) {
2991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2992 int cnt = min(count, MAX_CONST_I - start);
2994 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2995 iface, dstData, start, count);
2997 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2998 return WINED3DERR_INVALIDCALL;
3000 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3001 return WINED3D_OK;
3004 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3005 IWineD3DDevice *iface,
3006 UINT start,
3007 CONST float *srcData,
3008 UINT count) {
3010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3011 int i;
3013 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3014 iface, srcData, start, count);
3016 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3017 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3018 return WINED3DERR_INVALIDCALL;
3020 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3021 if(TRACE_ON(d3d)) {
3022 for (i = 0; i < count; i++)
3023 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3024 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3027 for (i = start; i < count + start; ++i) {
3028 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3029 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3030 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3031 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3032 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3034 ptr->idx[ptr->count++] = i;
3035 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3037 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3040 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3042 return WINED3D_OK;
3045 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3046 IWineD3DDevice *iface,
3047 UINT start,
3048 float *dstData,
3049 UINT count) {
3051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3052 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3054 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3055 iface, dstData, start, count);
3057 if (dstData == NULL || cnt < 0)
3058 return WINED3DERR_INVALIDCALL;
3060 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3061 return WINED3D_OK;
3064 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3065 DWORD i;
3066 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3067 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3071 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3072 DWORD i, tex;
3073 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3074 * it is never called.
3076 * Rules are:
3077 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3078 * that would be really messy and require shader recompilation
3079 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3080 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3081 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3082 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3084 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3085 if(This->oneToOneTexUnitMap) {
3086 TRACE("Not touching 1:1 map\n");
3087 return;
3089 TRACE("Restoring 1:1 texture unit mapping\n");
3090 /* Restore a 1:1 mapping */
3091 for(i = 0; i < MAX_SAMPLERS; i++) {
3092 if(This->texUnitMap[i] != i) {
3093 This->texUnitMap[i] = i;
3094 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3095 markTextureStagesDirty(This, i);
3098 This->oneToOneTexUnitMap = TRUE;
3099 return;
3100 } else {
3101 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3102 * First, see if we can succeed at all
3104 tex = 0;
3105 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3106 if(This->stateBlock->textures[i] == NULL) tex++;
3109 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3110 FIXME("Too many bound textures to support the combiner settings\n");
3111 return;
3114 /* Now work out the mapping */
3115 tex = 0;
3116 This->oneToOneTexUnitMap = FALSE;
3117 WARN("Non 1:1 mapping UNTESTED!\n");
3118 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3119 /* Skip NULL textures */
3120 if (!This->stateBlock->textures[i]) {
3121 /* Map to -1, so the check below doesn't fail if a non-NULL
3122 * texture is set on this stage */
3123 TRACE("Mapping texture stage %d to -1\n", i);
3124 This->texUnitMap[i] = -1;
3126 continue;
3129 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3130 if(This->texUnitMap[i] != tex) {
3131 This->texUnitMap[i] = tex;
3132 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3133 markTextureStagesDirty(This, i);
3136 ++tex;
3141 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3143 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3144 This->updateStateBlock->pixelShader = pShader;
3145 This->updateStateBlock->changed.pixelShader = TRUE;
3146 This->updateStateBlock->set.pixelShader = TRUE;
3148 /* Handle recording of state blocks */
3149 if (This->isRecordingState) {
3150 TRACE("Recording... not performing anything\n");
3153 if (This->isRecordingState) {
3154 TRACE("Recording... not performing anything\n");
3155 return WINED3D_OK;
3158 if(pShader == oldShader) {
3159 TRACE("App is setting the old pixel shader over, nothing to do\n");
3160 return WINED3D_OK;
3163 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3164 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3166 /* Rebuild the texture unit mapping if nvrc's are supported */
3167 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3168 IWineD3DDeviceImpl_FindTexUnitMap(This);
3171 return WINED3D_OK;
3174 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3177 if (NULL == ppShader) {
3178 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3179 return WINED3DERR_INVALIDCALL;
3182 *ppShader = This->stateBlock->pixelShader;
3183 if (NULL != *ppShader) {
3184 IWineD3DPixelShader_AddRef(*ppShader);
3186 TRACE("(%p) : returning %p\n", This, *ppShader);
3187 return WINED3D_OK;
3190 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3191 IWineD3DDevice *iface,
3192 UINT start,
3193 CONST BOOL *srcData,
3194 UINT count) {
3196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3197 int i, cnt = min(count, MAX_CONST_B - start);
3199 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3200 iface, srcData, start, count);
3202 if (srcData == NULL || cnt < 0)
3203 return WINED3DERR_INVALIDCALL;
3205 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3206 for (i = 0; i < cnt; i++)
3207 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3209 for (i = start; i < cnt + start; ++i) {
3210 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3211 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3214 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3216 return WINED3D_OK;
3219 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3220 IWineD3DDevice *iface,
3221 UINT start,
3222 BOOL *dstData,
3223 UINT count) {
3225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3226 int cnt = min(count, MAX_CONST_B - start);
3228 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3229 iface, dstData, start, count);
3231 if (dstData == NULL || cnt < 0)
3232 return WINED3DERR_INVALIDCALL;
3234 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3235 return WINED3D_OK;
3238 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3239 IWineD3DDevice *iface,
3240 UINT start,
3241 CONST int *srcData,
3242 UINT count) {
3244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3245 int i, cnt = min(count, MAX_CONST_I - start);
3247 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3248 iface, srcData, start, count);
3250 if (srcData == NULL || cnt < 0)
3251 return WINED3DERR_INVALIDCALL;
3253 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3254 for (i = 0; i < cnt; i++)
3255 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3256 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3258 for (i = start; i < cnt + start; ++i) {
3259 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3260 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3263 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3265 return WINED3D_OK;
3268 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3269 IWineD3DDevice *iface,
3270 UINT start,
3271 int *dstData,
3272 UINT count) {
3274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3275 int cnt = min(count, MAX_CONST_I - start);
3277 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3278 iface, dstData, start, count);
3280 if (dstData == NULL || cnt < 0)
3281 return WINED3DERR_INVALIDCALL;
3283 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3284 return WINED3D_OK;
3287 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3288 IWineD3DDevice *iface,
3289 UINT start,
3290 CONST float *srcData,
3291 UINT count) {
3293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3294 int i;
3296 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3297 iface, srcData, start, count);
3299 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3300 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3301 return WINED3DERR_INVALIDCALL;
3303 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3304 if(TRACE_ON(d3d)) {
3305 for (i = 0; i < count; i++)
3306 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3307 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3310 for (i = start; i < count + start; ++i) {
3311 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3312 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3313 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3314 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3315 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3317 ptr->idx[ptr->count++] = i;
3318 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3320 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3323 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3325 return WINED3D_OK;
3328 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3329 IWineD3DDevice *iface,
3330 UINT start,
3331 float *dstData,
3332 UINT count) {
3334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3335 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3337 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3338 iface, dstData, start, count);
3340 if (dstData == NULL || cnt < 0)
3341 return WINED3DERR_INVALIDCALL;
3343 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3344 return WINED3D_OK;
3347 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3348 static HRESULT
3349 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3350 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3351 unsigned int i;
3352 DWORD DestFVF = dest->fvf;
3353 WINED3DVIEWPORT vp;
3354 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3355 BOOL doClip;
3356 int numTextures;
3358 if (SrcFVF & WINED3DFVF_NORMAL) {
3359 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3362 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3363 ERR("Source has no position mask\n");
3364 return WINED3DERR_INVALIDCALL;
3367 /* We might access VBOs from this code, so hold the lock */
3368 ENTER_GL();
3370 if (dest->resource.allocatedMemory == NULL) {
3371 /* This may happen if we do direct locking into a vbo. Unlikely,
3372 * but theoretically possible(ddraw processvertices test)
3374 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3375 if(!dest->resource.allocatedMemory) {
3376 LEAVE_GL();
3377 ERR("Out of memory\n");
3378 return E_OUTOFMEMORY;
3380 if(dest->vbo) {
3381 void *src;
3382 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3383 checkGLcall("glBindBufferARB");
3384 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3385 if(src) {
3386 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3388 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3389 checkGLcall("glUnmapBufferARB");
3393 /* Get a pointer into the destination vbo(create one if none exists) and
3394 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3396 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3397 CreateVBO(dest);
3400 if(dest->vbo) {
3401 dest_conv_addr = HeapAlloc(GetProcessHeap(), 0, dwCount * get_flexible_vertex_size(DestFVF));
3402 if(!dest_conv_addr) {
3403 ERR("Out of memory\n");
3404 /* Continue without storing converted vertices */
3406 dest_conv = dest_conv_addr;
3409 /* Should I clip?
3410 * a) WINED3DRS_CLIPPING is enabled
3411 * b) WINED3DVOP_CLIP is passed
3413 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3414 static BOOL warned = FALSE;
3416 * The clipping code is not quite correct. Some things need
3417 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3418 * so disable clipping for now.
3419 * (The graphics in Half-Life are broken, and my processvertices
3420 * test crashes with IDirect3DDevice3)
3421 doClip = TRUE;
3423 doClip = FALSE;
3424 if(!warned) {
3425 warned = TRUE;
3426 FIXME("Clipping is broken and disabled for now\n");
3428 } else doClip = FALSE;
3429 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3431 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3432 WINED3DTS_VIEW,
3433 &view_mat);
3434 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3435 WINED3DTS_PROJECTION,
3436 &proj_mat);
3437 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3438 WINED3DTS_WORLDMATRIX(0),
3439 &world_mat);
3441 TRACE("View mat:\n");
3442 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);
3443 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);
3444 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);
3445 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);
3447 TRACE("Proj mat:\n");
3448 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);
3449 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);
3450 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);
3451 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);
3453 TRACE("World mat:\n");
3454 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);
3455 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);
3456 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);
3457 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);
3459 /* Get the viewport */
3460 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3461 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3462 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3464 multiply_matrix(&mat,&view_mat,&world_mat);
3465 multiply_matrix(&mat,&proj_mat,&mat);
3467 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3469 for (i = 0; i < dwCount; i+= 1) {
3470 unsigned int tex_index;
3472 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3473 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3474 /* The position first */
3475 float *p =
3476 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3477 float x, y, z, rhw;
3478 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3480 /* Multiplication with world, view and projection matrix */
3481 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);
3482 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);
3483 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);
3484 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);
3486 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3488 /* WARNING: The following things are taken from d3d7 and were not yet checked
3489 * against d3d8 or d3d9!
3492 /* Clipping conditions: From
3493 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3495 * A vertex is clipped if it does not match the following requirements
3496 * -rhw < x <= rhw
3497 * -rhw < y <= rhw
3498 * 0 < z <= rhw
3499 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3501 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3502 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3506 if( !doClip ||
3507 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3508 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3509 ( rhw > eps ) ) ) {
3511 /* "Normal" viewport transformation (not clipped)
3512 * 1) The values are divided by rhw
3513 * 2) The y axis is negative, so multiply it with -1
3514 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3515 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3516 * 4) Multiply x with Width/2 and add Width/2
3517 * 5) The same for the height
3518 * 6) Add the viewpoint X and Y to the 2D coordinates and
3519 * The minimum Z value to z
3520 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3522 * Well, basically it's simply a linear transformation into viewport
3523 * coordinates
3526 x /= rhw;
3527 y /= rhw;
3528 z /= rhw;
3530 y *= -1;
3532 x *= vp.Width / 2;
3533 y *= vp.Height / 2;
3534 z *= vp.MaxZ - vp.MinZ;
3536 x += vp.Width / 2 + vp.X;
3537 y += vp.Height / 2 + vp.Y;
3538 z += vp.MinZ;
3540 rhw = 1 / rhw;
3541 } else {
3542 /* That vertex got clipped
3543 * Contrary to OpenGL it is not dropped completely, it just
3544 * undergoes a different calculation.
3546 TRACE("Vertex got clipped\n");
3547 x += rhw;
3548 y += rhw;
3550 x /= 2;
3551 y /= 2;
3553 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3554 * outside of the main vertex buffer memory. That needs some more
3555 * investigation...
3559 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3562 ( (float *) dest_ptr)[0] = x;
3563 ( (float *) dest_ptr)[1] = y;
3564 ( (float *) dest_ptr)[2] = z;
3565 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3567 dest_ptr += 3 * sizeof(float);
3569 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3570 dest_ptr += sizeof(float);
3573 if(dest_conv) {
3574 float w = 1 / rhw;
3575 ( (float *) dest_conv)[0] = x * w;
3576 ( (float *) dest_conv)[1] = y * w;
3577 ( (float *) dest_conv)[2] = z * w;
3578 ( (float *) dest_conv)[3] = w;
3580 dest_conv += 3 * sizeof(float);
3582 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3583 dest_conv += sizeof(float);
3587 if (DestFVF & WINED3DFVF_PSIZE) {
3588 dest_ptr += sizeof(DWORD);
3589 if(dest_conv) dest_conv += sizeof(DWORD);
3591 if (DestFVF & WINED3DFVF_NORMAL) {
3592 float *normal =
3593 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3594 /* AFAIK this should go into the lighting information */
3595 FIXME("Didn't expect the destination to have a normal\n");
3596 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3597 if(dest_conv) {
3598 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3602 if (DestFVF & WINED3DFVF_DIFFUSE) {
3603 DWORD *color_d =
3604 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3605 if(!color_d) {
3606 static BOOL warned = FALSE;
3608 if(!warned) {
3609 ERR("No diffuse color in source, but destination has one\n");
3610 warned = TRUE;
3613 *( (DWORD *) dest_ptr) = 0xffffffff;
3614 dest_ptr += sizeof(DWORD);
3616 if(dest_conv) {
3617 *( (DWORD *) dest_conv) = 0xffffffff;
3618 dest_conv += sizeof(DWORD);
3621 else {
3622 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3623 if(dest_conv) {
3624 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3625 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3626 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3627 dest_conv += sizeof(DWORD);
3632 if (DestFVF & WINED3DFVF_SPECULAR) {
3633 /* What's the color value in the feedback buffer? */
3634 DWORD *color_s =
3635 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3636 if(!color_s) {
3637 static BOOL warned = FALSE;
3639 if(!warned) {
3640 ERR("No specular color in source, but destination has one\n");
3641 warned = TRUE;
3644 *( (DWORD *) dest_ptr) = 0xFF000000;
3645 dest_ptr += sizeof(DWORD);
3647 if(dest_conv) {
3648 *( (DWORD *) dest_conv) = 0xFF000000;
3649 dest_conv += sizeof(DWORD);
3652 else {
3653 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3654 if(dest_conv) {
3655 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3656 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3657 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3658 dest_conv += sizeof(DWORD);
3663 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3664 float *tex_coord =
3665 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3666 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3667 if(!tex_coord) {
3668 ERR("No source texture, but destination requests one\n");
3669 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3670 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3672 else {
3673 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3674 if(dest_conv) {
3675 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3681 if(dest_conv) {
3682 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3683 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3684 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3685 dwCount * get_flexible_vertex_size(DestFVF),
3686 dest_conv_addr));
3687 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3688 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3691 LEAVE_GL();
3693 return WINED3D_OK;
3695 #undef copy_and_next
3697 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
3698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3699 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
3700 WineDirect3DVertexStridedData strided;
3701 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3703 if (!SrcImpl) {
3704 WARN("NULL source vertex buffer\n");
3705 return WINED3DERR_INVALIDCALL;
3708 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3709 * and this call is quite performance critical, so don't call needlessly
3711 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3712 ENTER_GL();
3713 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3714 LEAVE_GL();
3717 /* We don't need the source vbo because this buffer is only used as
3718 * a source for ProcessVertices. Avoid wasting resources by converting the
3719 * buffer and loading the VBO
3721 if(SrcImpl->vbo) {
3722 TRACE("Releasing the source vbo, it won't be needed\n");
3724 if(!SrcImpl->resource.allocatedMemory) {
3725 /* Rescue the data from the buffer */
3726 void *src;
3727 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
3728 if(!SrcImpl->resource.allocatedMemory) {
3729 ERR("Out of memory\n");
3730 return E_OUTOFMEMORY;
3733 ENTER_GL();
3734 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
3735 checkGLcall("glBindBufferARB");
3737 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3738 if(src) {
3739 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
3742 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3743 checkGLcall("glUnmapBufferARB");
3744 } else {
3745 ENTER_GL();
3748 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
3749 checkGLcall("glBindBufferARB");
3750 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
3751 checkGLcall("glDeleteBuffersARB");
3752 LEAVE_GL();
3754 SrcImpl->vbo = 0;
3757 memset(&strided, 0, sizeof(strided));
3758 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0, 0);
3760 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3763 /*****
3764 * Get / Set Texture Stage States
3765 * TODO: Verify against dx9 definitions
3766 *****/
3767 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3768 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3769 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3771 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3773 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3775 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3776 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3777 This->updateStateBlock->textureState[Stage][Type] = Value;
3779 if (This->isRecordingState) {
3780 TRACE("Recording... not performing anything\n");
3781 return WINED3D_OK;
3784 /* Checked after the assignments to allow proper stateblock recording */
3785 if(oldValue == Value) {
3786 TRACE("App is setting the old value over, nothing to do\n");
3787 return WINED3D_OK;
3790 if(Stage > This->stateBlock->lowest_disabled_stage &&
3791 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3792 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3793 * Changes in other states are important on disabled stages too
3795 return WINED3D_OK;
3798 if(Type == WINED3DTSS_COLOROP) {
3799 int i;
3801 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3802 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3803 * they have to be disabled
3805 * The current stage is dirtified below.
3807 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3808 TRACE("Additionally dirtifying stage %d\n", i);
3809 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3811 This->stateBlock->lowest_disabled_stage = Stage;
3812 TRACE("New lowest disabled: %d\n", Stage);
3813 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3814 /* Previously disabled stage enabled. Stages above it may need enabling
3815 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3816 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3818 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3821 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3822 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3823 break;
3825 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3826 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3828 This->stateBlock->lowest_disabled_stage = i;
3829 TRACE("New lowest disabled: %d\n", i);
3831 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3832 /* TODO: Built a stage -> texture unit mapping for register combiners */
3836 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3838 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3839 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3840 * will call FindTexUnitMap too.
3842 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3843 IWineD3DDeviceImpl_FindTexUnitMap(This);
3845 return WINED3D_OK;
3848 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3850 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3851 *pValue = This->updateStateBlock->textureState[Stage][Type];
3852 return WINED3D_OK;
3855 /*****
3856 * Get / Set Texture
3857 *****/
3858 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
3860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3861 IWineD3DBaseTexture *oldTexture;
3863 oldTexture = This->updateStateBlock->textures[Stage];
3864 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
3866 #if 0 /* TODO: check so vertex textures */
3867 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
3868 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
3869 return WINED3D_OK;
3871 #endif
3873 if(pTexture != NULL) {
3874 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
3876 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
3877 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
3878 return WINED3DERR_INVALIDCALL;
3880 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
3883 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
3884 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
3886 This->updateStateBlock->set.textures[Stage] = TRUE;
3887 This->updateStateBlock->changed.textures[Stage] = TRUE;
3888 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
3889 This->updateStateBlock->textures[Stage] = pTexture;
3891 /* Handle recording of state blocks */
3892 if (This->isRecordingState) {
3893 TRACE("Recording... not performing anything\n");
3894 return WINED3D_OK;
3897 if(oldTexture == pTexture) {
3898 TRACE("App is setting the same texture again, nothing to do\n");
3899 return WINED3D_OK;
3902 /** NOTE: MSDN says that setTexture increases the reference count,
3903 * and the the application nust set the texture back to null (or have a leaky application),
3904 * This means we should pass the refcount up to the parent
3905 *******************************/
3906 if (NULL != This->updateStateBlock->textures[Stage]) {
3907 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
3908 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
3910 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
3911 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
3912 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
3913 * so the COLOROP and ALPHAOP have to be dirtified.
3915 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3916 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3918 if(bindCount == 1) {
3919 new->baseTexture.sampler = Stage;
3921 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
3925 if (NULL != oldTexture) {
3926 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
3927 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
3929 IWineD3DBaseTexture_Release(oldTexture);
3930 if(pTexture == NULL && Stage < MAX_TEXTURES) {
3931 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3932 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3935 if(bindCount && old->baseTexture.sampler == Stage) {
3936 int i;
3937 /* Have to do a search for the other sampler(s) where the texture is bound to
3938 * Shouldn't happen as long as apps bind a texture only to one stage
3940 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
3941 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
3942 if(This->updateStateBlock->textures[i] == oldTexture) {
3943 old->baseTexture.sampler = i;
3944 break;
3950 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
3952 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
3953 * pixel shader is used
3955 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3956 IWineD3DDeviceImpl_FindTexUnitMap(This);
3959 return WINED3D_OK;
3962 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3964 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
3966 *ppTexture=This->stateBlock->textures[Stage];
3967 if (*ppTexture)
3968 IWineD3DBaseTexture_AddRef(*ppTexture);
3970 return WINED3D_OK;
3973 /*****
3974 * Get Back Buffer
3975 *****/
3976 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
3977 IWineD3DSurface **ppBackBuffer) {
3978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3979 IWineD3DSwapChain *swapChain;
3980 HRESULT hr;
3982 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
3984 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
3985 if (hr == WINED3D_OK) {
3986 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
3987 IWineD3DSwapChain_Release(swapChain);
3988 } else {
3989 *ppBackBuffer = NULL;
3991 return hr;
3994 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
3995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3996 WARN("(%p) : stub, calling idirect3d for now\n", This);
3997 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4000 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4002 IWineD3DSwapChain *swapChain;
4003 HRESULT hr;
4005 if(iSwapChain > 0) {
4006 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4007 if (hr == WINED3D_OK) {
4008 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4009 IWineD3DSwapChain_Release(swapChain);
4010 } else {
4011 FIXME("(%p) Error getting display mode\n", This);
4013 } else {
4014 /* Don't read the real display mode,
4015 but return the stored mode instead. X11 can't change the color
4016 depth, and some apps are pretty angry if they SetDisplayMode from
4017 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4019 Also don't relay to the swapchain because with ddraw it's possible
4020 that there isn't a swapchain at all */
4021 pMode->Width = This->ddraw_width;
4022 pMode->Height = This->ddraw_height;
4023 pMode->Format = This->ddraw_format;
4024 pMode->RefreshRate = 0;
4025 hr = WINED3D_OK;
4028 return hr;
4031 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4033 TRACE("(%p)->(%p)\n", This, hWnd);
4035 if(This->ddraw_fullscreen) {
4036 if(This->ddraw_window && This->ddraw_window != hWnd) {
4037 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4039 if(hWnd && This->ddraw_window != hWnd) {
4040 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4044 This->ddraw_window = hWnd;
4045 return WINED3D_OK;
4048 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4050 TRACE("(%p)->(%p)\n", This, hWnd);
4052 *hWnd = This->ddraw_window;
4053 return WINED3D_OK;
4056 /*****
4057 * Stateblock related functions
4058 *****/
4060 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4062 IWineD3DStateBlockImpl *object;
4063 HRESULT temp_result;
4064 int i;
4066 TRACE("(%p)\n", This);
4068 if (This->isRecordingState) {
4069 return WINED3DERR_INVALIDCALL;
4072 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4073 if (NULL == object ) {
4074 FIXME("(%p)Error allocating memory for stateblock\n", This);
4075 return E_OUTOFMEMORY;
4077 TRACE("(%p) created object %p\n", This, object);
4078 object->wineD3DDevice= This;
4079 /** FIXME: object->parent = parent; **/
4080 object->parent = NULL;
4081 object->blockType = WINED3DSBT_ALL;
4082 object->ref = 1;
4083 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4085 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4086 list_init(&object->lightMap[i]);
4089 temp_result = allocate_shader_constants(object);
4090 if (WINED3D_OK != temp_result)
4091 return temp_result;
4093 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4094 This->updateStateBlock = object;
4095 This->isRecordingState = TRUE;
4097 TRACE("(%p) recording stateblock %p\n",This , object);
4098 return WINED3D_OK;
4101 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4104 if (!This->isRecordingState) {
4105 FIXME("(%p) not recording! returning error\n", This);
4106 *ppStateBlock = NULL;
4107 return WINED3DERR_INVALIDCALL;
4110 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4111 This->isRecordingState = FALSE;
4112 This->updateStateBlock = This->stateBlock;
4113 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4114 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4115 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4116 return WINED3D_OK;
4119 /*****
4120 * Scene related functions
4121 *****/
4122 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4123 /* At the moment we have no need for any functionality at the beginning
4124 of a scene */
4125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4126 TRACE("(%p)\n", This);
4128 if(This->inScene) {
4129 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4130 return WINED3DERR_INVALIDCALL;
4132 This->inScene = TRUE;
4133 return WINED3D_OK;
4136 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4138 TRACE("(%p)\n", This);
4140 if(!This->inScene) {
4141 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4142 return WINED3DERR_INVALIDCALL;
4145 ENTER_GL();
4146 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4147 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4149 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4150 glFlush();
4151 checkGLcall("glFlush");
4152 LEAVE_GL();
4154 This->inScene = FALSE;
4155 return WINED3D_OK;
4158 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4159 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4160 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4162 IWineD3DSwapChain *swapChain = NULL;
4163 int i;
4164 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4166 TRACE("(%p) Presenting the frame\n", This);
4168 for(i = 0 ; i < swapchains ; i ++) {
4170 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4171 TRACE("presentinng chain %d, %p\n", i, swapChain);
4172 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4173 IWineD3DSwapChain_Release(swapChain);
4176 return WINED3D_OK;
4179 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4180 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4182 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4184 GLbitfield glMask = 0;
4185 unsigned int i;
4186 CONST WINED3DRECT* curRect;
4188 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4189 Count, pRects, Flags, Z, Stencil);
4191 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4192 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4193 /* TODO: What about depth stencil buffers without stencil bits? */
4194 return WINED3DERR_INVALIDCALL;
4197 ENTER_GL();
4198 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4199 * and not the last active one.
4202 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4203 apply_fbo_state(iface);
4206 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
4208 glEnable(GL_SCISSOR_TEST);
4209 checkGLcall("glEnable GL_SCISSOR_TEST");
4210 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4211 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4213 if (Count > 0 && pRects) {
4214 curRect = pRects;
4215 } else {
4216 curRect = NULL;
4219 /* Only set the values up once, as they are not changing */
4220 if (Flags & WINED3DCLEAR_STENCIL) {
4221 glClearStencil(Stencil);
4222 checkGLcall("glClearStencil");
4223 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4224 glStencilMask(0xFFFFFFFF);
4227 if (Flags & WINED3DCLEAR_ZBUFFER) {
4228 glDepthMask(GL_TRUE);
4229 glClearDepth(Z);
4230 checkGLcall("glClearDepth");
4231 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4232 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4235 if (Flags & WINED3DCLEAR_TARGET) {
4236 TRACE("Clearing screen with glClear to color %x\n", Color);
4237 glClearColor(D3DCOLOR_R(Color),
4238 D3DCOLOR_G(Color),
4239 D3DCOLOR_B(Color),
4240 D3DCOLOR_A(Color));
4241 checkGLcall("glClearColor");
4243 /* Clear ALL colors! */
4244 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4245 glMask = glMask | GL_COLOR_BUFFER_BIT;
4248 if (!curRect) {
4249 /* In drawable flag is set below */
4251 glScissor(This->stateBlock->viewport.X,
4252 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4253 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4254 This->stateBlock->viewport.Width,
4255 This->stateBlock->viewport.Height);
4256 checkGLcall("glScissor");
4257 glClear(glMask);
4258 checkGLcall("glClear");
4259 } else {
4260 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4261 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4263 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4264 curRect[0].x2 < target->currentDesc.Width ||
4265 curRect[0].y2 < target->currentDesc.Height) {
4266 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4267 blt_to_drawable(This, target);
4271 /* Now process each rect in turn */
4272 for (i = 0; i < Count; i++) {
4273 /* Note gl uses lower left, width/height */
4274 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4275 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4276 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4277 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4279 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4280 * The rectangle is not cleared, no error is returned, but further rectanlges are
4281 * still cleared if they are valid
4283 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4284 TRACE("Rectangle with negative dimensions, ignoring\n");
4285 continue;
4288 if(This->render_offscreen) {
4289 glScissor(curRect[i].x1, curRect[i].y1,
4290 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4291 } else {
4292 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4293 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4295 checkGLcall("glScissor");
4297 glClear(glMask);
4298 checkGLcall("glClear");
4302 /* Restore the old values (why..?) */
4303 if (Flags & WINED3DCLEAR_STENCIL) {
4304 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4306 if (Flags & WINED3DCLEAR_TARGET) {
4307 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4308 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4309 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4310 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4311 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4314 LEAVE_GL();
4316 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4317 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4319 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4320 target->Flags |= SFLAG_INTEXTURE;
4321 target->Flags &= ~SFLAG_INSYSMEM;
4322 } else {
4323 target->Flags |= SFLAG_INDRAWABLE;
4324 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4326 return WINED3D_OK;
4329 /*****
4330 * Drawing functions
4331 *****/
4332 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4333 UINT PrimitiveCount) {
4335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4337 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4338 debug_d3dprimitivetype(PrimitiveType),
4339 StartVertex, PrimitiveCount);
4341 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4342 if(This->stateBlock->streamIsUP) {
4343 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4344 This->stateBlock->streamIsUP = FALSE;
4347 if(This->stateBlock->loadBaseVertexIndex != 0) {
4348 This->stateBlock->loadBaseVertexIndex = 0;
4349 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4351 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4352 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4353 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4354 return WINED3D_OK;
4357 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4358 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4359 WINED3DPRIMITIVETYPE PrimitiveType,
4360 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4363 UINT idxStride = 2;
4364 IWineD3DIndexBuffer *pIB;
4365 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4366 GLuint vbo;
4368 if(This->stateBlock->streamIsUP) {
4369 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4370 This->stateBlock->streamIsUP = FALSE;
4372 pIB = This->stateBlock->pIndexData;
4373 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4375 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4376 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4377 minIndex, NumVertices, startIndex, primCount);
4379 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4380 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4381 idxStride = 2;
4382 } else {
4383 idxStride = 4;
4386 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4387 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4388 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4391 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4392 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4394 return WINED3D_OK;
4397 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4398 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4399 UINT VertexStreamZeroStride) {
4400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4402 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4403 debug_d3dprimitivetype(PrimitiveType),
4404 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4406 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4407 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4408 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4409 This->stateBlock->streamIsUP = TRUE;
4410 This->stateBlock->loadBaseVertexIndex = 0;
4412 /* TODO: Only mark dirty if drawing from a different UP address */
4413 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4415 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4416 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4418 /* MSDN specifies stream zero settings must be set to NULL */
4419 This->stateBlock->streamStride[0] = 0;
4420 This->stateBlock->streamSource[0] = NULL;
4422 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4423 * the new stream sources or use UP drawing again
4425 return WINED3D_OK;
4428 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4429 UINT MinVertexIndex, UINT NumVertices,
4430 UINT PrimitiveCount, CONST void* pIndexData,
4431 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4432 UINT VertexStreamZeroStride) {
4433 int idxStride;
4434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4436 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4437 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4438 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4439 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4441 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4442 idxStride = 2;
4443 } else {
4444 idxStride = 4;
4447 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4448 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4449 This->stateBlock->streamIsUP = TRUE;
4450 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4452 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4453 This->stateBlock->baseVertexIndex = 0;
4454 This->stateBlock->loadBaseVertexIndex = 0;
4455 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4456 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4457 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4459 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4461 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4462 This->stateBlock->streamSource[0] = NULL;
4463 This->stateBlock->streamStride[0] = 0;
4464 This->stateBlock->pIndexData = NULL;
4465 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4466 * SetStreamSource to specify a vertex buffer
4469 return WINED3D_OK;
4472 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4475 /* Mark the state dirty until we have nicer tracking
4476 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4477 * that value.
4479 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4480 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4481 This->stateBlock->baseVertexIndex = 0;
4482 This->up_strided = DrawPrimStrideData;
4483 This->stateBlock->streamIsUP = TRUE;
4484 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4485 This->up_strided = NULL;
4486 return WINED3D_OK;
4488 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4489 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4490 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4491 HRESULT hr = WINED3D_OK;
4492 WINED3DRESOURCETYPE sourceType;
4493 WINED3DRESOURCETYPE destinationType;
4494 int i ,levels;
4496 /* TODO: think about moving the code into IWineD3DBaseTexture */
4498 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4500 /* verify that the source and destination textures aren't NULL */
4501 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4502 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4503 This, pSourceTexture, pDestinationTexture);
4504 hr = WINED3DERR_INVALIDCALL;
4507 if (pSourceTexture == pDestinationTexture) {
4508 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4509 This, pSourceTexture, pDestinationTexture);
4510 hr = WINED3DERR_INVALIDCALL;
4512 /* Verify that the source and destination textures are the same type */
4513 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4514 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4516 if (sourceType != destinationType) {
4517 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4518 This);
4519 hr = WINED3DERR_INVALIDCALL;
4522 /* check that both textures have the identical numbers of levels */
4523 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4524 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4525 hr = WINED3DERR_INVALIDCALL;
4528 if (WINED3D_OK == hr) {
4530 /* Make sure that the destination texture is loaded */
4531 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4533 /* Update every surface level of the texture */
4534 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4536 switch (sourceType) {
4537 case WINED3DRTYPE_TEXTURE:
4539 IWineD3DSurface *srcSurface;
4540 IWineD3DSurface *destSurface;
4542 for (i = 0 ; i < levels ; ++i) {
4543 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4544 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4545 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4546 IWineD3DSurface_Release(srcSurface);
4547 IWineD3DSurface_Release(destSurface);
4548 if (WINED3D_OK != hr) {
4549 WARN("(%p) : Call to update surface failed\n", This);
4550 return hr;
4554 break;
4555 case WINED3DRTYPE_CUBETEXTURE:
4557 IWineD3DSurface *srcSurface;
4558 IWineD3DSurface *destSurface;
4559 WINED3DCUBEMAP_FACES faceType;
4561 for (i = 0 ; i < levels ; ++i) {
4562 /* Update each cube face */
4563 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4564 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4565 if (WINED3D_OK != hr) {
4566 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4567 } else {
4568 TRACE("Got srcSurface %p\n", srcSurface);
4570 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4571 if (WINED3D_OK != hr) {
4572 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4573 } else {
4574 TRACE("Got desrSurface %p\n", destSurface);
4576 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4577 IWineD3DSurface_Release(srcSurface);
4578 IWineD3DSurface_Release(destSurface);
4579 if (WINED3D_OK != hr) {
4580 WARN("(%p) : Call to update surface failed\n", This);
4581 return hr;
4586 break;
4587 #if 0 /* TODO: Add support for volume textures */
4588 case WINED3DRTYPE_VOLUMETEXTURE:
4590 IWineD3DVolume srcVolume = NULL;
4591 IWineD3DSurface destVolume = NULL;
4593 for (i = 0 ; i < levels ; ++i) {
4594 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4595 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4596 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4597 IWineD3DVolume_Release(srcSurface);
4598 IWineD3DVolume_Release(destSurface);
4599 if (WINED3D_OK != hr) {
4600 WARN("(%p) : Call to update volume failed\n", This);
4601 return hr;
4605 break;
4606 #endif
4607 default:
4608 FIXME("(%p) : Unsupported source and destination type\n", This);
4609 hr = WINED3DERR_INVALIDCALL;
4613 return hr;
4616 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4617 IWineD3DSwapChain *swapChain;
4618 HRESULT hr;
4619 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4620 if(hr == WINED3D_OK) {
4621 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4622 IWineD3DSwapChain_Release(swapChain);
4624 return hr;
4627 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4629 /* return a sensible default */
4630 *pNumPasses = 1;
4631 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4632 FIXME("(%p) : stub\n", This);
4633 return WINED3D_OK;
4636 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4638 int j;
4639 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4640 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4641 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4642 return WINED3DERR_INVALIDCALL;
4644 for (j = 0; j < 256; ++j) {
4645 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4646 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4647 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4648 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4650 TRACE("(%p) : returning\n", This);
4651 return WINED3D_OK;
4654 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4656 int j;
4657 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4658 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4659 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4660 return WINED3DERR_INVALIDCALL;
4662 for (j = 0; j < 256; ++j) {
4663 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4664 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4665 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4666 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4668 TRACE("(%p) : returning\n", This);
4669 return WINED3D_OK;
4672 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4674 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4675 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4676 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4677 return WINED3DERR_INVALIDCALL;
4679 /*TODO: stateblocks */
4680 This->currentPalette = PaletteNumber;
4681 TRACE("(%p) : returning\n", This);
4682 return WINED3D_OK;
4685 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4687 if (PaletteNumber == NULL) {
4688 WARN("(%p) : returning Invalid Call\n", This);
4689 return WINED3DERR_INVALIDCALL;
4691 /*TODO: stateblocks */
4692 *PaletteNumber = This->currentPalette;
4693 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4694 return WINED3D_OK;
4697 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4699 static BOOL showFixmes = TRUE;
4700 if (showFixmes) {
4701 FIXME("(%p) : stub\n", This);
4702 showFixmes = FALSE;
4705 This->softwareVertexProcessing = bSoftware;
4706 return WINED3D_OK;
4710 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4712 static BOOL showFixmes = TRUE;
4713 if (showFixmes) {
4714 FIXME("(%p) : stub\n", This);
4715 showFixmes = FALSE;
4717 return This->softwareVertexProcessing;
4721 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4723 IWineD3DSwapChain *swapChain;
4724 HRESULT hr;
4726 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4728 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4729 if(hr == WINED3D_OK){
4730 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4731 IWineD3DSwapChain_Release(swapChain);
4732 }else{
4733 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4735 return hr;
4739 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4741 static BOOL showfixmes = TRUE;
4742 if(nSegments != 0.0f) {
4743 if( showfixmes) {
4744 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4745 showfixmes = FALSE;
4748 return WINED3D_OK;
4751 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4753 static BOOL showfixmes = TRUE;
4754 if( showfixmes) {
4755 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4756 showfixmes = FALSE;
4758 return 0.0f;
4761 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4763 /** TODO: remove casts to IWineD3DSurfaceImpl
4764 * NOTE: move code to surface to accomplish this
4765 ****************************************/
4766 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4767 int srcWidth, srcHeight;
4768 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4769 WINED3DFORMAT destFormat, srcFormat;
4770 UINT destSize;
4771 int srcLeft, destLeft, destTop;
4772 WINED3DPOOL srcPool, destPool;
4773 int offset = 0;
4774 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4775 glDescriptor *glDescription = NULL;
4777 WINED3DSURFACE_DESC winedesc;
4779 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4780 memset(&winedesc, 0, sizeof(winedesc));
4781 winedesc.Width = &srcSurfaceWidth;
4782 winedesc.Height = &srcSurfaceHeight;
4783 winedesc.Pool = &srcPool;
4784 winedesc.Format = &srcFormat;
4786 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4788 winedesc.Width = &destSurfaceWidth;
4789 winedesc.Height = &destSurfaceHeight;
4790 winedesc.Pool = &destPool;
4791 winedesc.Format = &destFormat;
4792 winedesc.Size = &destSize;
4794 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4796 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4797 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4798 return WINED3DERR_INVALIDCALL;
4801 if (destFormat == WINED3DFMT_UNKNOWN) {
4802 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4803 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4805 /* Get the update surface description */
4806 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4809 ENTER_GL();
4811 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4813 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
4814 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4815 checkGLcall("glActiveTextureARB");
4818 /* Make sure the surface is loaded and up to date */
4819 IWineD3DSurface_PreLoad(pDestinationSurface);
4821 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4823 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4824 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4825 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
4826 srcLeft = pSourceRect ? pSourceRect->left : 0;
4827 destLeft = pDestPoint ? pDestPoint->x : 0;
4828 destTop = pDestPoint ? pDestPoint->y : 0;
4831 /* This function doesn't support compressed textures
4832 the pitch is just bytesPerPixel * width */
4833 if(srcWidth != srcSurfaceWidth || srcLeft ){
4834 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
4835 offset += srcLeft * pSrcSurface->bytesPerPixel;
4836 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4838 /* TODO DXT formats */
4840 if(pSourceRect != NULL && pSourceRect->top != 0){
4841 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
4843 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4844 ,This
4845 ,glDescription->level
4846 ,destLeft
4847 ,destTop
4848 ,srcWidth
4849 ,srcHeight
4850 ,glDescription->glFormat
4851 ,glDescription->glType
4852 ,IWineD3DSurface_GetData(pSourceSurface)
4855 /* Sanity check */
4856 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
4858 /* need to lock the surface to get the data */
4859 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
4862 /* TODO: Cube and volume support */
4863 if(rowoffset != 0){
4864 /* not a whole row so we have to do it a line at a time */
4865 int j;
4867 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
4868 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
4870 for(j = destTop ; j < (srcHeight + destTop) ; j++){
4872 glTexSubImage2D(glDescription->target
4873 ,glDescription->level
4874 ,destLeft
4876 ,srcWidth
4878 ,glDescription->glFormat
4879 ,glDescription->glType
4880 ,data /* could be quicker using */
4882 data += rowoffset;
4885 } else { /* Full width, so just write out the whole texture */
4887 if (WINED3DFMT_DXT1 == destFormat ||
4888 WINED3DFMT_DXT2 == destFormat ||
4889 WINED3DFMT_DXT3 == destFormat ||
4890 WINED3DFMT_DXT4 == destFormat ||
4891 WINED3DFMT_DXT5 == destFormat) {
4892 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
4893 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
4894 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
4895 FIXME("Updating part of a compressed texture is not supported at the moment\n");
4896 } if (destFormat != srcFormat) {
4897 FIXME("Updating mixed format compressed texture is not curretly support\n");
4898 } else {
4899 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
4900 glDescription->level,
4901 glDescription->glFormatInternal,
4902 srcWidth,
4903 srcHeight,
4905 destSize,
4906 IWineD3DSurface_GetData(pSourceSurface));
4908 } else {
4909 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
4913 } else {
4914 glTexSubImage2D(glDescription->target
4915 ,glDescription->level
4916 ,destLeft
4917 ,destTop
4918 ,srcWidth
4919 ,srcHeight
4920 ,glDescription->glFormat
4921 ,glDescription->glType
4922 ,IWineD3DSurface_GetData(pSourceSurface)
4926 checkGLcall("glTexSubImage2D");
4928 LEAVE_GL();
4930 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
4931 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
4932 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
4934 return WINED3D_OK;
4937 /* Implementation details at http://developer.nvidia.com/attach/6494
4939 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
4940 hmm.. no longer supported use
4941 OpenGL evaluators or tessellate surfaces within your application.
4944 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
4945 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
4946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4947 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
4948 FIXME("(%p) : Stub\n", This);
4949 return WINED3D_OK;
4953 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
4954 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
4955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4956 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
4957 FIXME("(%p) : Stub\n", This);
4958 return WINED3D_OK;
4961 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
4962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4963 TRACE("(%p) Handle(%d)\n", This, Handle);
4964 FIXME("(%p) : Stub\n", This);
4965 return WINED3D_OK;
4968 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
4969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4970 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
4971 DDBLTFX BltFx;
4972 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
4974 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
4975 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
4976 return WINED3DERR_INVALIDCALL;
4979 /* Just forward this to the DirectDraw blitting engine */
4980 memset(&BltFx, 0, sizeof(BltFx));
4981 BltFx.dwSize = sizeof(BltFx);
4982 BltFx.u5.dwFillColor = color;
4983 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
4986 /* rendertarget and deptth stencil functions */
4987 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
4988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4990 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
4991 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
4992 return WINED3DERR_INVALIDCALL;
4995 *ppRenderTarget = This->render_targets[RenderTargetIndex];
4996 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
4997 /* Note inc ref on returned surface */
4998 if(*ppRenderTarget != NULL)
4999 IWineD3DSurface_AddRef(*ppRenderTarget);
5000 return WINED3D_OK;
5003 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5005 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5006 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5007 IWineD3DSwapChainImpl *Swapchain;
5008 HRESULT hr;
5010 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5012 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5013 if(hr != WINED3D_OK) {
5014 ERR("Can't get the swapchain\n");
5015 return hr;
5018 /* Make sure to release the swapchain */
5019 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5021 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5022 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5023 return WINED3DERR_INVALIDCALL;
5025 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5026 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5027 return WINED3DERR_INVALIDCALL;
5030 if(Swapchain->frontBuffer != Front) {
5031 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5033 if(Swapchain->frontBuffer)
5034 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5035 Swapchain->frontBuffer = Front;
5037 if(Swapchain->frontBuffer) {
5038 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5042 if(Back && !Swapchain->backBuffer) {
5043 /* We need memory for the back buffer array - only one back buffer this way */
5044 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5045 if(!Swapchain->backBuffer) {
5046 ERR("Out of memory\n");
5047 return E_OUTOFMEMORY;
5051 if(Swapchain->backBuffer[0] != Back) {
5052 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5054 /* What to do about the context here in the case of multithreading? Not sure.
5055 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5057 ENTER_GL();
5058 if(!Swapchain->backBuffer[0]) {
5059 /* GL was told to draw to the front buffer at creation,
5060 * undo that
5062 glDrawBuffer(GL_BACK);
5063 checkGLcall("glDrawBuffer(GL_BACK)");
5064 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5065 Swapchain->presentParms.BackBufferCount = 1;
5066 } else if (!Back) {
5067 /* That makes problems - disable for now */
5068 /* glDrawBuffer(GL_FRONT); */
5069 checkGLcall("glDrawBuffer(GL_FRONT)");
5070 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5071 Swapchain->presentParms.BackBufferCount = 0;
5073 LEAVE_GL();
5075 if(Swapchain->backBuffer[0])
5076 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5077 Swapchain->backBuffer[0] = Back;
5079 if(Swapchain->backBuffer[0]) {
5080 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5081 } else {
5082 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5087 return WINED3D_OK;
5090 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5092 *ppZStencilSurface = This->depthStencilBuffer;
5093 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5095 if(*ppZStencilSurface != NULL) {
5096 /* Note inc ref on returned surface */
5097 IWineD3DSurface_AddRef(*ppZStencilSurface);
5099 return WINED3D_OK;
5102 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5105 if (!*fbo) {
5106 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5107 checkGLcall("glGenFramebuffersEXT()");
5109 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5110 checkGLcall("glBindFramebuffer()");
5113 /* TODO: Handle stencil attachments */
5114 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5116 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5118 TRACE("Set depth stencil to %p\n", depth_stencil);
5120 if (depth_stencil_impl) {
5121 if (depth_stencil_impl->current_renderbuffer) {
5122 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5123 checkGLcall("glFramebufferRenderbufferEXT()");
5124 } else {
5125 GLenum texttarget, target;
5126 GLint old_binding = 0;
5128 texttarget = depth_stencil_impl->glDescription.target;
5129 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5130 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5132 IWineD3DSurface_PreLoad(depth_stencil);
5134 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5135 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5136 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5137 glBindTexture(target, old_binding);
5139 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5140 checkGLcall("glFramebufferTexture2DEXT()");
5142 } else {
5143 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5144 checkGLcall("glFramebufferTexture2DEXT()");
5148 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5149 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5150 GLenum texttarget, target;
5151 GLint old_binding;
5153 texttarget = surface_impl->glDescription.target;
5154 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5155 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5157 IWineD3DSurface_PreLoad(surface);
5159 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5160 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5161 glBindTexture(target, old_binding);
5163 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5165 checkGLcall("attach_surface_fbo");
5168 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5170 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5172 TRACE("Set render target %u to %p\n", idx, render_target);
5174 if (rtimpl) {
5175 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5176 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5177 } else {
5178 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5179 checkGLcall("glFramebufferTexture2DEXT()");
5181 This->draw_buffers[idx] = GL_NONE;
5185 static void check_fbo_status(IWineD3DDevice *iface) {
5186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5187 GLenum status;
5189 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5190 switch(status) {
5191 case GL_FRAMEBUFFER_COMPLETE_EXT: TRACE("FBO complete.\n"); break;
5192 default: FIXME("FBO status %#x.\n", status); break;
5196 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5198 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5199 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5201 if (!ds_impl) return FALSE;
5203 if (ds_impl->current_renderbuffer) {
5204 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5205 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5208 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5209 rt_impl->pow2Height != ds_impl->pow2Height);
5212 void apply_fbo_state(IWineD3DDevice *iface) {
5213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5214 unsigned int i;
5216 if (This->render_offscreen) {
5217 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5219 /* Apply render targets */
5220 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5221 IWineD3DSurface *render_target = This->render_targets[i];
5222 if (This->fbo_color_attachments[i] != render_target) {
5223 set_render_target_fbo(iface, i, render_target);
5224 This->fbo_color_attachments[i] = render_target;
5228 /* Apply depth targets */
5229 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5230 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5231 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5233 if (This->stencilBufferTarget) {
5234 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5236 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5237 This->fbo_depth_attachment = This->stencilBufferTarget;
5240 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5241 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5242 checkGLcall("glDrawBuffers()");
5244 } else {
5245 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5248 check_fbo_status(iface);
5251 static BOOL is_onscreen(IWineD3DSurface *target) {
5252 HRESULT hr;
5253 void *tmp;
5255 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, &tmp);
5256 if (SUCCEEDED(hr)) {
5257 IWineD3DSwapChain_Release((IUnknown *)tmp);
5258 return TRUE;
5261 return FALSE;
5264 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, const WINED3DRECT *src_rect,
5265 IWineD3DSurface *dst_surface, const WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5267 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5268 GLenum gl_filter;
5270 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x)\n",
5271 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter);
5273 switch (filter) {
5274 case WINED3DTEXF_LINEAR:
5275 gl_filter = GL_LINEAR;
5276 break;
5278 default:
5279 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5280 case WINED3DTEXF_NONE:
5281 case WINED3DTEXF_POINT:
5282 gl_filter = GL_NEAREST;
5283 break;
5286 /* Attach src surface to src fbo */
5287 if (is_onscreen(src_surface)) {
5288 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5289 flip = !flip;
5290 } else {
5291 IWineD3DSurface_PreLoad(src_surface);
5292 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5293 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5296 /* Attach dst surface to dst fbo */
5297 if (is_onscreen(dst_surface)) {
5298 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5299 flip = !flip;
5300 } else {
5301 IWineD3DSurface_PreLoad(dst_surface);
5302 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5303 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5306 if (flip) {
5307 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5308 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5309 } else {
5310 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5311 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5314 if (This->render_offscreen) {
5315 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5316 } else {
5317 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5318 checkGLcall("glBindFramebuffer()");
5322 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5324 WINED3DVIEWPORT viewport;
5326 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5328 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5329 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5330 return WINED3DERR_INVALIDCALL;
5333 /* MSDN says that null disables the render target
5334 but a device must always be associated with a render target
5335 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5337 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5338 for more details
5340 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5341 FIXME("Trying to set render target 0 to NULL\n");
5342 return WINED3DERR_INVALIDCALL;
5344 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5345 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);
5346 return WINED3DERR_INVALIDCALL;
5349 /* If we are trying to set what we already have, don't bother */
5350 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5351 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5352 return WINED3D_OK;
5354 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5355 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5356 This->render_targets[RenderTargetIndex] = pRenderTarget;
5358 /* Render target 0 is special */
5359 if(RenderTargetIndex == 0) {
5360 /* Finally, reset the viewport as the MSDN states. */
5361 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5362 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5363 viewport.X = 0;
5364 viewport.Y = 0;
5365 viewport.MaxZ = 1.0f;
5366 viewport.MinZ = 0.0f;
5367 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5368 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5369 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5373 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5374 * ctx properly.
5375 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5376 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5378 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5380 return WINED3D_OK;
5383 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5385 HRESULT hr = WINED3D_OK;
5386 IWineD3DSurface *tmp;
5388 TRACE("(%p) Swapping z-buffer\n",This);
5390 if (pNewZStencil == This->stencilBufferTarget) {
5391 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5392 } else {
5393 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5394 * depending on the renter target implementation being used.
5395 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5396 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5397 * stencil buffer and incure an extra memory overhead
5398 ******************************************************/
5400 tmp = This->stencilBufferTarget;
5401 This->stencilBufferTarget = pNewZStencil;
5402 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5403 /* should we be calling the parent or the wined3d surface? */
5404 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5405 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5406 hr = WINED3D_OK;
5408 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5409 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5410 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5411 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5412 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5416 return hr;
5419 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5420 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5422 /* TODO: the use of Impl is deprecated. */
5423 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5425 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5427 /* some basic validation checks */
5428 if(This->cursorTexture) {
5429 ENTER_GL();
5430 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5431 glDeleteTextures(1, &This->cursorTexture);
5432 LEAVE_GL();
5433 This->cursorTexture = 0;
5436 if(pCursorBitmap) {
5437 WINED3DLOCKED_RECT rect;
5439 /* MSDN: Cursor must be A8R8G8B8 */
5440 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5441 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5442 return WINED3DERR_INVALIDCALL;
5445 /* MSDN: Cursor must be smaller than the display mode */
5446 if(pSur->currentDesc.Width > This->ddraw_width ||
5447 pSur->currentDesc.Height > This->ddraw_height) {
5448 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);
5449 return WINED3DERR_INVALIDCALL;
5452 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5454 /* Do not store the surface's pointer because the application may release
5455 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5456 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5458 This->cursorWidth = pSur->currentDesc.Width;
5459 This->cursorHeight = pSur->currentDesc.Height;
5460 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5462 const PixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8);
5463 char *mem, *bits = (char *)rect.pBits;
5464 GLint intfmt = tableEntry->glInternal;
5465 GLint format = tableEntry->glFormat;
5466 GLint type = tableEntry->glType;
5467 INT height = This->cursorHeight;
5468 INT width = This->cursorWidth;
5469 INT bpp = tableEntry->bpp;
5470 INT i;
5472 /* Reformat the texture memory (pitch and width can be different) */
5473 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5474 for(i = 0; i < height; i++)
5475 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5476 IWineD3DSurface_UnlockRect(pCursorBitmap);
5477 ENTER_GL();
5478 /* Make sure that a proper texture unit is selected */
5479 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5480 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5481 checkGLcall("glActiveTextureARB");
5483 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5484 /* Create a new cursor texture */
5485 glGenTextures(1, &This->cursorTexture);
5486 checkGLcall("glGenTextures");
5487 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5488 checkGLcall("glBindTexture");
5489 /* Copy the bitmap memory into the cursor texture */
5490 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5491 HeapFree(GetProcessHeap(), 0, mem);
5492 checkGLcall("glTexImage2D");
5493 LEAVE_GL();
5495 else
5497 FIXME("A cursor texture was not returned.\n");
5498 This->cursorTexture = 0;
5503 This->xHotSpot = XHotSpot;
5504 This->yHotSpot = YHotSpot;
5505 return WINED3D_OK;
5508 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5510 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5512 This->xScreenSpace = XScreenSpace;
5513 This->yScreenSpace = YScreenSpace;
5515 return;
5519 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5521 BOOL oldVisible = This->bCursorVisible;
5522 POINT pt;
5524 TRACE("(%p) : visible(%d)\n", This, bShow);
5526 if(This->cursorTexture)
5527 This->bCursorVisible = bShow;
5529 * When ShowCursor is first called it should make the cursor appear at the OS's last
5530 * known cursor position. Because of this, some applications just repetitively call
5531 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5533 GetCursorPos(&pt);
5534 This->xScreenSpace = pt.x;
5535 This->yScreenSpace = pt.y;
5537 return oldVisible;
5540 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5542 TRACE("(%p) : state (%u)\n", This, This->state);
5543 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5544 switch (This->state) {
5545 case WINED3D_OK:
5546 return WINED3D_OK;
5547 case WINED3DERR_DEVICELOST:
5549 ResourceList *resourceList = This->resources;
5550 while (NULL != resourceList) {
5551 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5552 return WINED3DERR_DEVICENOTRESET;
5553 resourceList = resourceList->next;
5555 return WINED3DERR_DEVICELOST;
5557 case WINED3DERR_DRIVERINTERNALERROR:
5558 return WINED3DERR_DRIVERINTERNALERROR;
5561 /* Unknown state */
5562 return WINED3DERR_DRIVERINTERNALERROR;
5566 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5568 /** FIXME: Resource tracking needs to be done,
5569 * The closes we can do to this is set the priorities of all managed textures low
5570 * and then reset them.
5571 ***********************************************************/
5572 FIXME("(%p) : stub\n", This);
5573 return WINED3D_OK;
5576 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5577 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5579 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5580 if(surface->Flags & SFLAG_DIBSECTION) {
5581 /* Release the DC */
5582 SelectObject(surface->hDC, surface->dib.holdbitmap);
5583 DeleteDC(surface->hDC);
5584 /* Release the DIB section */
5585 DeleteObject(surface->dib.DIBsection);
5586 surface->dib.bitmap_data = NULL;
5587 surface->resource.allocatedMemory = NULL;
5588 surface->Flags &= ~SFLAG_DIBSECTION;
5590 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5591 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5592 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5593 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5594 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5595 } else {
5596 surface->pow2Width = surface->pow2Height = 1;
5597 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5598 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5600 if(surface->glDescription.textureName) {
5601 ENTER_GL();
5602 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5603 glDeleteTextures(1, &surface->glDescription.textureName);
5604 LEAVE_GL();
5605 surface->glDescription.textureName = 0;
5606 surface->Flags &= ~SFLAG_CLIENT;
5608 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5609 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5610 surface->Flags |= SFLAG_NONPOW2;
5611 } else {
5612 surface->Flags &= ~SFLAG_NONPOW2;
5614 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5615 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5618 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5620 IWineD3DSwapChainImpl *swapchain;
5621 HRESULT hr;
5622 BOOL DisplayModeChanged = FALSE;
5623 WINED3DDISPLAYMODE mode;
5624 TRACE("(%p)\n", This);
5626 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5627 if(FAILED(hr)) {
5628 ERR("Failed to get the first implicit swapchain\n");
5629 return hr;
5632 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5633 * on an existing gl context, so there's no real need for recreation.
5635 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5637 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5639 TRACE("New params:\n");
5640 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5641 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5642 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5643 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5644 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
5645 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
5646 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
5647 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
5648 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
5649 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5650 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
5651 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
5652 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
5654 /* No special treatment of these parameters. Just store them */
5655 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
5656 swapchain->presentParms.Flags = pPresentationParameters->Flags;
5657 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
5658 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
5660 /* What to do about these? */
5661 if(pPresentationParameters->BackBufferCount != 0 &&
5662 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
5663 ERR("Cannot change the back buffer count yet\n");
5665 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5666 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5667 ERR("Cannot change the back buffer format yet\n");
5669 if(pPresentationParameters->hDeviceWindow != NULL &&
5670 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
5671 ERR("Cannot change the device window yet\n");
5673 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
5674 ERR("What do do about a changed auto depth stencil parameter?\n");
5677 if(pPresentationParameters->Windowed) {
5678 mode.Width = swapchain->orig_width;
5679 mode.Height = swapchain->orig_height;
5680 mode.RefreshRate = 0;
5681 mode.Format = swapchain->presentParms.BackBufferFormat;
5682 } else {
5683 mode.Width = pPresentationParameters->BackBufferWidth;
5684 mode.Height = pPresentationParameters->BackBufferHeight;
5685 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
5686 mode.Format = swapchain->presentParms.BackBufferFormat;
5689 /* Should Width == 800 && Height == 0 set 800x600? */
5690 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
5691 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
5692 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5694 WINED3DVIEWPORT vp;
5695 int i;
5697 vp.X = 0;
5698 vp.Y = 0;
5699 vp.Width = pPresentationParameters->BackBufferWidth;
5700 vp.Height = pPresentationParameters->BackBufferHeight;
5701 vp.MinZ = 0;
5702 vp.MaxZ = 1;
5704 if(!pPresentationParameters->Windowed) {
5705 DisplayModeChanged = TRUE;
5707 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
5708 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
5710 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
5711 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
5712 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
5715 /* Now set the new viewport */
5716 IWineD3DDevice_SetViewport(iface, &vp);
5719 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
5720 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
5721 DisplayModeChanged) {
5723 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
5724 if(!pPresentationParameters->Windowed) {
5725 IWineD3DDevice_SetFullscreen(iface, TRUE);
5728 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
5730 /* Switching out of fullscreen mode? First set the original res, then change the window */
5731 if(pPresentationParameters->Windowed) {
5732 IWineD3DDevice_SetFullscreen(iface, FALSE);
5734 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
5737 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5738 return WINED3D_OK;
5741 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
5742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5743 /** FIXME: always true at the moment **/
5744 if(!bEnableDialogs) {
5745 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
5747 return WINED3D_OK;
5751 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
5752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5753 TRACE("(%p) : pParameters %p\n", This, pParameters);
5755 *pParameters = This->createParms;
5756 return WINED3D_OK;
5759 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
5760 IWineD3DSwapChain *swapchain;
5761 HRESULT hrc = WINED3D_OK;
5763 TRACE("Relaying to swapchain\n");
5765 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5766 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
5767 IWineD3DSwapChain_Release(swapchain);
5769 return;
5772 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
5773 IWineD3DSwapChain *swapchain;
5774 HRESULT hrc = WINED3D_OK;
5776 TRACE("Relaying to swapchain\n");
5778 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5779 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
5780 IWineD3DSwapChain_Release(swapchain);
5782 return;
5786 /** ********************************************************
5787 * Notification functions
5788 ** ********************************************************/
5789 /** This function must be called in the release of a resource when ref == 0,
5790 * the contents of resource must still be correct,
5791 * any handels to other resource held by the caller must be closed
5792 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
5793 *****************************************************/
5794 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5796 ResourceList* resourceList;
5798 TRACE("(%p) : resource %p\n", This, resource);
5799 #if 0
5800 EnterCriticalSection(&resourceStoreCriticalSection);
5801 #endif
5802 /* add a new texture to the frot of the linked list */
5803 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
5804 resourceList->resource = resource;
5806 /* Get the old head */
5807 resourceList->next = This->resources;
5809 This->resources = resourceList;
5810 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
5812 #if 0
5813 LeaveCriticalSection(&resourceStoreCriticalSection);
5814 #endif
5815 return;
5818 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5820 ResourceList* resourceList = NULL;
5821 ResourceList* previousResourceList = NULL;
5823 TRACE("(%p) : resource %p\n", This, resource);
5825 #if 0
5826 EnterCriticalSection(&resourceStoreCriticalSection);
5827 #endif
5828 resourceList = This->resources;
5830 while (resourceList != NULL) {
5831 if(resourceList->resource == resource) break;
5832 previousResourceList = resourceList;
5833 resourceList = resourceList->next;
5836 if (resourceList == NULL) {
5837 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
5838 #if 0
5839 LeaveCriticalSection(&resourceStoreCriticalSection);
5840 #endif
5841 return;
5842 } else {
5843 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
5845 /* make sure we don't leave a hole in the list */
5846 if (previousResourceList != NULL) {
5847 previousResourceList->next = resourceList->next;
5848 } else {
5849 This->resources = resourceList->next;
5852 #if 0
5853 LeaveCriticalSection(&resourceStoreCriticalSection);
5854 #endif
5855 return;
5859 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
5860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5861 int counter;
5863 TRACE("(%p) : resource %p\n", This, resource);
5864 switch(IWineD3DResource_GetType(resource)){
5865 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
5866 case WINED3DRTYPE_SURFACE: {
5867 unsigned int i;
5869 /* Cleanup any FBO attachments */
5870 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5871 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
5872 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5873 set_render_target_fbo(iface, i, NULL);
5874 This->fbo_color_attachments[i] = NULL;
5877 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
5878 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5879 set_depth_stencil_fbo(iface, NULL);
5880 This->fbo_depth_attachment = NULL;
5883 break;
5886 case WINED3DRTYPE_TEXTURE:
5887 case WINED3DRTYPE_CUBETEXTURE:
5888 case WINED3DRTYPE_VOLUMETEXTURE:
5889 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
5890 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5891 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5892 This->stateBlock->textures[counter] = NULL;
5894 if (This->updateStateBlock != This->stateBlock ){
5895 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5896 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5897 This->updateStateBlock->textures[counter] = NULL;
5901 break;
5902 case WINED3DRTYPE_VOLUME:
5903 /* TODO: nothing really? */
5904 break;
5905 case WINED3DRTYPE_VERTEXBUFFER:
5906 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
5908 int streamNumber;
5909 TRACE("Cleaning up stream pointers\n");
5911 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
5912 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
5913 FINDOUT: should changes.streamSource[StreamNumber] be set ?
5915 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5916 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
5917 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5918 This->updateStateBlock->streamSource[streamNumber] = 0;
5919 /* Set changed flag? */
5922 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) */
5923 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
5924 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5925 This->stateBlock->streamSource[streamNumber] = 0;
5928 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
5929 else { /* This shouldn't happen */
5930 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
5932 #endif
5936 break;
5937 case WINED3DRTYPE_INDEXBUFFER:
5938 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
5939 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5940 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5941 This->updateStateBlock->pIndexData = NULL;
5944 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
5945 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5946 This->stateBlock->pIndexData = NULL;
5950 break;
5951 default:
5952 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
5953 break;
5957 /* Remove the resoruce from the resourceStore */
5958 IWineD3DDeviceImpl_RemoveResource(iface, resource);
5960 TRACE("Resource released\n");
5964 /**********************************************************
5965 * IWineD3DDevice VTbl follows
5966 **********************************************************/
5968 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
5970 /*** IUnknown methods ***/
5971 IWineD3DDeviceImpl_QueryInterface,
5972 IWineD3DDeviceImpl_AddRef,
5973 IWineD3DDeviceImpl_Release,
5974 /*** IWineD3DDevice methods ***/
5975 IWineD3DDeviceImpl_GetParent,
5976 /*** Creation methods**/
5977 IWineD3DDeviceImpl_CreateVertexBuffer,
5978 IWineD3DDeviceImpl_CreateIndexBuffer,
5979 IWineD3DDeviceImpl_CreateStateBlock,
5980 IWineD3DDeviceImpl_CreateSurface,
5981 IWineD3DDeviceImpl_CreateTexture,
5982 IWineD3DDeviceImpl_CreateVolumeTexture,
5983 IWineD3DDeviceImpl_CreateVolume,
5984 IWineD3DDeviceImpl_CreateCubeTexture,
5985 IWineD3DDeviceImpl_CreateQuery,
5986 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
5987 IWineD3DDeviceImpl_CreateVertexDeclaration,
5988 IWineD3DDeviceImpl_CreateVertexShader,
5989 IWineD3DDeviceImpl_CreatePixelShader,
5990 IWineD3DDeviceImpl_CreatePalette,
5991 /*** Odd functions **/
5992 IWineD3DDeviceImpl_Init3D,
5993 IWineD3DDeviceImpl_Uninit3D,
5994 IWineD3DDeviceImpl_SetFullscreen,
5995 IWineD3DDeviceImpl_SetMultithreaded,
5996 IWineD3DDeviceImpl_EvictManagedResources,
5997 IWineD3DDeviceImpl_GetAvailableTextureMem,
5998 IWineD3DDeviceImpl_GetBackBuffer,
5999 IWineD3DDeviceImpl_GetCreationParameters,
6000 IWineD3DDeviceImpl_GetDeviceCaps,
6001 IWineD3DDeviceImpl_GetDirect3D,
6002 IWineD3DDeviceImpl_GetDisplayMode,
6003 IWineD3DDeviceImpl_SetDisplayMode,
6004 IWineD3DDeviceImpl_GetHWND,
6005 IWineD3DDeviceImpl_SetHWND,
6006 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6007 IWineD3DDeviceImpl_GetRasterStatus,
6008 IWineD3DDeviceImpl_GetSwapChain,
6009 IWineD3DDeviceImpl_Reset,
6010 IWineD3DDeviceImpl_SetDialogBoxMode,
6011 IWineD3DDeviceImpl_SetCursorProperties,
6012 IWineD3DDeviceImpl_SetCursorPosition,
6013 IWineD3DDeviceImpl_ShowCursor,
6014 IWineD3DDeviceImpl_TestCooperativeLevel,
6015 /*** Getters and setters **/
6016 IWineD3DDeviceImpl_SetClipPlane,
6017 IWineD3DDeviceImpl_GetClipPlane,
6018 IWineD3DDeviceImpl_SetClipStatus,
6019 IWineD3DDeviceImpl_GetClipStatus,
6020 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6021 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6022 IWineD3DDeviceImpl_SetDepthStencilSurface,
6023 IWineD3DDeviceImpl_GetDepthStencilSurface,
6024 IWineD3DDeviceImpl_SetFVF,
6025 IWineD3DDeviceImpl_GetFVF,
6026 IWineD3DDeviceImpl_SetGammaRamp,
6027 IWineD3DDeviceImpl_GetGammaRamp,
6028 IWineD3DDeviceImpl_SetIndices,
6029 IWineD3DDeviceImpl_GetIndices,
6030 IWineD3DDeviceImpl_SetBasevertexIndex,
6031 IWineD3DDeviceImpl_SetLight,
6032 IWineD3DDeviceImpl_GetLight,
6033 IWineD3DDeviceImpl_SetLightEnable,
6034 IWineD3DDeviceImpl_GetLightEnable,
6035 IWineD3DDeviceImpl_SetMaterial,
6036 IWineD3DDeviceImpl_GetMaterial,
6037 IWineD3DDeviceImpl_SetNPatchMode,
6038 IWineD3DDeviceImpl_GetNPatchMode,
6039 IWineD3DDeviceImpl_SetPaletteEntries,
6040 IWineD3DDeviceImpl_GetPaletteEntries,
6041 IWineD3DDeviceImpl_SetPixelShader,
6042 IWineD3DDeviceImpl_GetPixelShader,
6043 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6044 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6045 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6046 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6047 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6048 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6049 IWineD3DDeviceImpl_SetRenderState,
6050 IWineD3DDeviceImpl_GetRenderState,
6051 IWineD3DDeviceImpl_SetRenderTarget,
6052 IWineD3DDeviceImpl_GetRenderTarget,
6053 IWineD3DDeviceImpl_SetFrontBackBuffers,
6054 IWineD3DDeviceImpl_SetSamplerState,
6055 IWineD3DDeviceImpl_GetSamplerState,
6056 IWineD3DDeviceImpl_SetScissorRect,
6057 IWineD3DDeviceImpl_GetScissorRect,
6058 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6059 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6060 IWineD3DDeviceImpl_SetStreamSource,
6061 IWineD3DDeviceImpl_GetStreamSource,
6062 IWineD3DDeviceImpl_SetStreamSourceFreq,
6063 IWineD3DDeviceImpl_GetStreamSourceFreq,
6064 IWineD3DDeviceImpl_SetTexture,
6065 IWineD3DDeviceImpl_GetTexture,
6066 IWineD3DDeviceImpl_SetTextureStageState,
6067 IWineD3DDeviceImpl_GetTextureStageState,
6068 IWineD3DDeviceImpl_SetTransform,
6069 IWineD3DDeviceImpl_GetTransform,
6070 IWineD3DDeviceImpl_SetVertexDeclaration,
6071 IWineD3DDeviceImpl_GetVertexDeclaration,
6072 IWineD3DDeviceImpl_SetVertexShader,
6073 IWineD3DDeviceImpl_GetVertexShader,
6074 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6075 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6076 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6077 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6078 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6079 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6080 IWineD3DDeviceImpl_SetViewport,
6081 IWineD3DDeviceImpl_GetViewport,
6082 IWineD3DDeviceImpl_MultiplyTransform,
6083 IWineD3DDeviceImpl_ValidateDevice,
6084 IWineD3DDeviceImpl_ProcessVertices,
6085 /*** State block ***/
6086 IWineD3DDeviceImpl_BeginStateBlock,
6087 IWineD3DDeviceImpl_EndStateBlock,
6088 /*** Scene management ***/
6089 IWineD3DDeviceImpl_BeginScene,
6090 IWineD3DDeviceImpl_EndScene,
6091 IWineD3DDeviceImpl_Present,
6092 IWineD3DDeviceImpl_Clear,
6093 /*** Drawing ***/
6094 IWineD3DDeviceImpl_DrawPrimitive,
6095 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6096 IWineD3DDeviceImpl_DrawPrimitiveUP,
6097 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6098 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6099 IWineD3DDeviceImpl_DrawRectPatch,
6100 IWineD3DDeviceImpl_DrawTriPatch,
6101 IWineD3DDeviceImpl_DeletePatch,
6102 IWineD3DDeviceImpl_ColorFill,
6103 IWineD3DDeviceImpl_UpdateTexture,
6104 IWineD3DDeviceImpl_UpdateSurface,
6105 IWineD3DDeviceImpl_GetFrontBufferData,
6106 /*** object tracking ***/
6107 IWineD3DDeviceImpl_ResourceReleased
6111 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6112 WINED3DRS_ALPHABLENDENABLE ,
6113 WINED3DRS_ALPHAFUNC ,
6114 WINED3DRS_ALPHAREF ,
6115 WINED3DRS_ALPHATESTENABLE ,
6116 WINED3DRS_BLENDOP ,
6117 WINED3DRS_COLORWRITEENABLE ,
6118 WINED3DRS_DESTBLEND ,
6119 WINED3DRS_DITHERENABLE ,
6120 WINED3DRS_FILLMODE ,
6121 WINED3DRS_FOGDENSITY ,
6122 WINED3DRS_FOGEND ,
6123 WINED3DRS_FOGSTART ,
6124 WINED3DRS_LASTPIXEL ,
6125 WINED3DRS_SHADEMODE ,
6126 WINED3DRS_SRCBLEND ,
6127 WINED3DRS_STENCILENABLE ,
6128 WINED3DRS_STENCILFAIL ,
6129 WINED3DRS_STENCILFUNC ,
6130 WINED3DRS_STENCILMASK ,
6131 WINED3DRS_STENCILPASS ,
6132 WINED3DRS_STENCILREF ,
6133 WINED3DRS_STENCILWRITEMASK ,
6134 WINED3DRS_STENCILZFAIL ,
6135 WINED3DRS_TEXTUREFACTOR ,
6136 WINED3DRS_WRAP0 ,
6137 WINED3DRS_WRAP1 ,
6138 WINED3DRS_WRAP2 ,
6139 WINED3DRS_WRAP3 ,
6140 WINED3DRS_WRAP4 ,
6141 WINED3DRS_WRAP5 ,
6142 WINED3DRS_WRAP6 ,
6143 WINED3DRS_WRAP7 ,
6144 WINED3DRS_ZENABLE ,
6145 WINED3DRS_ZFUNC ,
6146 WINED3DRS_ZWRITEENABLE
6149 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6150 WINED3DTSS_ADDRESSW ,
6151 WINED3DTSS_ALPHAARG0 ,
6152 WINED3DTSS_ALPHAARG1 ,
6153 WINED3DTSS_ALPHAARG2 ,
6154 WINED3DTSS_ALPHAOP ,
6155 WINED3DTSS_BUMPENVLOFFSET ,
6156 WINED3DTSS_BUMPENVLSCALE ,
6157 WINED3DTSS_BUMPENVMAT00 ,
6158 WINED3DTSS_BUMPENVMAT01 ,
6159 WINED3DTSS_BUMPENVMAT10 ,
6160 WINED3DTSS_BUMPENVMAT11 ,
6161 WINED3DTSS_COLORARG0 ,
6162 WINED3DTSS_COLORARG1 ,
6163 WINED3DTSS_COLORARG2 ,
6164 WINED3DTSS_COLOROP ,
6165 WINED3DTSS_RESULTARG ,
6166 WINED3DTSS_TEXCOORDINDEX ,
6167 WINED3DTSS_TEXTURETRANSFORMFLAGS
6170 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6171 WINED3DSAMP_ADDRESSU ,
6172 WINED3DSAMP_ADDRESSV ,
6173 WINED3DSAMP_ADDRESSW ,
6174 WINED3DSAMP_BORDERCOLOR ,
6175 WINED3DSAMP_MAGFILTER ,
6176 WINED3DSAMP_MINFILTER ,
6177 WINED3DSAMP_MIPFILTER ,
6178 WINED3DSAMP_MIPMAPLODBIAS ,
6179 WINED3DSAMP_MAXMIPLEVEL ,
6180 WINED3DSAMP_MAXANISOTROPY ,
6181 WINED3DSAMP_SRGBTEXTURE ,
6182 WINED3DSAMP_ELEMENTINDEX
6185 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6186 WINED3DRS_AMBIENT ,
6187 WINED3DRS_AMBIENTMATERIALSOURCE ,
6188 WINED3DRS_CLIPPING ,
6189 WINED3DRS_CLIPPLANEENABLE ,
6190 WINED3DRS_COLORVERTEX ,
6191 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6192 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6193 WINED3DRS_FOGDENSITY ,
6194 WINED3DRS_FOGEND ,
6195 WINED3DRS_FOGSTART ,
6196 WINED3DRS_FOGTABLEMODE ,
6197 WINED3DRS_FOGVERTEXMODE ,
6198 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6199 WINED3DRS_LIGHTING ,
6200 WINED3DRS_LOCALVIEWER ,
6201 WINED3DRS_MULTISAMPLEANTIALIAS ,
6202 WINED3DRS_MULTISAMPLEMASK ,
6203 WINED3DRS_NORMALIZENORMALS ,
6204 WINED3DRS_PATCHEDGESTYLE ,
6205 WINED3DRS_POINTSCALE_A ,
6206 WINED3DRS_POINTSCALE_B ,
6207 WINED3DRS_POINTSCALE_C ,
6208 WINED3DRS_POINTSCALEENABLE ,
6209 WINED3DRS_POINTSIZE ,
6210 WINED3DRS_POINTSIZE_MAX ,
6211 WINED3DRS_POINTSIZE_MIN ,
6212 WINED3DRS_POINTSPRITEENABLE ,
6213 WINED3DRS_RANGEFOGENABLE ,
6214 WINED3DRS_SPECULARMATERIALSOURCE ,
6215 WINED3DRS_TWEENFACTOR ,
6216 WINED3DRS_VERTEXBLEND
6219 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6220 WINED3DTSS_TEXCOORDINDEX ,
6221 WINED3DTSS_TEXTURETRANSFORMFLAGS
6224 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6225 WINED3DSAMP_DMAPOFFSET
6228 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6229 DWORD rep = StateTable[state].representative;
6230 DWORD idx;
6231 BYTE shift;
6232 UINT i;
6233 WineD3DContext *context;
6235 if(!rep) return;
6236 for(i = 0; i < This->numContexts; i++) {
6237 context = This->contexts[i];
6238 if(isStateDirty(context, rep)) continue;
6240 context->dirtyArray[context->numDirtyEntries++] = rep;
6241 idx = rep >> 5;
6242 shift = rep & 0x1f;
6243 context->isStateDirty[idx] |= (1 << shift);