wined3d: Cleanup device_map_fixed_function_samplers().
[wine/gsoc_dplay.git] / dlls / wined3d / device.c
blob5d3a7ce2f278c051e010d9298a3ae0932ad73928
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
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
60 X11DRV_GET_FONT, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 static inline Display *get_display( HDC hdc )
66 Display *display;
67 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
69 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
70 sizeof(display), (LPSTR)&display )) display = NULL;
71 return display;
74 /* static function declarations */
75 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
77 /* helper macros */
78 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
80 #define D3DCREATEOBJECTINSTANCE(object, type) { \
81 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
82 D3DMEMCHECK(object, pp##type); \
83 object->lpVtbl = &IWineD3D##type##_Vtbl; \
84 object->wineD3DDevice = This; \
85 object->parent = parent; \
86 object->ref = 1; \
87 *pp##type = (IWineD3D##type *) object; \
90 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
91 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
92 D3DMEMCHECK(object, pp##type); \
93 object->lpVtbl = &IWineD3D##type##_Vtbl; \
94 object->parent = parent; \
95 object->ref = 1; \
96 object->baseShader.device = (IWineD3DDevice*) This; \
97 list_init(&object->baseShader.linked_programs); \
98 *pp##type = (IWineD3D##type *) object; \
101 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
102 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
103 D3DMEMCHECK(object, pp##type); \
104 object->lpVtbl = &IWineD3D##type##_Vtbl; \
105 object->resource.wineD3DDevice = This; \
106 object->resource.parent = parent; \
107 object->resource.resourceType = d3dtype; \
108 object->resource.ref = 1; \
109 object->resource.pool = Pool; \
110 object->resource.format = Format; \
111 object->resource.usage = Usage; \
112 object->resource.size = _size; \
113 list_init(&object->resource.privateData); \
114 /* Check that we have enough video ram left */ \
115 if (Pool == WINED3DPOOL_DEFAULT) { \
116 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
117 WARN("Out of 'bogus' video memory\n"); \
118 HeapFree(GetProcessHeap(), 0, object); \
119 *pp##type = NULL; \
120 return WINED3DERR_OUTOFVIDEOMEMORY; \
122 globalChangeGlRam(_size); \
124 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
125 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
126 FIXME("Out of memory!\n"); \
127 HeapFree(GetProcessHeap(), 0, object); \
128 *pp##type = NULL; \
129 return WINED3DERR_OUTOFVIDEOMEMORY; \
131 *pp##type = (IWineD3D##type *) object; \
132 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
133 TRACE("(%p) : Created resource %p\n", This, object); \
136 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
137 _basetexture.levels = Levels; \
138 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
139 _basetexture.LOD = 0; \
140 _basetexture.dirty = TRUE; \
141 _basetexture.is_srgb = FALSE; \
142 _basetexture.srgb_mode_change_count = 0; \
145 /**********************************************************
146 * Global variable / Constants follow
147 **********************************************************/
148 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
150 /**********************************************************
151 * IUnknown parts follows
152 **********************************************************/
154 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
158 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
159 if (IsEqualGUID(riid, &IID_IUnknown)
160 || IsEqualGUID(riid, &IID_IWineD3DBase)
161 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
162 IUnknown_AddRef(iface);
163 *ppobj = This;
164 return S_OK;
166 *ppobj = NULL;
167 return E_NOINTERFACE;
170 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
172 ULONG refCount = InterlockedIncrement(&This->ref);
174 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
175 return refCount;
178 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
180 ULONG refCount = InterlockedDecrement(&This->ref);
182 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
184 if (!refCount) {
185 if (This->fbo) {
186 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
188 if (This->src_fbo) {
189 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
191 if (This->dst_fbo) {
192 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
195 HeapFree(GetProcessHeap(), 0, This->render_targets);
196 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
197 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
199 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
201 /* TODO: Clean up all the surfaces and textures! */
202 /* NOTE: You must release the parent if the object was created via a callback
203 ** ***************************/
205 /* Release the update stateblock */
206 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
207 if(This->updateStateBlock != This->stateBlock)
208 FIXME("(%p) Something's still holding the Update stateblock\n",This);
210 This->updateStateBlock = NULL;
211 { /* because were not doing proper internal refcounts releasing the primary state block
212 causes recursion with the extra checks in ResourceReleased, to avoid this we have
213 to set this->stateBlock = NULL; first */
214 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
215 This->stateBlock = NULL;
217 /* Release the stateblock */
218 if(IWineD3DStateBlock_Release(stateBlock) > 0){
219 FIXME("(%p) Something's still holding the Update stateblock\n",This);
223 if (This->resources != NULL ) {
224 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
225 dumpResources(This->resources);
228 if(This->contexts) ERR("Context array not freed!\n");
229 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
230 This->haveHardwareCursor = FALSE;
232 IWineD3D_Release(This->wineD3D);
233 This->wineD3D = NULL;
234 HeapFree(GetProcessHeap(), 0, This);
235 TRACE("Freed device %p\n", This);
236 This = NULL;
238 return refCount;
241 /**********************************************************
242 * IWineD3DDevice implementation follows
243 **********************************************************/
244 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
246 *pParent = This->parent;
247 IUnknown_AddRef(This->parent);
248 return WINED3D_OK;
251 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
252 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
253 GLenum error, glUsage;
254 DWORD vboUsage = object->resource.usage;
255 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
256 WARN("Creating a vbo failed once, not trying again\n");
257 return;
260 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
262 ENTER_GL();
263 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
264 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
266 /* Make sure that the gl error is cleared. Do not use checkGLcall
267 * here because checkGLcall just prints a fixme and continues. However,
268 * if an error during VBO creation occurs we can fall back to non-vbo operation
269 * with full functionality(but performance loss)
271 while(glGetError() != GL_NO_ERROR);
273 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
274 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
275 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
276 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
277 * to check if the rhw and color values are in the correct format.
280 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
281 error = glGetError();
282 if(object->vbo == 0 || error != GL_NO_ERROR) {
283 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
284 goto error;
287 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
288 error = glGetError();
289 if(error != GL_NO_ERROR) {
290 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
291 goto error;
294 /* Don't use static, because dx apps tend to update the buffer
295 * quite often even if they specify 0 usage. Because we always keep the local copy
296 * we never read from the vbo and can create a write only opengl buffer.
298 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
299 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
300 case WINED3DUSAGE_DYNAMIC:
301 TRACE("Gl usage = GL_STREAM_DRAW\n");
302 glUsage = GL_STREAM_DRAW_ARB;
303 break;
304 case WINED3DUSAGE_WRITEONLY:
305 default:
306 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
307 glUsage = GL_DYNAMIC_DRAW_ARB;
308 break;
311 /* Reserve memory for the buffer. The amount of data won't change
312 * so we are safe with calling glBufferData once with a NULL ptr and
313 * calling glBufferSubData on updates
315 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
316 error = glGetError();
317 if(error != GL_NO_ERROR) {
318 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
319 goto error;
322 LEAVE_GL();
324 return;
325 error:
326 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
327 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
328 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
329 object->vbo = 0;
330 object->Flags |= VBFLAG_VBOCREATEFAIL;
331 LEAVE_GL();
332 return;
335 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
336 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
337 IUnknown *parent) {
338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
339 IWineD3DVertexBufferImpl *object;
340 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
341 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
342 BOOL conv;
344 if(Size == 0) {
345 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
346 *ppVertexBuffer = NULL;
347 return WINED3DERR_INVALIDCALL;
350 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
352 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
353 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
355 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
356 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
358 object->fvf = FVF;
360 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
361 * drawStridedFast (half-life 2).
363 * Basically converting the vertices in the buffer is quite expensive, and observations
364 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
365 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
367 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
368 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
369 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
370 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
371 * dx7 apps.
372 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
373 * more. In this call we can convert dx7 buffers too.
375 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
376 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
377 (dxVersion > 7 || !conv) ) {
378 CreateVBO(object);
380 return WINED3D_OK;
383 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
384 GLenum error, glUsage;
385 TRACE("Creating VBO for Index Buffer %p\n", object);
387 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
388 * restored on the next draw
390 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
392 ENTER_GL();
393 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
394 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
396 while(glGetError());
398 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
399 error = glGetError();
400 if(error != GL_NO_ERROR || object->vbo == 0) {
401 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
402 goto out;
405 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
406 error = glGetError();
407 if(error != GL_NO_ERROR) {
408 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
409 goto out;
412 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
413 * copy no readback will be needed
415 glUsage = GL_STATIC_DRAW_ARB;
416 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
417 error = glGetError();
418 if(error != GL_NO_ERROR) {
419 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
420 goto out;
422 LEAVE_GL();
423 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
424 return;
426 out:
427 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
428 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
429 LEAVE_GL();
430 object->vbo = 0;
433 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
434 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
435 HANDLE *sharedHandle, IUnknown *parent) {
436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
437 IWineD3DIndexBufferImpl *object;
438 TRACE("(%p) Creating index buffer\n", This);
440 /* Allocate the storage for the device */
441 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
443 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
444 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
447 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
448 CreateIndexBufferVBO(This, object);
451 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
452 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
453 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
455 return WINED3D_OK;
458 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
461 IWineD3DStateBlockImpl *object;
462 int i, j;
463 HRESULT temp_result;
465 D3DCREATEOBJECTINSTANCE(object, StateBlock)
466 object->blockType = Type;
468 for(i = 0; i < LIGHTMAP_SIZE; i++) {
469 list_init(&object->lightMap[i]);
472 /* Special case - Used during initialization to produce a placeholder stateblock
473 so other functions called can update a state block */
474 if (Type == WINED3DSBT_INIT) {
475 /* Don't bother increasing the reference count otherwise a device will never
476 be freed due to circular dependencies */
477 return WINED3D_OK;
480 temp_result = allocate_shader_constants(object);
481 if (WINED3D_OK != temp_result)
482 return temp_result;
484 /* Otherwise, might as well set the whole state block to the appropriate values */
485 if (This->stateBlock != NULL)
486 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
487 else
488 memset(object->streamFreq, 1, sizeof(object->streamFreq));
490 /* Reset the ref and type after kludging it */
491 object->wineD3DDevice = This;
492 object->ref = 1;
493 object->blockType = Type;
495 TRACE("Updating changed flags appropriate for type %d\n", Type);
497 if (Type == WINED3DSBT_ALL) {
499 TRACE("ALL => Pretend everything has changed\n");
500 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
502 /* Lights are not part of the changed / set structure */
503 for(j = 0; j < LIGHTMAP_SIZE; j++) {
504 struct list *e;
505 LIST_FOR_EACH(e, &object->lightMap[j]) {
506 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
507 light->changed = TRUE;
508 light->enabledChanged = TRUE;
511 } else if (Type == WINED3DSBT_PIXELSTATE) {
513 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
514 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
516 object->changed.pixelShader = TRUE;
518 /* Pixel Shader Constants */
519 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
520 object->changed.pixelShaderConstantsF[i] = TRUE;
521 for (i = 0; i < MAX_CONST_B; ++i)
522 object->changed.pixelShaderConstantsB[i] = TRUE;
523 for (i = 0; i < MAX_CONST_I; ++i)
524 object->changed.pixelShaderConstantsI[i] = TRUE;
526 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
527 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
529 for (j = 0; j < MAX_TEXTURES; j++) {
530 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
531 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
534 for (j = 0 ; j < 16; j++) {
535 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
537 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
541 } else if (Type == WINED3DSBT_VERTEXSTATE) {
543 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
544 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
546 object->changed.vertexShader = TRUE;
548 /* Vertex Shader Constants */
549 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
550 object->changed.vertexShaderConstantsF[i] = TRUE;
551 for (i = 0; i < MAX_CONST_B; ++i)
552 object->changed.vertexShaderConstantsB[i] = TRUE;
553 for (i = 0; i < MAX_CONST_I; ++i)
554 object->changed.vertexShaderConstantsI[i] = TRUE;
556 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
557 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
559 for (j = 0; j < MAX_TEXTURES; j++) {
560 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
561 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
564 for (j = 0 ; j < 16; j++){
565 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
566 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
570 for(j = 0; j < LIGHTMAP_SIZE; j++) {
571 struct list *e;
572 LIST_FOR_EACH(e, &object->lightMap[j]) {
573 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
574 light->changed = TRUE;
575 light->enabledChanged = TRUE;
578 } else {
579 FIXME("Unrecognized state block type %d\n", Type);
582 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
583 return WINED3D_OK;
586 /* ************************************
587 MSDN:
588 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
590 Discard
591 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
593 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.
595 ******************************** */
597 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) {
598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
599 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
600 unsigned int pow2Width, pow2Height;
601 unsigned int Size = 1;
602 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
603 TRACE("(%p) Create surface\n",This);
605 /** FIXME: Check ranges on the inputs are valid
606 * MSDN
607 * MultisampleQuality
608 * [in] Quality level. The valid range is between zero and one less than the level
609 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
610 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
611 * values of paired render targets, depth stencil surfaces, and the MultiSample type
612 * must all match.
613 *******************************/
617 * TODO: Discard MSDN
618 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
620 * If this flag is set, the contents of the depth stencil buffer will be
621 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
622 * with a different depth surface.
624 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
625 ***************************/
627 if(MultisampleQuality < 0) {
628 FIXME("Invalid multisample level %d\n", MultisampleQuality);
629 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
632 if(MultisampleQuality > 0) {
633 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
634 MultisampleQuality=0;
637 /** FIXME: Check that the format is supported
638 * by the device.
639 *******************************/
641 /* Non-power2 support */
642 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
643 pow2Width = Width;
644 pow2Height = Height;
645 } else {
646 /* Find the nearest pow2 match */
647 pow2Width = pow2Height = 1;
648 while (pow2Width < Width) pow2Width <<= 1;
649 while (pow2Height < Height) pow2Height <<= 1;
652 if (pow2Width > Width || pow2Height > Height) {
653 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
654 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
655 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
656 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
657 This, Width, Height);
658 return WINED3DERR_NOTAVAILABLE;
662 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
663 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
664 * space!
665 *********************************/
666 if (WINED3DFMT_UNKNOWN == Format) {
667 Size = 0;
668 } else if (Format == WINED3DFMT_DXT1) {
669 /* DXT1 is half byte per pixel */
670 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
672 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
673 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
674 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
675 } else {
676 /* The pitch is a multiple of 4 bytes */
677 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
678 Size *= Height;
681 /** Create and initialise the surface resource **/
682 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
683 /* "Standalone" surface */
684 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
686 object->currentDesc.Width = Width;
687 object->currentDesc.Height = Height;
688 object->currentDesc.MultiSampleType = MultiSample;
689 object->currentDesc.MultiSampleQuality = MultisampleQuality;
691 /* Setup some glformat defaults */
692 object->glDescription.glFormat = tableEntry->glFormat;
693 object->glDescription.glFormatInternal = tableEntry->glInternal;
694 object->glDescription.glType = tableEntry->glType;
696 object->glDescription.textureName = 0;
697 object->glDescription.level = Level;
698 object->glDescription.target = GL_TEXTURE_2D;
700 /* Internal data */
701 object->pow2Width = pow2Width;
702 object->pow2Height = pow2Height;
704 /* Flags */
705 object->Flags = 0;
706 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
707 object->Flags |= Discard ? SFLAG_DISCARD : 0;
708 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
709 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
712 if (WINED3DFMT_UNKNOWN != Format) {
713 object->bytesPerPixel = tableEntry->bpp;
714 } else {
715 object->bytesPerPixel = 0;
718 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
720 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
722 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
723 * this function is too deep to need to care about things like this.
724 * Levels need to be checked too, and possibly Type since they all affect what can be done.
725 * ****************************************/
726 switch(Pool) {
727 case WINED3DPOOL_SCRATCH:
728 if(!Lockable)
729 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
730 "which are mutually exclusive, setting lockable to TRUE\n");
731 Lockable = TRUE;
732 break;
733 case WINED3DPOOL_SYSTEMMEM:
734 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
735 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
736 case WINED3DPOOL_MANAGED:
737 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
738 "Usage of DYNAMIC which are mutually exclusive, not doing "
739 "anything just telling you.\n");
740 break;
741 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
742 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
743 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
744 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
745 break;
746 default:
747 FIXME("(%p) Unknown pool %d\n", This, Pool);
748 break;
751 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
752 FIXME("Trying to create a render target that isn't in the default pool\n");
755 /* mark the texture as dirty so that it gets loaded first time around*/
756 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
757 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
758 This, Width, Height, Format, debug_d3dformat(Format),
759 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
761 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
762 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
763 This->ddraw_primary = (IWineD3DSurface *) object;
765 /* Look at the implementation and set the correct Vtable */
766 switch(Impl) {
767 case SURFACE_OPENGL:
768 /* Nothing to do, it's set already */
769 break;
771 case SURFACE_GDI:
772 object->lpVtbl = &IWineGDISurface_Vtbl;
773 break;
775 default:
776 /* To be sure to catch this */
777 ERR("Unknown requested surface implementation %d!\n", Impl);
778 IWineD3DSurface_Release((IWineD3DSurface *) object);
779 return WINED3DERR_INVALIDCALL;
782 list_init(&object->renderbuffers);
784 /* Call the private setup routine */
785 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
789 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
790 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
791 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
792 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
795 IWineD3DTextureImpl *object;
796 unsigned int i;
797 UINT tmpW;
798 UINT tmpH;
799 HRESULT hr;
800 unsigned int pow2Width;
801 unsigned int pow2Height;
804 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
805 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
806 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
808 /* TODO: It should only be possible to create textures for formats
809 that are reported as supported */
810 if (WINED3DFMT_UNKNOWN >= Format) {
811 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
812 return WINED3DERR_INVALIDCALL;
815 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
816 D3DINITIALIZEBASETEXTURE(object->baseTexture);
817 object->width = Width;
818 object->height = Height;
820 /** Non-power2 support **/
821 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
822 pow2Width = Width;
823 pow2Height = Height;
824 } else {
825 /* Find the nearest pow2 match */
826 pow2Width = pow2Height = 1;
827 while (pow2Width < Width) pow2Width <<= 1;
828 while (pow2Height < Height) pow2Height <<= 1;
831 /** FIXME: add support for real non-power-two if it's provided by the video card **/
832 /* Precalculated scaling for 'faked' non power of two texture coords */
833 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
834 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
835 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
837 /* Calculate levels for mip mapping */
838 if (Levels == 0) {
839 TRACE("calculating levels %d\n", object->baseTexture.levels);
840 object->baseTexture.levels++;
841 tmpW = Width;
842 tmpH = Height;
843 while (tmpW > 1 || tmpH > 1) {
844 tmpW = max(1, tmpW >> 1);
845 tmpH = max(1, tmpH >> 1);
846 object->baseTexture.levels++;
848 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
851 /* Generate all the surfaces */
852 tmpW = Width;
853 tmpH = Height;
854 for (i = 0; i < object->baseTexture.levels; i++)
856 /* use the callback to create the texture surface */
857 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
858 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
859 FIXME("Failed to create surface %p\n", object);
860 /* clean up */
861 object->surfaces[i] = NULL;
862 IWineD3DTexture_Release((IWineD3DTexture *)object);
864 *ppTexture = NULL;
865 return hr;
868 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
869 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
870 /* calculate the next mipmap level */
871 tmpW = max(1, tmpW >> 1);
872 tmpH = max(1, tmpH >> 1);
875 TRACE("(%p) : Created texture %p\n", This, object);
876 return WINED3D_OK;
879 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
880 UINT Width, UINT Height, UINT Depth,
881 UINT Levels, DWORD Usage,
882 WINED3DFORMAT Format, WINED3DPOOL Pool,
883 IWineD3DVolumeTexture **ppVolumeTexture,
884 HANDLE *pSharedHandle, IUnknown *parent,
885 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
888 IWineD3DVolumeTextureImpl *object;
889 unsigned int i;
890 UINT tmpW;
891 UINT tmpH;
892 UINT tmpD;
894 /* TODO: It should only be possible to create textures for formats
895 that are reported as supported */
896 if (WINED3DFMT_UNKNOWN >= Format) {
897 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
898 return WINED3DERR_INVALIDCALL;
901 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
902 D3DINITIALIZEBASETEXTURE(object->baseTexture);
904 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
905 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
907 object->width = Width;
908 object->height = Height;
909 object->depth = Depth;
911 /* Calculate levels for mip mapping */
912 if (Levels == 0) {
913 object->baseTexture.levels++;
914 tmpW = Width;
915 tmpH = Height;
916 tmpD = Depth;
917 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
918 tmpW = max(1, tmpW >> 1);
919 tmpH = max(1, tmpH >> 1);
920 tmpD = max(1, tmpD >> 1);
921 object->baseTexture.levels++;
923 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
926 /* Generate all the surfaces */
927 tmpW = Width;
928 tmpH = Height;
929 tmpD = Depth;
931 for (i = 0; i < object->baseTexture.levels; i++)
933 HRESULT hr;
934 /* Create the volume */
935 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
936 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
938 if(FAILED(hr)) {
939 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
940 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
941 *ppVolumeTexture = NULL;
942 return hr;
945 /* Set its container to this object */
946 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
948 /* calcualte the next mipmap level */
949 tmpW = max(1, tmpW >> 1);
950 tmpH = max(1, tmpH >> 1);
951 tmpD = max(1, tmpD >> 1);
954 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
955 TRACE("(%p) : Created volume texture %p\n", This, object);
956 return WINED3D_OK;
959 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
960 UINT Width, UINT Height, UINT Depth,
961 DWORD Usage,
962 WINED3DFORMAT Format, WINED3DPOOL Pool,
963 IWineD3DVolume** ppVolume,
964 HANDLE* pSharedHandle, IUnknown *parent) {
966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
967 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
968 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
970 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
972 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
973 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
975 object->currentDesc.Width = Width;
976 object->currentDesc.Height = Height;
977 object->currentDesc.Depth = Depth;
978 object->bytesPerPixel = formatDesc->bpp;
980 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
981 object->lockable = TRUE;
982 object->locked = FALSE;
983 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
984 object->dirty = TRUE;
986 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
989 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
990 UINT Levels, DWORD Usage,
991 WINED3DFORMAT Format, WINED3DPOOL Pool,
992 IWineD3DCubeTexture **ppCubeTexture,
993 HANDLE *pSharedHandle, IUnknown *parent,
994 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
997 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
998 unsigned int i, j;
999 UINT tmpW;
1000 HRESULT hr;
1001 unsigned int pow2EdgeLength = EdgeLength;
1003 /* TODO: It should only be possible to create textures for formats
1004 that are reported as supported */
1005 if (WINED3DFMT_UNKNOWN >= Format) {
1006 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1007 return WINED3DERR_INVALIDCALL;
1010 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1011 WARN("(%p) : Tried to create not supported cube texture\n", This);
1012 return WINED3DERR_INVALIDCALL;
1015 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1016 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1018 TRACE("(%p) Create Cube Texture\n", This);
1020 /** Non-power2 support **/
1022 /* Find the nearest pow2 match */
1023 pow2EdgeLength = 1;
1024 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1026 object->edgeLength = EdgeLength;
1027 /* TODO: support for native non-power 2 */
1028 /* Precalculated scaling for 'faked' non power of two texture coords */
1029 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1031 /* Calculate levels for mip mapping */
1032 if (Levels == 0) {
1033 object->baseTexture.levels++;
1034 tmpW = EdgeLength;
1035 while (tmpW > 1) {
1036 tmpW = max(1, tmpW >> 1);
1037 object->baseTexture.levels++;
1039 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1042 /* Generate all the surfaces */
1043 tmpW = EdgeLength;
1044 for (i = 0; i < object->baseTexture.levels; i++) {
1046 /* Create the 6 faces */
1047 for (j = 0; j < 6; j++) {
1049 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1050 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1052 if(hr!= WINED3D_OK) {
1053 /* clean up */
1054 int k;
1055 int l;
1056 for (l = 0; l < j; l++) {
1057 IWineD3DSurface_Release(object->surfaces[j][i]);
1059 for (k = 0; k < i; k++) {
1060 for (l = 0; l < 6; l++) {
1061 IWineD3DSurface_Release(object->surfaces[l][j]);
1065 FIXME("(%p) Failed to create surface\n",object);
1066 HeapFree(GetProcessHeap(),0,object);
1067 *ppCubeTexture = NULL;
1068 return hr;
1070 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1071 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1073 tmpW = max(1, tmpW >> 1);
1076 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1077 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1078 return WINED3D_OK;
1081 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1083 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1084 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1086 /* Just a check to see if we support this type of query */
1087 switch(Type) {
1088 case WINED3DQUERYTYPE_OCCLUSION:
1089 TRACE("(%p) occlusion query\n", This);
1090 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1091 hr = WINED3D_OK;
1092 else
1093 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1094 break;
1096 case WINED3DQUERYTYPE_EVENT:
1097 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1098 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1099 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1101 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1103 hr = WINED3D_OK;
1104 break;
1106 case WINED3DQUERYTYPE_VCACHE:
1107 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1108 case WINED3DQUERYTYPE_VERTEXSTATS:
1109 case WINED3DQUERYTYPE_TIMESTAMP:
1110 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1111 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1112 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1113 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1114 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1115 case WINED3DQUERYTYPE_PIXELTIMINGS:
1116 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1117 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1118 default:
1119 FIXME("(%p) Unhandled query type %d\n", This, Type);
1121 if(NULL == ppQuery || hr != WINED3D_OK) {
1122 return hr;
1125 D3DCREATEOBJECTINSTANCE(object, Query)
1126 object->type = Type;
1127 /* allocated the 'extended' data based on the type of query requested */
1128 switch(Type){
1129 case WINED3DQUERYTYPE_OCCLUSION:
1130 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1131 TRACE("(%p) Allocating data for an occlusion query\n", This);
1132 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1133 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1134 break;
1136 case WINED3DQUERYTYPE_EVENT:
1137 /* TODO: GL_APPLE_fence */
1138 if(GL_SUPPORT(APPLE_FENCE)) {
1139 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1140 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1141 checkGLcall("glGenFencesAPPLE");
1142 } else if(GL_SUPPORT(NV_FENCE)) {
1143 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1144 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1145 checkGLcall("glGenFencesNV");
1147 break;
1149 case WINED3DQUERYTYPE_VCACHE:
1150 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1151 case WINED3DQUERYTYPE_VERTEXSTATS:
1152 case WINED3DQUERYTYPE_TIMESTAMP:
1153 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1154 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1155 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1156 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1157 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1158 case WINED3DQUERYTYPE_PIXELTIMINGS:
1159 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1160 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1161 default:
1162 object->extendedData = 0;
1163 FIXME("(%p) Unhandled query type %d\n",This , Type);
1165 TRACE("(%p) : Created Query %p\n", This, object);
1166 return WINED3D_OK;
1169 /*****************************************************************************
1170 * IWineD3DDeviceImpl_SetupFullscreenWindow
1172 * Helper function that modifies a HWND's Style and ExStyle for proper
1173 * fullscreen use.
1175 * Params:
1176 * iface: Pointer to the IWineD3DDevice interface
1177 * window: Window to setup
1179 *****************************************************************************/
1180 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1183 LONG style, exStyle;
1184 /* Don't do anything if an original style is stored.
1185 * That shouldn't happen
1187 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1188 if (This->style || This->exStyle) {
1189 ERR("(%p): Want to change the window parameters of HWND %p, but "
1190 "another style is stored for restoration afterwards\n", This, window);
1193 /* Get the parameters and save them */
1194 style = GetWindowLongW(window, GWL_STYLE);
1195 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1196 This->style = style;
1197 This->exStyle = exStyle;
1199 /* Filter out window decorations */
1200 style &= ~WS_CAPTION;
1201 style &= ~WS_THICKFRAME;
1202 exStyle &= ~WS_EX_WINDOWEDGE;
1203 exStyle &= ~WS_EX_CLIENTEDGE;
1205 /* Make sure the window is managed, otherwise we won't get keyboard input */
1206 style |= WS_POPUP | WS_SYSMENU;
1208 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1209 This->style, This->exStyle, style, exStyle);
1211 SetWindowLongW(window, GWL_STYLE, style);
1212 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1214 /* Inform the window about the update. */
1215 SetWindowPos(window, HWND_TOP, 0, 0,
1216 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1217 ShowWindow(window, SW_NORMAL);
1220 /*****************************************************************************
1221 * IWineD3DDeviceImpl_RestoreWindow
1223 * Helper function that restores a windows' properties when taking it out
1224 * of fullscreen mode
1226 * Params:
1227 * iface: Pointer to the IWineD3DDevice interface
1228 * window: Window to setup
1230 *****************************************************************************/
1231 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1234 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1235 * switch, do nothing
1237 if (!This->style && !This->exStyle) return;
1239 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1240 This, window, This->style, This->exStyle);
1242 SetWindowLongW(window, GWL_STYLE, This->style);
1243 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1245 /* Delete the old values */
1246 This->style = 0;
1247 This->exStyle = 0;
1249 /* Inform the window about the update */
1250 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1251 0, 0, 0, 0, /* Pos, Size, ignored */
1252 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1255 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1256 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1257 IUnknown* parent,
1258 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1259 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1262 HDC hDc;
1263 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1264 HRESULT hr = WINED3D_OK;
1265 IUnknown *bufferParent;
1266 Display *display;
1268 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1270 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1271 * does a device hold a reference to a swap chain giving them a lifetime of the device
1272 * or does the swap chain notify the device of its destruction.
1273 *******************************/
1275 /* Check the params */
1276 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1277 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1278 return WINED3DERR_INVALIDCALL;
1279 } else if (pPresentationParameters->BackBufferCount > 1) {
1280 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");
1283 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1285 /*********************
1286 * Lookup the window Handle and the relating X window handle
1287 ********************/
1289 /* Setup hwnd we are using, plus which display this equates to */
1290 object->win_handle = pPresentationParameters->hDeviceWindow;
1291 if (!object->win_handle) {
1292 object->win_handle = This->createParms.hFocusWindow;
1295 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1296 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1297 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1298 return WINED3DERR_NOTAVAILABLE;
1300 hDc = GetDC(object->win_handle);
1301 display = get_display(hDc);
1302 ReleaseDC(object->win_handle, hDc);
1303 TRACE("Using a display of %p %p\n", display, hDc);
1305 if (NULL == display || NULL == hDc) {
1306 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1307 return WINED3DERR_NOTAVAILABLE;
1310 if (object->win == 0) {
1311 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1312 return WINED3DERR_NOTAVAILABLE;
1315 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1316 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1317 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1319 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1320 * then the corresponding dimension of the client area of the hDeviceWindow
1321 * (or the focus window, if hDeviceWindow is NULL) is taken.
1322 **********************/
1324 if (pPresentationParameters->Windowed &&
1325 ((pPresentationParameters->BackBufferWidth == 0) ||
1326 (pPresentationParameters->BackBufferHeight == 0))) {
1328 RECT Rect;
1329 GetClientRect(object->win_handle, &Rect);
1331 if (pPresentationParameters->BackBufferWidth == 0) {
1332 pPresentationParameters->BackBufferWidth = Rect.right;
1333 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1335 if (pPresentationParameters->BackBufferHeight == 0) {
1336 pPresentationParameters->BackBufferHeight = Rect.bottom;
1337 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1341 /* Put the correct figures in the presentation parameters */
1342 TRACE("Copying across presentation parameters\n");
1343 object->presentParms = *pPresentationParameters;
1345 TRACE("calling rendertarget CB\n");
1346 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1347 parent,
1348 object->presentParms.BackBufferWidth,
1349 object->presentParms.BackBufferHeight,
1350 object->presentParms.BackBufferFormat,
1351 object->presentParms.MultiSampleType,
1352 object->presentParms.MultiSampleQuality,
1353 TRUE /* Lockable */,
1354 &object->frontBuffer,
1355 NULL /* pShared (always null)*/);
1356 if (object->frontBuffer != NULL) {
1357 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1358 } else {
1359 ERR("Failed to create the front buffer\n");
1360 goto error;
1364 * Create an opengl context for the display visual
1365 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1366 * use different properties after that point in time. FIXME: How to handle when requested format
1367 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1368 * it chooses is identical to the one already being used!
1369 **********************************/
1370 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1372 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1373 if(!object->context)
1374 return E_OUTOFMEMORY;
1375 object->num_contexts = 1;
1377 ENTER_GL();
1378 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1379 LEAVE_GL();
1381 if (!object->context[0]) {
1382 ERR("Failed to create a new context\n");
1383 hr = WINED3DERR_NOTAVAILABLE;
1384 goto error;
1385 } else {
1386 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1387 object->win_handle, object->context[0]->glCtx, object->win);
1390 /*********************
1391 * Windowed / Fullscreen
1392 *******************/
1395 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1396 * so we should really check to see if there is a fullscreen swapchain already
1397 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1398 **************************************/
1400 if (!pPresentationParameters->Windowed) {
1402 DEVMODEW devmode;
1403 HDC hdc;
1404 int bpp = 0;
1405 RECT clip_rc;
1407 /* Get info on the current display setup */
1408 hdc = GetDC(0);
1409 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1410 ReleaseDC(0, hdc);
1412 /* Change the display settings */
1413 memset(&devmode, 0, sizeof(DEVMODEW));
1414 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1415 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1416 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1417 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1418 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1419 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1421 /* For GetDisplayMode */
1422 This->ddraw_width = devmode.dmPelsWidth;
1423 This->ddraw_height = devmode.dmPelsHeight;
1424 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1426 IWineD3DDevice_SetFullscreen(iface, TRUE);
1428 /* And finally clip mouse to our screen */
1429 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1430 ClipCursor(&clip_rc);
1433 /*********************
1434 * Create the back, front and stencil buffers
1435 *******************/
1436 if(object->presentParms.BackBufferCount > 0) {
1437 int i;
1439 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1440 if(!object->backBuffer) {
1441 ERR("Out of memory\n");
1442 hr = E_OUTOFMEMORY;
1443 goto error;
1446 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1447 TRACE("calling rendertarget CB\n");
1448 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1449 parent,
1450 object->presentParms.BackBufferWidth,
1451 object->presentParms.BackBufferHeight,
1452 object->presentParms.BackBufferFormat,
1453 object->presentParms.MultiSampleType,
1454 object->presentParms.MultiSampleQuality,
1455 TRUE /* Lockable */,
1456 &object->backBuffer[i],
1457 NULL /* pShared (always null)*/);
1458 if(hr == WINED3D_OK && object->backBuffer[i]) {
1459 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1460 } else {
1461 ERR("Cannot create new back buffer\n");
1462 goto error;
1464 ENTER_GL();
1465 glDrawBuffer(GL_BACK);
1466 checkGLcall("glDrawBuffer(GL_BACK)");
1467 LEAVE_GL();
1469 } else {
1470 object->backBuffer = NULL;
1472 /* Single buffering - draw to front buffer */
1473 ENTER_GL();
1474 glDrawBuffer(GL_FRONT);
1475 checkGLcall("glDrawBuffer(GL_FRONT)");
1476 LEAVE_GL();
1479 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1480 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1481 TRACE("Creating depth stencil buffer\n");
1482 if (This->depthStencilBuffer == NULL ) {
1483 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1484 parent,
1485 object->presentParms.BackBufferWidth,
1486 object->presentParms.BackBufferHeight,
1487 object->presentParms.AutoDepthStencilFormat,
1488 object->presentParms.MultiSampleType,
1489 object->presentParms.MultiSampleQuality,
1490 FALSE /* FIXME: Discard */,
1491 &This->depthStencilBuffer,
1492 NULL /* pShared (always null)*/ );
1493 if (This->depthStencilBuffer != NULL)
1494 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1497 /** TODO: A check on width, height and multisample types
1498 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1499 ****************************/
1500 object->wantsDepthStencilBuffer = TRUE;
1501 } else {
1502 object->wantsDepthStencilBuffer = FALSE;
1505 TRACE("Created swapchain %p\n", object);
1506 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1507 return WINED3D_OK;
1509 error:
1510 if (object->backBuffer) {
1511 int i;
1512 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1513 if(object->backBuffer[i]) {
1514 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1515 IUnknown_Release(bufferParent); /* once for the get parent */
1516 if (IUnknown_Release(bufferParent) > 0) {
1517 FIXME("(%p) Something's still holding the back buffer\n",This);
1521 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1522 object->backBuffer = NULL;
1524 if(object->context[0])
1525 DestroyContext(This, object->context[0]);
1526 if(object->frontBuffer) {
1527 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1528 IUnknown_Release(bufferParent); /* once for the get parent */
1529 if (IUnknown_Release(bufferParent) > 0) {
1530 FIXME("(%p) Something's still holding the front buffer\n",This);
1533 HeapFree(GetProcessHeap(), 0, object);
1534 return hr;
1537 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1538 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1540 TRACE("(%p)\n", This);
1542 return This->NumberOfSwapChains;
1545 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1547 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1549 if(iSwapChain < This->NumberOfSwapChains) {
1550 *pSwapChain = This->swapchains[iSwapChain];
1551 IWineD3DSwapChain_AddRef(*pSwapChain);
1552 TRACE("(%p) returning %p\n", This, *pSwapChain);
1553 return WINED3D_OK;
1554 } else {
1555 TRACE("Swapchain out of range\n");
1556 *pSwapChain = NULL;
1557 return WINED3DERR_INVALIDCALL;
1561 /*****
1562 * Vertex Declaration
1563 *****/
1564 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1565 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1567 IWineD3DVertexDeclarationImpl *object = NULL;
1568 HRESULT hr = WINED3D_OK;
1570 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1571 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1573 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1575 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1577 return hr;
1580 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1582 unsigned int idx, idx2;
1583 unsigned int offset;
1584 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1585 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1586 BOOL has_blend_idx = has_blend &&
1587 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1588 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1589 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1590 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1591 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1592 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1593 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1595 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1596 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1598 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1599 WINED3DVERTEXELEMENT *elements = NULL;
1601 unsigned int size;
1602 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1603 if (has_blend_idx) num_blends--;
1605 /* Compute declaration size */
1606 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1607 has_psize + has_diffuse + has_specular + num_textures + 1;
1609 /* convert the declaration */
1610 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1611 if (!elements)
1612 return 0;
1614 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1615 idx = 0;
1616 if (has_pos) {
1617 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1618 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1619 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1621 else {
1622 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1623 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1625 elements[idx].UsageIndex = 0;
1626 idx++;
1628 if (has_blend && (num_blends > 0)) {
1629 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1630 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1631 else
1632 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1633 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1634 elements[idx].UsageIndex = 0;
1635 idx++;
1637 if (has_blend_idx) {
1638 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1639 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1640 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1641 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1642 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1643 else
1644 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1645 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1646 elements[idx].UsageIndex = 0;
1647 idx++;
1649 if (has_normal) {
1650 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1651 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1652 elements[idx].UsageIndex = 0;
1653 idx++;
1655 if (has_psize) {
1656 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1657 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1658 elements[idx].UsageIndex = 0;
1659 idx++;
1661 if (has_diffuse) {
1662 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1663 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1664 elements[idx].UsageIndex = 0;
1665 idx++;
1667 if (has_specular) {
1668 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1669 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1670 elements[idx].UsageIndex = 1;
1671 idx++;
1673 for (idx2 = 0; idx2 < num_textures; idx2++) {
1674 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1675 switch (numcoords) {
1676 case WINED3DFVF_TEXTUREFORMAT1:
1677 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1678 break;
1679 case WINED3DFVF_TEXTUREFORMAT2:
1680 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1681 break;
1682 case WINED3DFVF_TEXTUREFORMAT3:
1683 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1684 break;
1685 case WINED3DFVF_TEXTUREFORMAT4:
1686 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1687 break;
1689 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1690 elements[idx].UsageIndex = idx2;
1691 idx++;
1694 /* Now compute offsets, and initialize the rest of the fields */
1695 for (idx = 0, offset = 0; idx < size-1; idx++) {
1696 elements[idx].Stream = 0;
1697 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1698 elements[idx].Offset = offset;
1699 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1702 *ppVertexElements = elements;
1703 return size;
1706 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1707 WINED3DVERTEXELEMENT* elements = NULL;
1708 size_t size;
1709 DWORD hr;
1711 size = ConvertFvfToDeclaration(Fvf, &elements);
1712 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1714 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1715 HeapFree(GetProcessHeap(), 0, elements);
1716 if (hr != S_OK) return hr;
1718 return WINED3D_OK;
1721 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1722 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1724 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1725 HRESULT hr = WINED3D_OK;
1726 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1727 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1729 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1731 if (vertex_declaration) {
1732 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1735 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1737 if (WINED3D_OK != hr) {
1738 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1739 IWineD3DVertexShader_Release(*ppVertexShader);
1740 return WINED3DERR_INVALIDCALL;
1743 return WINED3D_OK;
1746 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1748 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1749 HRESULT hr = WINED3D_OK;
1751 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1752 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1753 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1754 if (WINED3D_OK == hr) {
1755 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1756 } else {
1757 WARN("(%p) : Failed to create pixel shader\n", This);
1760 return hr;
1763 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1765 IWineD3DPaletteImpl *object;
1766 HRESULT hr;
1767 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1769 /* Create the new object */
1770 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1771 if(!object) {
1772 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1773 return E_OUTOFMEMORY;
1776 object->lpVtbl = &IWineD3DPalette_Vtbl;
1777 object->ref = 1;
1778 object->Flags = Flags;
1779 object->parent = Parent;
1780 object->wineD3DDevice = This;
1781 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1783 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1785 if(!object->hpal) {
1786 HeapFree( GetProcessHeap(), 0, object);
1787 return E_OUTOFMEMORY;
1790 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1791 if(FAILED(hr)) {
1792 IWineD3DPalette_Release((IWineD3DPalette *) object);
1793 return hr;
1796 *Palette = (IWineD3DPalette *) object;
1798 return WINED3D_OK;
1801 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1803 IWineD3DSwapChainImpl *swapchain;
1804 HRESULT hr;
1805 DWORD state;
1807 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1808 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1810 /* TODO: Test if OpenGL is compiled in and loaded */
1812 /* Initialize the texture unit mapping to a 1:1 mapping */
1813 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1814 if (state < GL_LIMITS(fragment_samplers)) {
1815 This->texUnitMap[state] = state;
1816 This->rev_tex_unit_map[state] = state;
1817 } else {
1818 This->texUnitMap[state] = -1;
1819 This->rev_tex_unit_map[state] = -1;
1822 This->oneToOneTexUnitMap = TRUE;
1824 /* Setup the implicit swapchain */
1825 TRACE("Creating implicit swapchain\n");
1826 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1827 if (FAILED(hr) || !swapchain) {
1828 WARN("Failed to create implicit swapchain\n");
1829 return hr;
1832 This->NumberOfSwapChains = 1;
1833 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1834 if(!This->swapchains) {
1835 ERR("Out of memory!\n");
1836 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1837 return E_OUTOFMEMORY;
1839 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1841 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1843 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1844 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1845 This->render_targets[0] = swapchain->backBuffer[0];
1846 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1848 else {
1849 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1850 This->render_targets[0] = swapchain->frontBuffer;
1851 This->lastActiveRenderTarget = swapchain->frontBuffer;
1853 IWineD3DSurface_AddRef(This->render_targets[0]);
1854 This->activeContext = swapchain->context[0];
1856 /* Depth Stencil support */
1857 This->stencilBufferTarget = This->depthStencilBuffer;
1858 if (NULL != This->stencilBufferTarget) {
1859 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1862 /* Set up some starting GL setup */
1863 ENTER_GL();
1865 /* Setup all the devices defaults */
1866 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1867 #if 0
1868 IWineD3DImpl_CheckGraphicsMemory();
1869 #endif
1871 { /* Set a default viewport */
1872 WINED3DVIEWPORT vp;
1873 vp.X = 0;
1874 vp.Y = 0;
1875 vp.Width = pPresentationParameters->BackBufferWidth;
1876 vp.Height = pPresentationParameters->BackBufferHeight;
1877 vp.MinZ = 0.0f;
1878 vp.MaxZ = 1.0f;
1879 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1882 /* Initialize the current view state */
1883 This->view_ident = 1;
1884 This->contexts[0]->last_was_rhw = 0;
1885 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1886 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1888 switch(wined3d_settings.offscreen_rendering_mode) {
1889 case ORM_FBO:
1890 case ORM_PBUFFER:
1891 This->offscreenBuffer = GL_BACK;
1892 break;
1894 case ORM_BACKBUFFER:
1896 if(GL_LIMITS(aux_buffers) > 0) {
1897 TRACE("Using auxilliary buffer for offscreen rendering\n");
1898 This->offscreenBuffer = GL_AUX0;
1899 } else {
1900 TRACE("Using back buffer for offscreen rendering\n");
1901 This->offscreenBuffer = GL_BACK;
1906 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1907 LEAVE_GL();
1909 /* Clear the screen */
1910 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1911 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1912 0x00, 1.0, 0);
1914 This->d3d_initialized = TRUE;
1915 return WINED3D_OK;
1918 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1920 int sampler;
1921 uint i;
1922 TRACE("(%p)\n", This);
1924 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1926 ENTER_GL();
1927 /* I don't think that the interface guarants that the device is destroyed from the same thread
1928 * it was created. Thus make sure a context is active for the glDelete* calls
1930 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1931 LEAVE_GL();
1933 /* Delete the pbuffer context if there is any */
1934 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1936 /* Delete the mouse cursor texture */
1937 if(This->cursorTexture) {
1938 ENTER_GL();
1939 glDeleteTextures(1, &This->cursorTexture);
1940 LEAVE_GL();
1941 This->cursorTexture = 0;
1944 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1945 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1947 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1948 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1951 /* Release the buffers (with sanity checks)*/
1952 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1953 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1954 if(This->depthStencilBuffer != This->stencilBufferTarget)
1955 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1957 This->stencilBufferTarget = NULL;
1959 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1960 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1961 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1963 TRACE("Setting rendertarget to NULL\n");
1964 This->render_targets[0] = NULL;
1966 if (This->depthStencilBuffer) {
1967 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1968 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1970 This->depthStencilBuffer = NULL;
1973 for(i=0; i < This->NumberOfSwapChains; i++) {
1974 TRACE("Releasing the implicit swapchain %d\n", i);
1975 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1976 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1980 HeapFree(GetProcessHeap(), 0, This->swapchains);
1981 This->swapchains = NULL;
1982 This->NumberOfSwapChains = 0;
1984 This->d3d_initialized = FALSE;
1985 return WINED3D_OK;
1988 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1990 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1992 /* Setup the window for fullscreen mode */
1993 if(fullscreen && !This->ddraw_fullscreen) {
1994 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1995 } else if(!fullscreen && This->ddraw_fullscreen) {
1996 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1999 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2000 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2001 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2002 * separately.
2004 This->ddraw_fullscreen = fullscreen;
2007 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2008 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2009 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2011 * There is no way to deactivate thread safety once it is enabled
2013 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2015 FIXME("No thread safety in wined3d yet\n");
2017 /*For now just store the flag(needed in case of ddraw) */
2018 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2020 return;
2023 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2024 DEVMODEW devmode;
2025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2026 LONG ret;
2027 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2028 RECT clip_rc;
2030 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2032 /* Resize the screen even without a window:
2033 * The app could have unset it with SetCooperativeLevel, but not called
2034 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2035 * but we don't have any hwnd
2038 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2039 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2040 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2041 devmode.dmPelsWidth = pMode->Width;
2042 devmode.dmPelsHeight = pMode->Height;
2044 devmode.dmDisplayFrequency = pMode->RefreshRate;
2045 if (pMode->RefreshRate != 0) {
2046 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2049 /* Only change the mode if necessary */
2050 if( (This->ddraw_width == pMode->Width) &&
2051 (This->ddraw_height == pMode->Height) &&
2052 (This->ddraw_format == pMode->Format) &&
2053 (pMode->RefreshRate == 0) ) {
2054 return WINED3D_OK;
2057 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2058 if (ret != DISP_CHANGE_SUCCESSFUL) {
2059 if(devmode.dmDisplayFrequency != 0) {
2060 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2061 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2062 devmode.dmDisplayFrequency = 0;
2063 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2065 if(ret != DISP_CHANGE_SUCCESSFUL) {
2066 return WINED3DERR_NOTAVAILABLE;
2070 /* Store the new values */
2071 This->ddraw_width = pMode->Width;
2072 This->ddraw_height = pMode->Height;
2073 This->ddraw_format = pMode->Format;
2075 /* Only do this with a window of course */
2076 if(This->ddraw_window)
2077 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2079 /* And finally clip mouse to our screen */
2080 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2081 ClipCursor(&clip_rc);
2083 return WINED3D_OK;
2086 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2088 *ppD3D= This->wineD3D;
2089 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2090 IWineD3D_AddRef(*ppD3D);
2091 return WINED3D_OK;
2094 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2095 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2096 * into the video ram as possible and seeing how many fit
2097 * you can also get the correct initial value from nvidia and ATI's driver via X
2098 * texture memory is video memory + AGP memory
2099 *******************/
2100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2101 static BOOL showfixmes = TRUE;
2102 if (showfixmes) {
2103 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2104 (wined3d_settings.emulated_textureram/(1024*1024)),
2105 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2106 showfixmes = FALSE;
2108 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2109 (wined3d_settings.emulated_textureram/(1024*1024)),
2110 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2111 /* return simulated texture memory left */
2112 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2117 /*****
2118 * Get / Set FVF
2119 *****/
2120 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2123 /* Update the current state block */
2124 This->updateStateBlock->changed.fvf = TRUE;
2125 This->updateStateBlock->set.fvf = TRUE;
2127 if(This->updateStateBlock->fvf == fvf) {
2128 TRACE("Application is setting the old fvf over, nothing to do\n");
2129 return WINED3D_OK;
2132 This->updateStateBlock->fvf = fvf;
2133 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2134 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2135 return WINED3D_OK;
2139 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2141 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2142 *pfvf = This->stateBlock->fvf;
2143 return WINED3D_OK;
2146 /*****
2147 * Get / Set Stream Source
2148 *****/
2149 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2151 IWineD3DVertexBuffer *oldSrc;
2153 if (StreamNumber >= MAX_STREAMS) {
2154 WARN("Stream out of range %d\n", StreamNumber);
2155 return WINED3DERR_INVALIDCALL;
2158 oldSrc = This->stateBlock->streamSource[StreamNumber];
2159 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2161 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2162 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2164 if(oldSrc == pStreamData &&
2165 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2166 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2167 TRACE("Application is setting the old values over, nothing to do\n");
2168 return WINED3D_OK;
2171 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2172 if (pStreamData) {
2173 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2174 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2177 /* Handle recording of state blocks */
2178 if (This->isRecordingState) {
2179 TRACE("Recording... not performing anything\n");
2180 return WINED3D_OK;
2183 /* Need to do a getParent and pass the reffs up */
2184 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2185 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2186 so for now, just count internally */
2187 if (pStreamData != NULL) {
2188 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2189 InterlockedIncrement(&vbImpl->bindCount);
2191 if (oldSrc != NULL) {
2192 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2195 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2197 return WINED3D_OK;
2200 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2203 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2204 This->stateBlock->streamSource[StreamNumber],
2205 This->stateBlock->streamOffset[StreamNumber],
2206 This->stateBlock->streamStride[StreamNumber]);
2208 if (StreamNumber >= MAX_STREAMS) {
2209 WARN("Stream out of range %d\n", StreamNumber);
2210 return WINED3DERR_INVALIDCALL;
2212 *pStream = This->stateBlock->streamSource[StreamNumber];
2213 *pStride = This->stateBlock->streamStride[StreamNumber];
2214 if (pOffset) {
2215 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2218 if (*pStream != NULL) {
2219 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2221 return WINED3D_OK;
2224 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2226 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2227 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2229 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2230 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2232 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2233 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2234 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2236 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2237 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2238 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2241 return WINED3D_OK;
2244 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2247 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2248 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2250 TRACE("(%p) : returning %d\n", This, *Divider);
2252 return WINED3D_OK;
2255 /*****
2256 * Get / Set & Multiply Transform
2257 *****/
2258 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2261 /* Most of this routine, comments included copied from ddraw tree initially: */
2262 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2264 /* Handle recording of state blocks */
2265 if (This->isRecordingState) {
2266 TRACE("Recording... not performing anything\n");
2267 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2268 This->updateStateBlock->set.transform[d3dts] = TRUE;
2269 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2270 return WINED3D_OK;
2274 * If the new matrix is the same as the current one,
2275 * we cut off any further processing. this seems to be a reasonable
2276 * optimization because as was noticed, some apps (warcraft3 for example)
2277 * tend towards setting the same matrix repeatedly for some reason.
2279 * From here on we assume that the new matrix is different, wherever it matters.
2281 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2282 TRACE("The app is setting the same matrix over again\n");
2283 return WINED3D_OK;
2284 } else {
2285 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2289 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2290 where ViewMat = Camera space, WorldMat = world space.
2292 In OpenGL, camera and world space is combined into GL_MODELVIEW
2293 matrix. The Projection matrix stay projection matrix.
2296 /* Capture the times we can just ignore the change for now */
2297 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2298 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2299 /* Handled by the state manager */
2302 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2303 return WINED3D_OK;
2306 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2308 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2309 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2310 return WINED3D_OK;
2313 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2314 WINED3DMATRIX *mat = NULL;
2315 WINED3DMATRIX temp;
2317 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2318 * below means it will be recorded in a state block change, but it
2319 * works regardless where it is recorded.
2320 * If this is found to be wrong, change to StateBlock.
2322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2323 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2325 if (State < HIGHEST_TRANSFORMSTATE)
2327 mat = &This->updateStateBlock->transforms[State];
2328 } else {
2329 FIXME("Unhandled transform state!!\n");
2332 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2334 /* Apply change via set transform - will reapply to eg. lights this way */
2335 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2338 /*****
2339 * Get / Set Light
2340 *****/
2341 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2342 you can reference any indexes you want as long as that number max are enabled at any
2343 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2344 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2345 but when recording, just build a chain pretty much of commands to be replayed. */
2347 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2348 float rho;
2349 PLIGHTINFOEL *object = NULL;
2350 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2351 struct list *e;
2353 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2354 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2356 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2357 * the gl driver.
2359 if(!pLight) {
2360 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2361 return WINED3DERR_INVALIDCALL;
2364 switch(pLight->Type) {
2365 case WINED3DLIGHT_POINT:
2366 case WINED3DLIGHT_SPOT:
2367 case WINED3DLIGHT_PARALLELPOINT:
2368 case WINED3DLIGHT_GLSPOT:
2369 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2370 * most wanted
2372 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2373 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2374 return WINED3DERR_INVALIDCALL;
2376 break;
2378 case WINED3DLIGHT_DIRECTIONAL:
2379 /* Ignores attenuation */
2380 break;
2382 default:
2383 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2384 return WINED3DERR_INVALIDCALL;
2387 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2388 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2389 if(object->OriginalIndex == Index) break;
2390 object = NULL;
2393 if(!object) {
2394 TRACE("Adding new light\n");
2395 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2396 if(!object) {
2397 ERR("Out of memory error when allocating a light\n");
2398 return E_OUTOFMEMORY;
2400 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2401 object->glIndex = -1;
2402 object->OriginalIndex = Index;
2403 object->changed = TRUE;
2406 /* Initialize the object */
2407 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,
2408 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2409 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2410 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2411 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2412 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2413 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2415 /* Save away the information */
2416 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2418 switch (pLight->Type) {
2419 case WINED3DLIGHT_POINT:
2420 /* Position */
2421 object->lightPosn[0] = pLight->Position.x;
2422 object->lightPosn[1] = pLight->Position.y;
2423 object->lightPosn[2] = pLight->Position.z;
2424 object->lightPosn[3] = 1.0f;
2425 object->cutoff = 180.0f;
2426 /* FIXME: Range */
2427 break;
2429 case WINED3DLIGHT_DIRECTIONAL:
2430 /* Direction */
2431 object->lightPosn[0] = -pLight->Direction.x;
2432 object->lightPosn[1] = -pLight->Direction.y;
2433 object->lightPosn[2] = -pLight->Direction.z;
2434 object->lightPosn[3] = 0.0;
2435 object->exponent = 0.0f;
2436 object->cutoff = 180.0f;
2437 break;
2439 case WINED3DLIGHT_SPOT:
2440 /* Position */
2441 object->lightPosn[0] = pLight->Position.x;
2442 object->lightPosn[1] = pLight->Position.y;
2443 object->lightPosn[2] = pLight->Position.z;
2444 object->lightPosn[3] = 1.0;
2446 /* Direction */
2447 object->lightDirn[0] = pLight->Direction.x;
2448 object->lightDirn[1] = pLight->Direction.y;
2449 object->lightDirn[2] = pLight->Direction.z;
2450 object->lightDirn[3] = 1.0;
2453 * opengl-ish and d3d-ish spot lights use too different models for the
2454 * light "intensity" as a function of the angle towards the main light direction,
2455 * so we only can approximate very roughly.
2456 * however spot lights are rather rarely used in games (if ever used at all).
2457 * furthermore if still used, probably nobody pays attention to such details.
2459 if (pLight->Falloff == 0) {
2460 rho = 6.28f;
2461 } else {
2462 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2464 if (rho < 0.0001) rho = 0.0001f;
2465 object->exponent = -0.3/log(cos(rho/2));
2466 if (object->exponent > 128.0) {
2467 object->exponent = 128.0;
2469 object->cutoff = pLight->Phi*90/M_PI;
2471 /* FIXME: Range */
2472 break;
2474 default:
2475 FIXME("Unrecognized light type %d\n", pLight->Type);
2478 /* Update the live definitions if the light is currently assigned a glIndex */
2479 if (object->glIndex != -1 && !This->isRecordingState) {
2480 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2482 return WINED3D_OK;
2485 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2486 PLIGHTINFOEL *lightInfo = NULL;
2487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2488 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2489 struct list *e;
2490 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2492 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2493 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2494 if(lightInfo->OriginalIndex == Index) break;
2495 lightInfo = NULL;
2498 if (lightInfo == NULL) {
2499 TRACE("Light information requested but light not defined\n");
2500 return WINED3DERR_INVALIDCALL;
2503 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2504 return WINED3D_OK;
2507 /*****
2508 * Get / Set Light Enable
2509 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2510 *****/
2511 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2512 PLIGHTINFOEL *lightInfo = NULL;
2513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2514 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2515 struct list *e;
2516 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2518 /* Tests show true = 128...not clear why */
2519 Enable = Enable? 128: 0;
2521 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2522 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2523 if(lightInfo->OriginalIndex == Index) break;
2524 lightInfo = NULL;
2526 TRACE("Found light: %p\n", lightInfo);
2528 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2529 if (lightInfo == NULL) {
2531 TRACE("Light enabled requested but light not defined, so defining one!\n");
2532 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2534 /* Search for it again! Should be fairly quick as near head of list */
2535 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2536 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2537 if(lightInfo->OriginalIndex == Index) break;
2538 lightInfo = NULL;
2540 if (lightInfo == NULL) {
2541 FIXME("Adding default lights has failed dismally\n");
2542 return WINED3DERR_INVALIDCALL;
2546 lightInfo->enabledChanged = TRUE;
2547 if(!Enable) {
2548 if(lightInfo->glIndex != -1) {
2549 if(!This->isRecordingState) {
2550 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2553 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2554 lightInfo->glIndex = -1;
2555 } else {
2556 TRACE("Light already disabled, nothing to do\n");
2558 } else {
2559 if (lightInfo->glIndex != -1) {
2560 /* nop */
2561 TRACE("Nothing to do as light was enabled\n");
2562 } else {
2563 int i;
2564 /* Find a free gl light */
2565 for(i = 0; i < This->maxConcurrentLights; i++) {
2566 if(This->stateBlock->activeLights[i] == NULL) {
2567 This->stateBlock->activeLights[i] = lightInfo;
2568 lightInfo->glIndex = i;
2569 break;
2572 if(lightInfo->glIndex == -1) {
2573 ERR("Too many concurrently active lights\n");
2574 return WINED3DERR_INVALIDCALL;
2577 /* i == lightInfo->glIndex */
2578 if(!This->isRecordingState) {
2579 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2584 return WINED3D_OK;
2587 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2589 PLIGHTINFOEL *lightInfo = NULL;
2590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2591 struct list *e;
2592 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2593 TRACE("(%p) : for idx(%d)\n", This, Index);
2595 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2596 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2597 if(lightInfo->OriginalIndex == Index) break;
2598 lightInfo = NULL;
2601 if (lightInfo == NULL) {
2602 TRACE("Light enabled state requested but light not defined\n");
2603 return WINED3DERR_INVALIDCALL;
2605 /* true is 128 according to SetLightEnable */
2606 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2607 return WINED3D_OK;
2610 /*****
2611 * Get / Set Clip Planes
2612 *****/
2613 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2615 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2617 /* Validate Index */
2618 if (Index >= GL_LIMITS(clipplanes)) {
2619 TRACE("Application has requested clipplane this device doesn't support\n");
2620 return WINED3DERR_INVALIDCALL;
2623 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2624 This->updateStateBlock->set.clipplane[Index] = TRUE;
2626 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2627 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2628 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2629 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2630 TRACE("Application is setting old values over, nothing to do\n");
2631 return WINED3D_OK;
2634 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2635 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2636 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2637 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2639 /* Handle recording of state blocks */
2640 if (This->isRecordingState) {
2641 TRACE("Recording... not performing anything\n");
2642 return WINED3D_OK;
2645 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2647 return WINED3D_OK;
2650 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2652 TRACE("(%p) : for idx %d\n", This, Index);
2654 /* Validate Index */
2655 if (Index >= GL_LIMITS(clipplanes)) {
2656 TRACE("Application has requested clipplane this device doesn't support\n");
2657 return WINED3DERR_INVALIDCALL;
2660 pPlane[0] = This->stateBlock->clipplane[Index][0];
2661 pPlane[1] = This->stateBlock->clipplane[Index][1];
2662 pPlane[2] = This->stateBlock->clipplane[Index][2];
2663 pPlane[3] = This->stateBlock->clipplane[Index][3];
2664 return WINED3D_OK;
2667 /*****
2668 * Get / Set Clip Plane Status
2669 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2670 *****/
2671 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2673 FIXME("(%p) : stub\n", This);
2674 if (NULL == pClipStatus) {
2675 return WINED3DERR_INVALIDCALL;
2677 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2678 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2679 return WINED3D_OK;
2682 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2684 FIXME("(%p) : stub\n", This);
2685 if (NULL == pClipStatus) {
2686 return WINED3DERR_INVALIDCALL;
2688 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2689 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2690 return WINED3D_OK;
2693 /*****
2694 * Get / Set Material
2695 *****/
2696 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2699 This->updateStateBlock->changed.material = TRUE;
2700 This->updateStateBlock->set.material = TRUE;
2701 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2703 /* Handle recording of state blocks */
2704 if (This->isRecordingState) {
2705 TRACE("Recording... not performing anything\n");
2706 return WINED3D_OK;
2709 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2710 return WINED3D_OK;
2713 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2715 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2716 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2717 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2718 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2719 pMaterial->Ambient.b, pMaterial->Ambient.a);
2720 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2721 pMaterial->Specular.b, pMaterial->Specular.a);
2722 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2723 pMaterial->Emissive.b, pMaterial->Emissive.a);
2724 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2726 return WINED3D_OK;
2729 /*****
2730 * Get / Set Indices
2731 *****/
2732 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2734 IWineD3DIndexBuffer *oldIdxs;
2736 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2737 oldIdxs = This->updateStateBlock->pIndexData;
2739 This->updateStateBlock->changed.indices = TRUE;
2740 This->updateStateBlock->set.indices = TRUE;
2741 This->updateStateBlock->pIndexData = pIndexData;
2743 /* Handle recording of state blocks */
2744 if (This->isRecordingState) {
2745 TRACE("Recording... not performing anything\n");
2746 return WINED3D_OK;
2749 if(oldIdxs != pIndexData) {
2750 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2752 return WINED3D_OK;
2755 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2758 *ppIndexData = This->stateBlock->pIndexData;
2760 /* up ref count on ppindexdata */
2761 if (*ppIndexData) {
2762 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2763 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2764 }else{
2765 TRACE("(%p) No index data set\n", This);
2767 TRACE("Returning %p\n", *ppIndexData);
2769 return WINED3D_OK;
2772 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2773 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2775 TRACE("(%p)->(%d)\n", This, BaseIndex);
2777 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2778 TRACE("Application is setting the old value over, nothing to do\n");
2779 return WINED3D_OK;
2782 This->updateStateBlock->baseVertexIndex = BaseIndex;
2784 if (This->isRecordingState) {
2785 TRACE("Recording... not performing anything\n");
2786 return WINED3D_OK;
2788 /* The base vertex index affects the stream sources */
2789 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2790 return WINED3D_OK;
2793 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) {
2794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2795 TRACE("(%p) : base_index %p\n", This, base_index);
2797 *base_index = This->stateBlock->baseVertexIndex;
2799 TRACE("Returning %u\n", *base_index);
2801 return WINED3D_OK;
2804 /*****
2805 * Get / Set Viewports
2806 *****/
2807 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2810 TRACE("(%p)\n", This);
2811 This->updateStateBlock->changed.viewport = TRUE;
2812 This->updateStateBlock->set.viewport = TRUE;
2813 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2815 /* Handle recording of state blocks */
2816 if (This->isRecordingState) {
2817 TRACE("Recording... not performing anything\n");
2818 return WINED3D_OK;
2821 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2822 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2824 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2825 return WINED3D_OK;
2829 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2831 TRACE("(%p)\n", This);
2832 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2833 return WINED3D_OK;
2836 /*****
2837 * Get / Set Render States
2838 * TODO: Verify against dx9 definitions
2839 *****/
2840 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2843 DWORD oldValue = This->stateBlock->renderState[State];
2845 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2847 This->updateStateBlock->changed.renderState[State] = TRUE;
2848 This->updateStateBlock->set.renderState[State] = TRUE;
2849 This->updateStateBlock->renderState[State] = Value;
2851 /* Handle recording of state blocks */
2852 if (This->isRecordingState) {
2853 TRACE("Recording... not performing anything\n");
2854 return WINED3D_OK;
2857 /* Compared here and not before the assignment to allow proper stateblock recording */
2858 if(Value == oldValue) {
2859 TRACE("Application is setting the old value over, nothing to do\n");
2860 } else {
2861 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2864 return WINED3D_OK;
2867 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2869 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2870 *pValue = This->stateBlock->renderState[State];
2871 return WINED3D_OK;
2874 /*****
2875 * Get / Set Sampler States
2876 * TODO: Verify against dx9 definitions
2877 *****/
2879 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2881 DWORD oldValue;
2883 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2884 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2886 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2887 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2891 * SetSampler is designed to allow for more than the standard up to 8 textures
2892 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2893 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2895 * http://developer.nvidia.com/object/General_FAQ.html#t6
2897 * There are two new settings for GForce
2898 * the sampler one:
2899 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2900 * and the texture one:
2901 * GL_MAX_TEXTURE_COORDS_ARB.
2902 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2903 ******************/
2905 oldValue = This->stateBlock->samplerState[Sampler][Type];
2906 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2907 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2908 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2910 /* Handle recording of state blocks */
2911 if (This->isRecordingState) {
2912 TRACE("Recording... not performing anything\n");
2913 return WINED3D_OK;
2916 if(oldValue == Value) {
2917 TRACE("Application is setting the old value over, nothing to do\n");
2918 return WINED3D_OK;
2921 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2923 return WINED3D_OK;
2926 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2929 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2930 This, Sampler, debug_d3dsamplerstate(Type), Type);
2932 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2933 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2936 *Value = This->stateBlock->samplerState[Sampler][Type];
2937 TRACE("(%p) : Returning %#x\n", This, *Value);
2939 return WINED3D_OK;
2942 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2945 This->updateStateBlock->set.scissorRect = TRUE;
2946 This->updateStateBlock->changed.scissorRect = TRUE;
2947 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2948 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2949 return WINED3D_OK;
2951 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2953 if(This->isRecordingState) {
2954 TRACE("Recording... not performing anything\n");
2955 return WINED3D_OK;
2958 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2960 return WINED3D_OK;
2963 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2966 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2967 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2968 return WINED3D_OK;
2971 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2973 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2975 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2977 This->updateStateBlock->vertexDecl = pDecl;
2978 This->updateStateBlock->changed.vertexDecl = TRUE;
2979 This->updateStateBlock->set.vertexDecl = TRUE;
2981 if (This->isRecordingState) {
2982 TRACE("Recording... not performing anything\n");
2983 return WINED3D_OK;
2984 } else if(pDecl == oldDecl) {
2985 /* Checked after the assignment to allow proper stateblock recording */
2986 TRACE("Application is setting the old declaration over, nothing to do\n");
2987 return WINED3D_OK;
2990 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2991 return WINED3D_OK;
2994 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2997 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2999 *ppDecl = This->stateBlock->vertexDecl;
3000 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3001 return WINED3D_OK;
3004 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3006 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3008 This->updateStateBlock->vertexShader = pShader;
3009 This->updateStateBlock->changed.vertexShader = TRUE;
3010 This->updateStateBlock->set.vertexShader = TRUE;
3012 if (This->isRecordingState) {
3013 TRACE("Recording... not performing anything\n");
3014 return WINED3D_OK;
3015 } else if(oldShader == pShader) {
3016 /* Checked here to allow proper stateblock recording */
3017 TRACE("App is setting the old shader over, nothing to do\n");
3018 return WINED3D_OK;
3021 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3023 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3025 return WINED3D_OK;
3028 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3031 if (NULL == ppShader) {
3032 return WINED3DERR_INVALIDCALL;
3034 *ppShader = This->stateBlock->vertexShader;
3035 if( NULL != *ppShader)
3036 IWineD3DVertexShader_AddRef(*ppShader);
3038 TRACE("(%p) : returning %p\n", This, *ppShader);
3039 return WINED3D_OK;
3042 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3043 IWineD3DDevice *iface,
3044 UINT start,
3045 CONST BOOL *srcData,
3046 UINT count) {
3048 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3049 int i, cnt = min(count, MAX_CONST_B - start);
3051 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3052 iface, srcData, start, count);
3054 if (srcData == NULL || cnt < 0)
3055 return WINED3DERR_INVALIDCALL;
3057 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3058 for (i = 0; i < cnt; i++)
3059 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3061 for (i = start; i < cnt + start; ++i) {
3062 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3063 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3066 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3068 return WINED3D_OK;
3071 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3072 IWineD3DDevice *iface,
3073 UINT start,
3074 BOOL *dstData,
3075 UINT count) {
3077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3078 int cnt = min(count, MAX_CONST_B - start);
3080 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3081 iface, dstData, start, count);
3083 if (dstData == NULL || cnt < 0)
3084 return WINED3DERR_INVALIDCALL;
3086 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3087 return WINED3D_OK;
3090 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3091 IWineD3DDevice *iface,
3092 UINT start,
3093 CONST int *srcData,
3094 UINT count) {
3096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3097 int i, cnt = min(count, MAX_CONST_I - start);
3099 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3100 iface, srcData, start, count);
3102 if (srcData == NULL || cnt < 0)
3103 return WINED3DERR_INVALIDCALL;
3105 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3106 for (i = 0; i < cnt; i++)
3107 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3108 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3110 for (i = start; i < cnt + start; ++i) {
3111 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3112 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3115 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3117 return WINED3D_OK;
3120 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3121 IWineD3DDevice *iface,
3122 UINT start,
3123 int *dstData,
3124 UINT count) {
3126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3127 int cnt = min(count, MAX_CONST_I - start);
3129 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3130 iface, dstData, start, count);
3132 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3133 return WINED3DERR_INVALIDCALL;
3135 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3136 return WINED3D_OK;
3139 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3140 IWineD3DDevice *iface,
3141 UINT start,
3142 CONST float *srcData,
3143 UINT count) {
3145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3146 int i;
3148 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3149 iface, srcData, start, count);
3151 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3152 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3153 return WINED3DERR_INVALIDCALL;
3155 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3156 if(TRACE_ON(d3d)) {
3157 for (i = 0; i < count; i++)
3158 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3159 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3162 for (i = start; i < count + start; ++i) {
3163 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3164 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3165 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3166 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3167 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3169 ptr->idx[ptr->count++] = i;
3170 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3172 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3175 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3177 return WINED3D_OK;
3180 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3181 IWineD3DDevice *iface,
3182 UINT start,
3183 float *dstData,
3184 UINT count) {
3186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3187 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3189 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3190 iface, dstData, start, count);
3192 if (dstData == NULL || cnt < 0)
3193 return WINED3DERR_INVALIDCALL;
3195 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3196 return WINED3D_OK;
3199 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3200 DWORD i;
3201 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3202 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3206 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3207 int i = This->rev_tex_unit_map[unit];
3208 int j = This->texUnitMap[stage];
3210 This->texUnitMap[stage] = unit;
3211 if (i != -1 && i != stage) {
3212 This->texUnitMap[i] = -1;
3215 This->rev_tex_unit_map[unit] = stage;
3216 if (j != -1 && j != unit) {
3217 This->rev_tex_unit_map[j] = -1;
3221 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3222 int i;
3224 for (i = 0; i < MAX_TEXTURES; ++i) {
3225 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3226 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3227 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3228 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3229 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3230 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3231 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3232 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3234 if (color_op == WINED3DTOP_DISABLE) {
3235 /* Not used, and disable higher stages */
3236 while (i < MAX_TEXTURES) {
3237 This->fixed_function_usage_map[i] = FALSE;
3238 ++i;
3240 break;
3243 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3244 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3245 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3246 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3247 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3248 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3249 This->fixed_function_usage_map[i] = TRUE;
3250 } else {
3251 This->fixed_function_usage_map[i] = FALSE;
3254 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3255 This->fixed_function_usage_map[i+1] = TRUE;
3260 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3261 int i, tex;
3263 device_update_fixed_function_usage_map(This);
3265 if (This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3266 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3267 if (!This->fixed_function_usage_map[i]) continue;
3269 if (This->texUnitMap[i] != i) {
3270 device_map_stage(This, i, i);
3271 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3272 markTextureStagesDirty(This, i);
3275 return;
3278 /* Now work out the mapping */
3279 tex = 0;
3280 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3281 if (!This->fixed_function_usage_map[i]) continue;
3283 if (This->texUnitMap[i] != tex) {
3284 device_map_stage(This, i, tex);
3285 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3286 markTextureStagesDirty(This, i);
3289 ++tex;
3293 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3294 int i;
3296 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3297 if (This->texUnitMap[i] != i) {
3298 device_map_stage(This, i, i);
3299 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3300 if (i < MAX_TEXTURES) {
3301 markTextureStagesDirty(This, i);
3307 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3308 int current_mapping = This->rev_tex_unit_map[unit];
3310 if (current_mapping == -1) {
3311 /* Not currently used */
3312 return TRUE;
3315 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3316 /* Used by a fragment sampler */
3318 if (!pshader_sampler_tokens) {
3319 /* No pixel shader, check fixed function */
3320 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3323 /* Pixel shader, check the shader's sampler map */
3324 return !pshader_sampler_tokens[current_mapping];
3327 /* Used by a vertex sampler */
3328 return !vshader_sampler_tokens[current_mapping];
3331 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3332 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3333 DWORD *pshader_sampler_tokens = NULL;
3334 int start = GL_LIMITS(combined_samplers) - 1;
3335 int i;
3337 if (ps) {
3338 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3340 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3341 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3342 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3345 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3346 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3347 if (vshader_sampler_tokens[i]) {
3348 if (This->texUnitMap[vsampler_idx] != -1) {
3349 /* Already mapped somewhere */
3350 continue;
3353 while (start >= 0) {
3354 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3355 device_map_stage(This, vsampler_idx, start);
3356 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3358 --start;
3359 break;
3362 --start;
3368 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3369 BOOL vs = use_vs(This);
3370 BOOL ps = use_ps(This);
3371 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3372 * it is never called.
3374 * Rules are:
3375 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3376 * that would be really messy and require shader recompilation
3377 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3378 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3380 if (ps) {
3381 device_map_psamplers(This);
3382 } else {
3383 device_map_fixed_function_samplers(This);
3386 if (vs) {
3387 device_map_vsamplers(This, ps);
3391 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3393 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3394 This->updateStateBlock->pixelShader = pShader;
3395 This->updateStateBlock->changed.pixelShader = TRUE;
3396 This->updateStateBlock->set.pixelShader = TRUE;
3398 /* Handle recording of state blocks */
3399 if (This->isRecordingState) {
3400 TRACE("Recording... not performing anything\n");
3403 if (This->isRecordingState) {
3404 TRACE("Recording... not performing anything\n");
3405 return WINED3D_OK;
3408 if(pShader == oldShader) {
3409 TRACE("App is setting the old pixel shader over, nothing to do\n");
3410 return WINED3D_OK;
3413 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3414 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3416 return WINED3D_OK;
3419 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3422 if (NULL == ppShader) {
3423 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3424 return WINED3DERR_INVALIDCALL;
3427 *ppShader = This->stateBlock->pixelShader;
3428 if (NULL != *ppShader) {
3429 IWineD3DPixelShader_AddRef(*ppShader);
3431 TRACE("(%p) : returning %p\n", This, *ppShader);
3432 return WINED3D_OK;
3435 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3436 IWineD3DDevice *iface,
3437 UINT start,
3438 CONST BOOL *srcData,
3439 UINT count) {
3441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3442 int i, cnt = min(count, MAX_CONST_B - start);
3444 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3445 iface, srcData, start, count);
3447 if (srcData == NULL || cnt < 0)
3448 return WINED3DERR_INVALIDCALL;
3450 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3451 for (i = 0; i < cnt; i++)
3452 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3454 for (i = start; i < cnt + start; ++i) {
3455 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3456 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3459 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3461 return WINED3D_OK;
3464 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3465 IWineD3DDevice *iface,
3466 UINT start,
3467 BOOL *dstData,
3468 UINT count) {
3470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3471 int cnt = min(count, MAX_CONST_B - start);
3473 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3474 iface, dstData, start, count);
3476 if (dstData == NULL || cnt < 0)
3477 return WINED3DERR_INVALIDCALL;
3479 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3480 return WINED3D_OK;
3483 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3484 IWineD3DDevice *iface,
3485 UINT start,
3486 CONST int *srcData,
3487 UINT count) {
3489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3490 int i, cnt = min(count, MAX_CONST_I - start);
3492 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3493 iface, srcData, start, count);
3495 if (srcData == NULL || cnt < 0)
3496 return WINED3DERR_INVALIDCALL;
3498 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3499 for (i = 0; i < cnt; i++)
3500 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3501 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3503 for (i = start; i < cnt + start; ++i) {
3504 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3505 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3508 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3510 return WINED3D_OK;
3513 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3514 IWineD3DDevice *iface,
3515 UINT start,
3516 int *dstData,
3517 UINT count) {
3519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3520 int cnt = min(count, MAX_CONST_I - start);
3522 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3523 iface, dstData, start, count);
3525 if (dstData == NULL || cnt < 0)
3526 return WINED3DERR_INVALIDCALL;
3528 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3529 return WINED3D_OK;
3532 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3533 IWineD3DDevice *iface,
3534 UINT start,
3535 CONST float *srcData,
3536 UINT count) {
3538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3539 int i;
3541 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3542 iface, srcData, start, count);
3544 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3545 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3546 return WINED3DERR_INVALIDCALL;
3548 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3549 if(TRACE_ON(d3d)) {
3550 for (i = 0; i < count; i++)
3551 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3552 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3555 for (i = start; i < count + start; ++i) {
3556 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3557 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3558 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3559 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3560 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3562 ptr->idx[ptr->count++] = i;
3563 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3565 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3568 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3570 return WINED3D_OK;
3573 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3574 IWineD3DDevice *iface,
3575 UINT start,
3576 float *dstData,
3577 UINT count) {
3579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3580 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3582 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3583 iface, dstData, start, count);
3585 if (dstData == NULL || cnt < 0)
3586 return WINED3DERR_INVALIDCALL;
3588 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3589 return WINED3D_OK;
3592 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3593 static HRESULT
3594 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3595 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3596 unsigned int i;
3597 DWORD DestFVF = dest->fvf;
3598 WINED3DVIEWPORT vp;
3599 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3600 BOOL doClip;
3601 int numTextures;
3603 if (lpStrideData->u.s.normal.lpData) {
3604 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3607 if (lpStrideData->u.s.position.lpData == NULL) {
3608 ERR("Source has no position mask\n");
3609 return WINED3DERR_INVALIDCALL;
3612 /* We might access VBOs from this code, so hold the lock */
3613 ENTER_GL();
3615 if (dest->resource.allocatedMemory == NULL) {
3616 /* This may happen if we do direct locking into a vbo. Unlikely,
3617 * but theoretically possible(ddraw processvertices test)
3619 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3620 if(!dest->resource.allocatedMemory) {
3621 LEAVE_GL();
3622 ERR("Out of memory\n");
3623 return E_OUTOFMEMORY;
3625 if(dest->vbo) {
3626 void *src;
3627 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3628 checkGLcall("glBindBufferARB");
3629 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3630 if(src) {
3631 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3633 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3634 checkGLcall("glUnmapBufferARB");
3638 /* Get a pointer into the destination vbo(create one if none exists) and
3639 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3641 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3642 CreateVBO(dest);
3645 if(dest->vbo) {
3646 unsigned char extrabytes = 0;
3647 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3648 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3649 * this may write 4 extra bytes beyond the area that should be written
3651 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3652 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3653 if(!dest_conv_addr) {
3654 ERR("Out of memory\n");
3655 /* Continue without storing converted vertices */
3657 dest_conv = dest_conv_addr;
3660 /* Should I clip?
3661 * a) WINED3DRS_CLIPPING is enabled
3662 * b) WINED3DVOP_CLIP is passed
3664 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3665 static BOOL warned = FALSE;
3667 * The clipping code is not quite correct. Some things need
3668 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3669 * so disable clipping for now.
3670 * (The graphics in Half-Life are broken, and my processvertices
3671 * test crashes with IDirect3DDevice3)
3672 doClip = TRUE;
3674 doClip = FALSE;
3675 if(!warned) {
3676 warned = TRUE;
3677 FIXME("Clipping is broken and disabled for now\n");
3679 } else doClip = FALSE;
3680 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3682 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3683 WINED3DTS_VIEW,
3684 &view_mat);
3685 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3686 WINED3DTS_PROJECTION,
3687 &proj_mat);
3688 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3689 WINED3DTS_WORLDMATRIX(0),
3690 &world_mat);
3692 TRACE("View mat:\n");
3693 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);
3694 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);
3695 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);
3696 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);
3698 TRACE("Proj mat:\n");
3699 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);
3700 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);
3701 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);
3702 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);
3704 TRACE("World mat:\n");
3705 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);
3706 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);
3707 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);
3708 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);
3710 /* Get the viewport */
3711 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3712 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3713 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3715 multiply_matrix(&mat,&view_mat,&world_mat);
3716 multiply_matrix(&mat,&proj_mat,&mat);
3718 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3720 for (i = 0; i < dwCount; i+= 1) {
3721 unsigned int tex_index;
3723 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3724 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3725 /* The position first */
3726 float *p =
3727 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3728 float x, y, z, rhw;
3729 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3731 /* Multiplication with world, view and projection matrix */
3732 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);
3733 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);
3734 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);
3735 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);
3737 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3739 /* WARNING: The following things are taken from d3d7 and were not yet checked
3740 * against d3d8 or d3d9!
3743 /* Clipping conditions: From
3744 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3746 * A vertex is clipped if it does not match the following requirements
3747 * -rhw < x <= rhw
3748 * -rhw < y <= rhw
3749 * 0 < z <= rhw
3750 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3752 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3753 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3757 if( !doClip ||
3758 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3759 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3760 ( rhw > eps ) ) ) {
3762 /* "Normal" viewport transformation (not clipped)
3763 * 1) The values are divided by rhw
3764 * 2) The y axis is negative, so multiply it with -1
3765 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3766 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3767 * 4) Multiply x with Width/2 and add Width/2
3768 * 5) The same for the height
3769 * 6) Add the viewpoint X and Y to the 2D coordinates and
3770 * The minimum Z value to z
3771 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3773 * Well, basically it's simply a linear transformation into viewport
3774 * coordinates
3777 x /= rhw;
3778 y /= rhw;
3779 z /= rhw;
3781 y *= -1;
3783 x *= vp.Width / 2;
3784 y *= vp.Height / 2;
3785 z *= vp.MaxZ - vp.MinZ;
3787 x += vp.Width / 2 + vp.X;
3788 y += vp.Height / 2 + vp.Y;
3789 z += vp.MinZ;
3791 rhw = 1 / rhw;
3792 } else {
3793 /* That vertex got clipped
3794 * Contrary to OpenGL it is not dropped completely, it just
3795 * undergoes a different calculation.
3797 TRACE("Vertex got clipped\n");
3798 x += rhw;
3799 y += rhw;
3801 x /= 2;
3802 y /= 2;
3804 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3805 * outside of the main vertex buffer memory. That needs some more
3806 * investigation...
3810 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3813 ( (float *) dest_ptr)[0] = x;
3814 ( (float *) dest_ptr)[1] = y;
3815 ( (float *) dest_ptr)[2] = z;
3816 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3818 dest_ptr += 3 * sizeof(float);
3820 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3821 dest_ptr += sizeof(float);
3824 if(dest_conv) {
3825 float w = 1 / rhw;
3826 ( (float *) dest_conv)[0] = x * w;
3827 ( (float *) dest_conv)[1] = y * w;
3828 ( (float *) dest_conv)[2] = z * w;
3829 ( (float *) dest_conv)[3] = w;
3831 dest_conv += 3 * sizeof(float);
3833 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3834 dest_conv += sizeof(float);
3838 if (DestFVF & WINED3DFVF_PSIZE) {
3839 dest_ptr += sizeof(DWORD);
3840 if(dest_conv) dest_conv += sizeof(DWORD);
3842 if (DestFVF & WINED3DFVF_NORMAL) {
3843 float *normal =
3844 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3845 /* AFAIK this should go into the lighting information */
3846 FIXME("Didn't expect the destination to have a normal\n");
3847 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3848 if(dest_conv) {
3849 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3853 if (DestFVF & WINED3DFVF_DIFFUSE) {
3854 DWORD *color_d =
3855 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3856 if(!color_d) {
3857 static BOOL warned = FALSE;
3859 if(!warned) {
3860 ERR("No diffuse color in source, but destination has one\n");
3861 warned = TRUE;
3864 *( (DWORD *) dest_ptr) = 0xffffffff;
3865 dest_ptr += sizeof(DWORD);
3867 if(dest_conv) {
3868 *( (DWORD *) dest_conv) = 0xffffffff;
3869 dest_conv += sizeof(DWORD);
3872 else {
3873 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3874 if(dest_conv) {
3875 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3876 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3877 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3878 dest_conv += sizeof(DWORD);
3883 if (DestFVF & WINED3DFVF_SPECULAR) {
3884 /* What's the color value in the feedback buffer? */
3885 DWORD *color_s =
3886 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3887 if(!color_s) {
3888 static BOOL warned = FALSE;
3890 if(!warned) {
3891 ERR("No specular color in source, but destination has one\n");
3892 warned = TRUE;
3895 *( (DWORD *) dest_ptr) = 0xFF000000;
3896 dest_ptr += sizeof(DWORD);
3898 if(dest_conv) {
3899 *( (DWORD *) dest_conv) = 0xFF000000;
3900 dest_conv += sizeof(DWORD);
3903 else {
3904 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3905 if(dest_conv) {
3906 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3907 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3908 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3909 dest_conv += sizeof(DWORD);
3914 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3915 float *tex_coord =
3916 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3917 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3918 if(!tex_coord) {
3919 ERR("No source texture, but destination requests one\n");
3920 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3921 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3923 else {
3924 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3925 if(dest_conv) {
3926 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3932 if(dest_conv) {
3933 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3934 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3935 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3936 dwCount * get_flexible_vertex_size(DestFVF),
3937 dest_conv_addr));
3938 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3939 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3942 LEAVE_GL();
3944 return WINED3D_OK;
3946 #undef copy_and_next
3948 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3950 WineDirect3DVertexStridedData strided;
3951 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3952 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3954 if(pVertexDecl) {
3955 ERR("Output vertex declaration not implemented yet\n");
3958 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3959 * and this call is quite performance critical, so don't call needlessly
3961 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3962 ENTER_GL();
3963 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3964 LEAVE_GL();
3967 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3968 * control the streamIsUP flag, thus restore it afterwards.
3970 This->stateBlock->streamIsUP = FALSE;
3971 memset(&strided, 0, sizeof(strided));
3972 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
3973 This->stateBlock->streamIsUP = streamWasUP;
3975 if(vbo || SrcStartIndex) {
3976 unsigned int i;
3977 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
3978 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
3980 * Also get the start index in, but only loop over all elements if there's something to add at all.
3982 #define FIXSRC(type) \
3983 if(strided.u.s.type.VBO) { \
3984 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
3985 strided.u.s.type.VBO = 0; \
3986 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
3987 ENTER_GL(); \
3988 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
3989 vb->vbo = 0; \
3990 LEAVE_GL(); \
3992 if(strided.u.s.type.lpData) { \
3993 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
3995 FIXSRC(position);
3996 FIXSRC(blendWeights);
3997 FIXSRC(blendMatrixIndices);
3998 FIXSRC(normal);
3999 FIXSRC(pSize);
4000 FIXSRC(diffuse);
4001 FIXSRC(specular);
4002 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4003 FIXSRC(texCoords[i]);
4005 FIXSRC(position2);
4006 FIXSRC(normal2);
4007 FIXSRC(tangent);
4008 FIXSRC(binormal);
4009 FIXSRC(tessFactor);
4010 FIXSRC(fog);
4011 FIXSRC(depth);
4012 FIXSRC(sample);
4013 #undef FIXSRC
4016 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4019 /*****
4020 * Get / Set Texture Stage States
4021 * TODO: Verify against dx9 definitions
4022 *****/
4023 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4025 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4027 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4029 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4031 if (Stage >= MAX_TEXTURES) {
4032 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4033 return WINED3D_OK;
4036 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4037 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
4038 This->updateStateBlock->textureState[Stage][Type] = Value;
4040 if (This->isRecordingState) {
4041 TRACE("Recording... not performing anything\n");
4042 return WINED3D_OK;
4045 /* Checked after the assignments to allow proper stateblock recording */
4046 if(oldValue == Value) {
4047 TRACE("App is setting the old value over, nothing to do\n");
4048 return WINED3D_OK;
4051 if(Stage > This->stateBlock->lowest_disabled_stage &&
4052 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4053 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4054 * Changes in other states are important on disabled stages too
4056 return WINED3D_OK;
4059 if(Type == WINED3DTSS_COLOROP) {
4060 int i;
4062 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4063 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4064 * they have to be disabled
4066 * The current stage is dirtified below.
4068 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4069 TRACE("Additionally dirtifying stage %d\n", i);
4070 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4072 This->stateBlock->lowest_disabled_stage = Stage;
4073 TRACE("New lowest disabled: %d\n", Stage);
4074 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4075 /* Previously disabled stage enabled. Stages above it may need enabling
4076 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4077 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4079 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4082 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4083 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4084 break;
4086 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4087 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4089 This->stateBlock->lowest_disabled_stage = i;
4090 TRACE("New lowest disabled: %d\n", i);
4092 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4093 /* TODO: Built a stage -> texture unit mapping for register combiners */
4097 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4099 return WINED3D_OK;
4102 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4104 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4105 *pValue = This->updateStateBlock->textureState[Stage][Type];
4106 return WINED3D_OK;
4109 /*****
4110 * Get / Set Texture
4111 *****/
4112 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4114 IWineD3DBaseTexture *oldTexture;
4116 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4118 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4119 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4122 oldTexture = This->updateStateBlock->textures[Stage];
4124 if(pTexture != NULL) {
4125 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4127 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4128 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4129 return WINED3DERR_INVALIDCALL;
4131 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4134 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4135 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4137 This->updateStateBlock->set.textures[Stage] = TRUE;
4138 This->updateStateBlock->changed.textures[Stage] = TRUE;
4139 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4140 This->updateStateBlock->textures[Stage] = pTexture;
4142 /* Handle recording of state blocks */
4143 if (This->isRecordingState) {
4144 TRACE("Recording... not performing anything\n");
4145 return WINED3D_OK;
4148 if(oldTexture == pTexture) {
4149 TRACE("App is setting the same texture again, nothing to do\n");
4150 return WINED3D_OK;
4153 /** NOTE: MSDN says that setTexture increases the reference count,
4154 * and the the application must set the texture back to null (or have a leaky application),
4155 * This means we should pass the refcount up to the parent
4156 *******************************/
4157 if (NULL != This->updateStateBlock->textures[Stage]) {
4158 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4159 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4161 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4162 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4163 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4164 * so the COLOROP and ALPHAOP have to be dirtified.
4166 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4167 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4169 if(bindCount == 1) {
4170 new->baseTexture.sampler = Stage;
4172 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4176 if (NULL != oldTexture) {
4177 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4178 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4180 IWineD3DBaseTexture_Release(oldTexture);
4181 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4182 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4183 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4186 if(bindCount && old->baseTexture.sampler == Stage) {
4187 int i;
4188 /* Have to do a search for the other sampler(s) where the texture is bound to
4189 * Shouldn't happen as long as apps bind a texture only to one stage
4191 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4192 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4193 if(This->updateStateBlock->textures[i] == oldTexture) {
4194 old->baseTexture.sampler = i;
4195 break;
4201 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4203 return WINED3D_OK;
4206 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4209 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4211 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4212 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4215 *ppTexture=This->stateBlock->textures[Stage];
4216 if (*ppTexture)
4217 IWineD3DBaseTexture_AddRef(*ppTexture);
4219 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4221 return WINED3D_OK;
4224 /*****
4225 * Get Back Buffer
4226 *****/
4227 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4228 IWineD3DSurface **ppBackBuffer) {
4229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4230 IWineD3DSwapChain *swapChain;
4231 HRESULT hr;
4233 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4235 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4236 if (hr == WINED3D_OK) {
4237 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4238 IWineD3DSwapChain_Release(swapChain);
4239 } else {
4240 *ppBackBuffer = NULL;
4242 return hr;
4245 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4247 WARN("(%p) : stub, calling idirect3d for now\n", This);
4248 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4251 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4253 IWineD3DSwapChain *swapChain;
4254 HRESULT hr;
4256 if(iSwapChain > 0) {
4257 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4258 if (hr == WINED3D_OK) {
4259 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4260 IWineD3DSwapChain_Release(swapChain);
4261 } else {
4262 FIXME("(%p) Error getting display mode\n", This);
4264 } else {
4265 /* Don't read the real display mode,
4266 but return the stored mode instead. X11 can't change the color
4267 depth, and some apps are pretty angry if they SetDisplayMode from
4268 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4270 Also don't relay to the swapchain because with ddraw it's possible
4271 that there isn't a swapchain at all */
4272 pMode->Width = This->ddraw_width;
4273 pMode->Height = This->ddraw_height;
4274 pMode->Format = This->ddraw_format;
4275 pMode->RefreshRate = 0;
4276 hr = WINED3D_OK;
4279 return hr;
4282 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4284 TRACE("(%p)->(%p)\n", This, hWnd);
4286 if(This->ddraw_fullscreen) {
4287 if(This->ddraw_window && This->ddraw_window != hWnd) {
4288 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4290 if(hWnd && This->ddraw_window != hWnd) {
4291 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4295 This->ddraw_window = hWnd;
4296 return WINED3D_OK;
4299 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4301 TRACE("(%p)->(%p)\n", This, hWnd);
4303 *hWnd = This->ddraw_window;
4304 return WINED3D_OK;
4307 /*****
4308 * Stateblock related functions
4309 *****/
4311 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4313 IWineD3DStateBlockImpl *object;
4314 HRESULT temp_result;
4315 int i;
4317 TRACE("(%p)\n", This);
4319 if (This->isRecordingState) {
4320 return WINED3DERR_INVALIDCALL;
4323 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4324 if (NULL == object ) {
4325 FIXME("(%p)Error allocating memory for stateblock\n", This);
4326 return E_OUTOFMEMORY;
4328 TRACE("(%p) created object %p\n", This, object);
4329 object->wineD3DDevice= This;
4330 /** FIXME: object->parent = parent; **/
4331 object->parent = NULL;
4332 object->blockType = WINED3DSBT_ALL;
4333 object->ref = 1;
4334 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4336 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4337 list_init(&object->lightMap[i]);
4340 temp_result = allocate_shader_constants(object);
4341 if (WINED3D_OK != temp_result)
4342 return temp_result;
4344 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4345 This->updateStateBlock = object;
4346 This->isRecordingState = TRUE;
4348 TRACE("(%p) recording stateblock %p\n",This , object);
4349 return WINED3D_OK;
4352 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4353 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4355 if (!This->isRecordingState) {
4356 FIXME("(%p) not recording! returning error\n", This);
4357 *ppStateBlock = NULL;
4358 return WINED3DERR_INVALIDCALL;
4361 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4362 This->isRecordingState = FALSE;
4363 This->updateStateBlock = This->stateBlock;
4364 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4365 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4366 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4367 return WINED3D_OK;
4370 /*****
4371 * Scene related functions
4372 *****/
4373 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4374 /* At the moment we have no need for any functionality at the beginning
4375 of a scene */
4376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4377 TRACE("(%p)\n", This);
4379 if(This->inScene) {
4380 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4381 return WINED3DERR_INVALIDCALL;
4383 This->inScene = TRUE;
4384 return WINED3D_OK;
4387 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4389 TRACE("(%p)\n", This);
4391 if(!This->inScene) {
4392 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4393 return WINED3DERR_INVALIDCALL;
4396 ENTER_GL();
4397 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4398 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4400 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4401 glFlush();
4402 checkGLcall("glFlush");
4403 LEAVE_GL();
4405 This->inScene = FALSE;
4406 return WINED3D_OK;
4409 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4410 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4411 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4413 IWineD3DSwapChain *swapChain = NULL;
4414 int i;
4415 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4417 TRACE("(%p) Presenting the frame\n", This);
4419 for(i = 0 ; i < swapchains ; i ++) {
4421 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4422 TRACE("presentinng chain %d, %p\n", i, swapChain);
4423 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4424 IWineD3DSwapChain_Release(swapChain);
4427 return WINED3D_OK;
4430 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4431 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4433 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4435 GLbitfield glMask = 0;
4436 unsigned int i;
4437 CONST WINED3DRECT* curRect;
4439 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4440 Count, pRects, Flags, Color, Z, Stencil);
4442 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4443 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4444 /* TODO: What about depth stencil buffers without stencil bits? */
4445 return WINED3DERR_INVALIDCALL;
4448 ENTER_GL();
4449 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4450 * and not the last active one.
4453 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4454 apply_fbo_state(iface);
4457 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
4459 glEnable(GL_SCISSOR_TEST);
4460 checkGLcall("glEnable GL_SCISSOR_TEST");
4461 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4462 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4464 if (Count > 0 && pRects) {
4465 curRect = pRects;
4466 } else {
4467 curRect = NULL;
4470 /* Only set the values up once, as they are not changing */
4471 if (Flags & WINED3DCLEAR_STENCIL) {
4472 glClearStencil(Stencil);
4473 checkGLcall("glClearStencil");
4474 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4475 glStencilMask(0xFFFFFFFF);
4478 if (Flags & WINED3DCLEAR_ZBUFFER) {
4479 glDepthMask(GL_TRUE);
4480 glClearDepth(Z);
4481 checkGLcall("glClearDepth");
4482 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4483 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4486 if (Flags & WINED3DCLEAR_TARGET) {
4487 TRACE("Clearing screen with glClear to color %x\n", Color);
4488 glClearColor(D3DCOLOR_R(Color),
4489 D3DCOLOR_G(Color),
4490 D3DCOLOR_B(Color),
4491 D3DCOLOR_A(Color));
4492 checkGLcall("glClearColor");
4494 /* Clear ALL colors! */
4495 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4496 glMask = glMask | GL_COLOR_BUFFER_BIT;
4499 if (!curRect) {
4500 /* In drawable flag is set below */
4502 glScissor(This->stateBlock->viewport.X,
4503 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4504 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4505 This->stateBlock->viewport.Width,
4506 This->stateBlock->viewport.Height);
4507 checkGLcall("glScissor");
4508 glClear(glMask);
4509 checkGLcall("glClear");
4510 } else {
4511 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4512 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4514 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4515 curRect[0].x2 < target->currentDesc.Width ||
4516 curRect[0].y2 < target->currentDesc.Height) {
4517 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4518 blt_to_drawable(This, target);
4522 /* Now process each rect in turn */
4523 for (i = 0; i < Count; i++) {
4524 /* Note gl uses lower left, width/height */
4525 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4526 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4527 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4528 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4530 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4531 * The rectangle is not cleared, no error is returned, but further rectanlges are
4532 * still cleared if they are valid
4534 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4535 TRACE("Rectangle with negative dimensions, ignoring\n");
4536 continue;
4539 if(This->render_offscreen) {
4540 glScissor(curRect[i].x1, curRect[i].y1,
4541 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4542 } else {
4543 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4544 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4546 checkGLcall("glScissor");
4548 glClear(glMask);
4549 checkGLcall("glClear");
4553 /* Restore the old values (why..?) */
4554 if (Flags & WINED3DCLEAR_STENCIL) {
4555 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4557 if (Flags & WINED3DCLEAR_TARGET) {
4558 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4559 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4560 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4561 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4562 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4565 LEAVE_GL();
4567 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4568 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4570 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4571 target->Flags |= SFLAG_INTEXTURE;
4572 target->Flags &= ~SFLAG_INSYSMEM;
4573 } else {
4574 target->Flags |= SFLAG_INDRAWABLE;
4575 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4577 return WINED3D_OK;
4580 /*****
4581 * Drawing functions
4582 *****/
4583 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4584 UINT PrimitiveCount) {
4586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4588 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4589 debug_d3dprimitivetype(PrimitiveType),
4590 StartVertex, PrimitiveCount);
4592 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4593 if(This->stateBlock->streamIsUP) {
4594 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4595 This->stateBlock->streamIsUP = FALSE;
4598 if(This->stateBlock->loadBaseVertexIndex != 0) {
4599 This->stateBlock->loadBaseVertexIndex = 0;
4600 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4602 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4603 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4604 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4605 return WINED3D_OK;
4608 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4609 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4610 WINED3DPRIMITIVETYPE PrimitiveType,
4611 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4614 UINT idxStride = 2;
4615 IWineD3DIndexBuffer *pIB;
4616 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4617 GLuint vbo;
4619 pIB = This->stateBlock->pIndexData;
4620 if (!pIB) {
4621 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4622 * without an index buffer set. (The first time at least...)
4623 * D3D8 simply dies, but I doubt it can do much harm to return
4624 * D3DERR_INVALIDCALL there as well. */
4625 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4626 return WINED3DERR_INVALIDCALL;
4629 if(This->stateBlock->streamIsUP) {
4630 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4631 This->stateBlock->streamIsUP = FALSE;
4633 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4635 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4636 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4637 minIndex, NumVertices, startIndex, primCount);
4639 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4640 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4641 idxStride = 2;
4642 } else {
4643 idxStride = 4;
4646 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4647 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4648 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4651 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4652 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4654 return WINED3D_OK;
4657 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4658 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4659 UINT VertexStreamZeroStride) {
4660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4662 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4663 debug_d3dprimitivetype(PrimitiveType),
4664 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4666 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4667 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4668 This->stateBlock->streamOffset[0] = 0;
4669 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4670 This->stateBlock->streamIsUP = TRUE;
4671 This->stateBlock->loadBaseVertexIndex = 0;
4673 /* TODO: Only mark dirty if drawing from a different UP address */
4674 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4676 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4677 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4679 /* MSDN specifies stream zero settings must be set to NULL */
4680 This->stateBlock->streamStride[0] = 0;
4681 This->stateBlock->streamSource[0] = NULL;
4683 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4684 * the new stream sources or use UP drawing again
4686 return WINED3D_OK;
4689 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4690 UINT MinVertexIndex, UINT NumVertices,
4691 UINT PrimitiveCount, CONST void* pIndexData,
4692 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4693 UINT VertexStreamZeroStride) {
4694 int idxStride;
4695 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4697 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4698 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4699 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4700 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4702 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4703 idxStride = 2;
4704 } else {
4705 idxStride = 4;
4708 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4709 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4710 This->stateBlock->streamIsUP = TRUE;
4711 This->stateBlock->streamOffset[0] = 0;
4712 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4714 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4715 This->stateBlock->baseVertexIndex = 0;
4716 This->stateBlock->loadBaseVertexIndex = 0;
4717 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4718 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4719 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4721 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4723 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4724 This->stateBlock->streamSource[0] = NULL;
4725 This->stateBlock->streamStride[0] = 0;
4726 This->stateBlock->pIndexData = NULL;
4727 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4728 * SetStreamSource to specify a vertex buffer
4731 return WINED3D_OK;
4734 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4737 /* Mark the state dirty until we have nicer tracking
4738 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4739 * that value.
4741 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4742 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4743 This->stateBlock->baseVertexIndex = 0;
4744 This->up_strided = DrawPrimStrideData;
4745 This->stateBlock->streamIsUP = TRUE;
4746 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4747 This->up_strided = NULL;
4748 return WINED3D_OK;
4750 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4751 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4753 HRESULT hr = WINED3D_OK;
4754 WINED3DRESOURCETYPE sourceType;
4755 WINED3DRESOURCETYPE destinationType;
4756 int i ,levels;
4758 /* TODO: think about moving the code into IWineD3DBaseTexture */
4760 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4762 /* verify that the source and destination textures aren't NULL */
4763 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4764 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4765 This, pSourceTexture, pDestinationTexture);
4766 hr = WINED3DERR_INVALIDCALL;
4769 if (pSourceTexture == pDestinationTexture) {
4770 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4771 This, pSourceTexture, pDestinationTexture);
4772 hr = WINED3DERR_INVALIDCALL;
4774 /* Verify that the source and destination textures are the same type */
4775 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4776 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4778 if (sourceType != destinationType) {
4779 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4780 This);
4781 hr = WINED3DERR_INVALIDCALL;
4784 /* check that both textures have the identical numbers of levels */
4785 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4786 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4787 hr = WINED3DERR_INVALIDCALL;
4790 if (WINED3D_OK == hr) {
4792 /* Make sure that the destination texture is loaded */
4793 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4795 /* Update every surface level of the texture */
4796 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4798 switch (sourceType) {
4799 case WINED3DRTYPE_TEXTURE:
4801 IWineD3DSurface *srcSurface;
4802 IWineD3DSurface *destSurface;
4804 for (i = 0 ; i < levels ; ++i) {
4805 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4806 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4807 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4808 IWineD3DSurface_Release(srcSurface);
4809 IWineD3DSurface_Release(destSurface);
4810 if (WINED3D_OK != hr) {
4811 WARN("(%p) : Call to update surface failed\n", This);
4812 return hr;
4816 break;
4817 case WINED3DRTYPE_CUBETEXTURE:
4819 IWineD3DSurface *srcSurface;
4820 IWineD3DSurface *destSurface;
4821 WINED3DCUBEMAP_FACES faceType;
4823 for (i = 0 ; i < levels ; ++i) {
4824 /* Update each cube face */
4825 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4826 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4827 if (WINED3D_OK != hr) {
4828 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4829 } else {
4830 TRACE("Got srcSurface %p\n", srcSurface);
4832 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4833 if (WINED3D_OK != hr) {
4834 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4835 } else {
4836 TRACE("Got desrSurface %p\n", destSurface);
4838 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4839 IWineD3DSurface_Release(srcSurface);
4840 IWineD3DSurface_Release(destSurface);
4841 if (WINED3D_OK != hr) {
4842 WARN("(%p) : Call to update surface failed\n", This);
4843 return hr;
4848 break;
4849 #if 0 /* TODO: Add support for volume textures */
4850 case WINED3DRTYPE_VOLUMETEXTURE:
4852 IWineD3DVolume srcVolume = NULL;
4853 IWineD3DSurface destVolume = NULL;
4855 for (i = 0 ; i < levels ; ++i) {
4856 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4857 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4858 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4859 IWineD3DVolume_Release(srcSurface);
4860 IWineD3DVolume_Release(destSurface);
4861 if (WINED3D_OK != hr) {
4862 WARN("(%p) : Call to update volume failed\n", This);
4863 return hr;
4867 break;
4868 #endif
4869 default:
4870 FIXME("(%p) : Unsupported source and destination type\n", This);
4871 hr = WINED3DERR_INVALIDCALL;
4875 return hr;
4878 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4879 IWineD3DSwapChain *swapChain;
4880 HRESULT hr;
4881 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4882 if(hr == WINED3D_OK) {
4883 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4884 IWineD3DSwapChain_Release(swapChain);
4886 return hr;
4889 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4891 /* return a sensible default */
4892 *pNumPasses = 1;
4893 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4894 FIXME("(%p) : stub\n", This);
4895 return WINED3D_OK;
4898 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4900 int j;
4901 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4902 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4903 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4904 return WINED3DERR_INVALIDCALL;
4906 for (j = 0; j < 256; ++j) {
4907 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4908 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4909 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4910 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4912 TRACE("(%p) : returning\n", This);
4913 return WINED3D_OK;
4916 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4918 int j;
4919 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4920 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4921 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4922 return WINED3DERR_INVALIDCALL;
4924 for (j = 0; j < 256; ++j) {
4925 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4926 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4927 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4928 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4930 TRACE("(%p) : returning\n", This);
4931 return WINED3D_OK;
4934 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4936 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4937 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4938 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4939 return WINED3DERR_INVALIDCALL;
4941 /*TODO: stateblocks */
4942 This->currentPalette = PaletteNumber;
4943 TRACE("(%p) : returning\n", This);
4944 return WINED3D_OK;
4947 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4949 if (PaletteNumber == NULL) {
4950 WARN("(%p) : returning Invalid Call\n", This);
4951 return WINED3DERR_INVALIDCALL;
4953 /*TODO: stateblocks */
4954 *PaletteNumber = This->currentPalette;
4955 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4956 return WINED3D_OK;
4959 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4961 static BOOL showFixmes = TRUE;
4962 if (showFixmes) {
4963 FIXME("(%p) : stub\n", This);
4964 showFixmes = FALSE;
4967 This->softwareVertexProcessing = bSoftware;
4968 return WINED3D_OK;
4972 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4974 static BOOL showFixmes = TRUE;
4975 if (showFixmes) {
4976 FIXME("(%p) : stub\n", This);
4977 showFixmes = FALSE;
4979 return This->softwareVertexProcessing;
4983 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4985 IWineD3DSwapChain *swapChain;
4986 HRESULT hr;
4988 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4990 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4991 if(hr == WINED3D_OK){
4992 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4993 IWineD3DSwapChain_Release(swapChain);
4994 }else{
4995 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4997 return hr;
5001 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5003 static BOOL showfixmes = TRUE;
5004 if(nSegments != 0.0f) {
5005 if( showfixmes) {
5006 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5007 showfixmes = FALSE;
5010 return WINED3D_OK;
5013 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5015 static BOOL showfixmes = TRUE;
5016 if( showfixmes) {
5017 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5018 showfixmes = FALSE;
5020 return 0.0f;
5023 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5025 /** TODO: remove casts to IWineD3DSurfaceImpl
5026 * NOTE: move code to surface to accomplish this
5027 ****************************************/
5028 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5029 int srcWidth, srcHeight;
5030 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5031 WINED3DFORMAT destFormat, srcFormat;
5032 UINT destSize;
5033 int srcLeft, destLeft, destTop;
5034 WINED3DPOOL srcPool, destPool;
5035 int offset = 0;
5036 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5037 glDescriptor *glDescription = NULL;
5039 WINED3DSURFACE_DESC winedesc;
5041 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5042 memset(&winedesc, 0, sizeof(winedesc));
5043 winedesc.Width = &srcSurfaceWidth;
5044 winedesc.Height = &srcSurfaceHeight;
5045 winedesc.Pool = &srcPool;
5046 winedesc.Format = &srcFormat;
5048 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5050 winedesc.Width = &destSurfaceWidth;
5051 winedesc.Height = &destSurfaceHeight;
5052 winedesc.Pool = &destPool;
5053 winedesc.Format = &destFormat;
5054 winedesc.Size = &destSize;
5056 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5058 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5059 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5060 return WINED3DERR_INVALIDCALL;
5063 if (destFormat == WINED3DFMT_UNKNOWN) {
5064 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5065 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5067 /* Get the update surface description */
5068 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5071 ENTER_GL();
5073 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5075 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5076 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5077 checkGLcall("glActiveTextureARB");
5080 /* Make sure the surface is loaded and up to date */
5081 IWineD3DSurface_PreLoad(pDestinationSurface);
5083 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5085 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5086 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5087 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5088 srcLeft = pSourceRect ? pSourceRect->left : 0;
5089 destLeft = pDestPoint ? pDestPoint->x : 0;
5090 destTop = pDestPoint ? pDestPoint->y : 0;
5093 /* This function doesn't support compressed textures
5094 the pitch is just bytesPerPixel * width */
5095 if(srcWidth != srcSurfaceWidth || srcLeft ){
5096 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5097 offset += srcLeft * pSrcSurface->bytesPerPixel;
5098 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5100 /* TODO DXT formats */
5102 if(pSourceRect != NULL && pSourceRect->top != 0){
5103 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5105 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5106 ,This
5107 ,glDescription->level
5108 ,destLeft
5109 ,destTop
5110 ,srcWidth
5111 ,srcHeight
5112 ,glDescription->glFormat
5113 ,glDescription->glType
5114 ,IWineD3DSurface_GetData(pSourceSurface)
5117 /* Sanity check */
5118 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5120 /* need to lock the surface to get the data */
5121 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5124 /* TODO: Cube and volume support */
5125 if(rowoffset != 0){
5126 /* not a whole row so we have to do it a line at a time */
5127 int j;
5129 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5130 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5132 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5134 glTexSubImage2D(glDescription->target
5135 ,glDescription->level
5136 ,destLeft
5138 ,srcWidth
5140 ,glDescription->glFormat
5141 ,glDescription->glType
5142 ,data /* could be quicker using */
5144 data += rowoffset;
5147 } else { /* Full width, so just write out the whole texture */
5149 if (WINED3DFMT_DXT1 == destFormat ||
5150 WINED3DFMT_DXT2 == destFormat ||
5151 WINED3DFMT_DXT3 == destFormat ||
5152 WINED3DFMT_DXT4 == destFormat ||
5153 WINED3DFMT_DXT5 == destFormat) {
5154 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5155 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5156 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5157 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5158 } if (destFormat != srcFormat) {
5159 FIXME("Updating mixed format compressed texture is not curretly support\n");
5160 } else {
5161 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5162 glDescription->level,
5163 glDescription->glFormatInternal,
5164 srcWidth,
5165 srcHeight,
5167 destSize,
5168 IWineD3DSurface_GetData(pSourceSurface));
5170 } else {
5171 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5175 } else {
5176 glTexSubImage2D(glDescription->target
5177 ,glDescription->level
5178 ,destLeft
5179 ,destTop
5180 ,srcWidth
5181 ,srcHeight
5182 ,glDescription->glFormat
5183 ,glDescription->glType
5184 ,IWineD3DSurface_GetData(pSourceSurface)
5188 checkGLcall("glTexSubImage2D");
5190 LEAVE_GL();
5192 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5193 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5194 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5196 return WINED3D_OK;
5199 /* Implementation details at http://developer.nvidia.com/attach/6494
5201 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5202 hmm.. no longer supported use
5203 OpenGL evaluators or tessellate surfaces within your application.
5206 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5207 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5209 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5210 FIXME("(%p) : Stub\n", This);
5211 return WINED3D_OK;
5215 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5216 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5218 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5219 FIXME("(%p) : Stub\n", This);
5220 return WINED3D_OK;
5223 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5225 TRACE("(%p) Handle(%d)\n", This, Handle);
5226 FIXME("(%p) : Stub\n", This);
5227 return WINED3D_OK;
5230 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5231 HRESULT hr;
5232 IWineD3DSwapChain *swapchain;
5234 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5235 if (SUCCEEDED(hr)) {
5236 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5237 return swapchain;
5240 return NULL;
5243 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5246 if (!*fbo) {
5247 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5248 checkGLcall("glGenFramebuffersEXT()");
5250 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5251 checkGLcall("glBindFramebuffer()");
5254 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5255 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5256 IWineD3DBaseTextureImpl *texture_impl;
5257 GLenum texttarget, target;
5258 GLint old_binding;
5260 texttarget = surface_impl->glDescription.target;
5261 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5262 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5264 IWineD3DSurface_PreLoad(surface);
5266 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5267 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5268 glBindTexture(target, old_binding);
5270 /* Update base texture states array */
5271 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5272 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5273 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5274 if (texture_impl->baseTexture.bindCount) {
5275 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5278 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5281 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5283 checkGLcall("attach_surface_fbo");
5286 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5288 IWineD3DSwapChain *swapchain;
5290 swapchain = get_swapchain(surface);
5291 if (swapchain) {
5292 GLenum buffer;
5294 TRACE("Surface %p is onscreen\n", surface);
5296 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5297 buffer = surface_get_gl_buffer(surface, swapchain);
5298 glDrawBuffer(buffer);
5299 checkGLcall("glDrawBuffer()");
5300 } else {
5301 TRACE("Surface %p is offscreen\n", surface);
5302 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5303 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5306 if (rect) {
5307 glEnable(GL_SCISSOR_TEST);
5308 if(!swapchain) {
5309 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5310 } else {
5311 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5312 rect->x2 - rect->x1, rect->y2 - rect->y1);
5314 checkGLcall("glScissor");
5315 } else {
5316 glDisable(GL_SCISSOR_TEST);
5318 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5320 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5321 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5323 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5324 glClear(GL_COLOR_BUFFER_BIT);
5325 checkGLcall("glClear");
5327 if (This->render_offscreen) {
5328 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5329 } else {
5330 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5331 checkGLcall("glBindFramebuffer()");
5334 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5335 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5336 glDrawBuffer(GL_BACK);
5337 checkGLcall("glDrawBuffer()");
5341 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5343 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5344 WINEDDBLTFX BltFx;
5345 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5347 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5348 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5349 return WINED3DERR_INVALIDCALL;
5352 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5353 color_fill_fbo(iface, pSurface, pRect, color);
5354 return WINED3D_OK;
5355 } else {
5356 /* Just forward this to the DirectDraw blitting engine */
5357 memset(&BltFx, 0, sizeof(BltFx));
5358 BltFx.dwSize = sizeof(BltFx);
5359 BltFx.u5.dwFillColor = color;
5360 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5364 /* rendertarget and deptth stencil functions */
5365 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5368 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5369 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5370 return WINED3DERR_INVALIDCALL;
5373 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5374 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5375 /* Note inc ref on returned surface */
5376 if(*ppRenderTarget != NULL)
5377 IWineD3DSurface_AddRef(*ppRenderTarget);
5378 return WINED3D_OK;
5381 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5383 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5384 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5385 IWineD3DSwapChainImpl *Swapchain;
5386 HRESULT hr;
5388 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5390 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5391 if(hr != WINED3D_OK) {
5392 ERR("Can't get the swapchain\n");
5393 return hr;
5396 /* Make sure to release the swapchain */
5397 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5399 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5400 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5401 return WINED3DERR_INVALIDCALL;
5403 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5404 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5405 return WINED3DERR_INVALIDCALL;
5408 if(Swapchain->frontBuffer != Front) {
5409 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5411 if(Swapchain->frontBuffer)
5412 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5413 Swapchain->frontBuffer = Front;
5415 if(Swapchain->frontBuffer) {
5416 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5420 if(Back && !Swapchain->backBuffer) {
5421 /* We need memory for the back buffer array - only one back buffer this way */
5422 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5423 if(!Swapchain->backBuffer) {
5424 ERR("Out of memory\n");
5425 return E_OUTOFMEMORY;
5429 if(Swapchain->backBuffer[0] != Back) {
5430 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5432 /* What to do about the context here in the case of multithreading? Not sure.
5433 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5435 ENTER_GL();
5436 if(!Swapchain->backBuffer[0]) {
5437 /* GL was told to draw to the front buffer at creation,
5438 * undo that
5440 glDrawBuffer(GL_BACK);
5441 checkGLcall("glDrawBuffer(GL_BACK)");
5442 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5443 Swapchain->presentParms.BackBufferCount = 1;
5444 } else if (!Back) {
5445 /* That makes problems - disable for now */
5446 /* glDrawBuffer(GL_FRONT); */
5447 checkGLcall("glDrawBuffer(GL_FRONT)");
5448 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5449 Swapchain->presentParms.BackBufferCount = 0;
5451 LEAVE_GL();
5453 if(Swapchain->backBuffer[0])
5454 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5455 Swapchain->backBuffer[0] = Back;
5457 if(Swapchain->backBuffer[0]) {
5458 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5459 } else {
5460 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5465 return WINED3D_OK;
5468 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5470 *ppZStencilSurface = This->depthStencilBuffer;
5471 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5473 if(*ppZStencilSurface != NULL) {
5474 /* Note inc ref on returned surface */
5475 IWineD3DSurface_AddRef(*ppZStencilSurface);
5477 return WINED3D_OK;
5480 /* TODO: Handle stencil attachments */
5481 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5483 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5485 TRACE("Set depth stencil to %p\n", depth_stencil);
5487 if (depth_stencil_impl) {
5488 if (depth_stencil_impl->current_renderbuffer) {
5489 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5490 checkGLcall("glFramebufferRenderbufferEXT()");
5491 } else {
5492 IWineD3DBaseTextureImpl *texture_impl;
5493 GLenum texttarget, target;
5494 GLint old_binding = 0;
5496 texttarget = depth_stencil_impl->glDescription.target;
5497 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5498 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5500 IWineD3DSurface_PreLoad(depth_stencil);
5502 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5503 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5504 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5505 glBindTexture(target, old_binding);
5507 /* Update base texture states array */
5508 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5509 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5510 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5511 if (texture_impl->baseTexture.bindCount) {
5512 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5515 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5518 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5519 checkGLcall("glFramebufferTexture2DEXT()");
5521 } else {
5522 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5523 checkGLcall("glFramebufferTexture2DEXT()");
5527 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5529 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5531 TRACE("Set render target %u to %p\n", idx, render_target);
5533 if (rtimpl) {
5534 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5535 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5536 } else {
5537 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5538 checkGLcall("glFramebufferTexture2DEXT()");
5540 This->draw_buffers[idx] = GL_NONE;
5544 static void check_fbo_status(IWineD3DDevice *iface) {
5545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5546 GLenum status;
5548 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5549 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5550 TRACE("FBO complete\n");
5551 } else {
5552 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5554 /* Dump the FBO attachments */
5555 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5556 IWineD3DSurfaceImpl *attachment;
5557 int i;
5559 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5560 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5561 if (attachment) {
5562 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5563 attachment->pow2Width, attachment->pow2Height);
5566 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5567 if (attachment) {
5568 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5569 attachment->pow2Width, attachment->pow2Height);
5575 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5577 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5578 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5580 if (!ds_impl) return FALSE;
5582 if (ds_impl->current_renderbuffer) {
5583 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5584 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5587 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5588 rt_impl->pow2Height != ds_impl->pow2Height);
5591 void apply_fbo_state(IWineD3DDevice *iface) {
5592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5593 unsigned int i;
5595 if (This->render_offscreen) {
5596 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5598 /* Apply render targets */
5599 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5600 IWineD3DSurface *render_target = This->render_targets[i];
5601 if (This->fbo_color_attachments[i] != render_target) {
5602 set_render_target_fbo(iface, i, render_target);
5603 This->fbo_color_attachments[i] = render_target;
5607 /* Apply depth targets */
5608 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5609 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5610 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5612 if (This->stencilBufferTarget) {
5613 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5615 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5616 This->fbo_depth_attachment = This->stencilBufferTarget;
5619 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5620 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5621 checkGLcall("glDrawBuffers()");
5622 } else {
5623 glDrawBuffer(This->draw_buffers[0]);
5624 checkGLcall("glDrawBuffer()");
5626 } else {
5627 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5630 check_fbo_status(iface);
5633 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5634 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5636 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5637 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5638 GLenum gl_filter;
5640 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5641 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5642 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5643 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5645 switch (filter) {
5646 case WINED3DTEXF_LINEAR:
5647 gl_filter = GL_LINEAR;
5648 break;
5650 default:
5651 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5652 case WINED3DTEXF_NONE:
5653 case WINED3DTEXF_POINT:
5654 gl_filter = GL_NEAREST;
5655 break;
5658 /* Attach src surface to src fbo */
5659 src_swapchain = get_swapchain(src_surface);
5660 ENTER_GL();
5661 if (src_swapchain) {
5662 GLenum buffer;
5664 TRACE("Source surface %p is onscreen\n", src_surface);
5665 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5667 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5668 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5669 glReadBuffer(buffer);
5670 checkGLcall("glReadBuffer()");
5672 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5673 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5674 } else {
5675 TRACE("Source surface %p is offscreen\n", src_surface);
5676 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5677 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5678 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5679 checkGLcall("glReadBuffer()");
5682 /* Attach dst surface to dst fbo */
5683 dst_swapchain = get_swapchain(dst_surface);
5684 if (dst_swapchain) {
5685 GLenum buffer;
5687 TRACE("Destination surface %p is onscreen\n", dst_surface);
5688 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5690 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5691 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5692 glDrawBuffer(buffer);
5693 checkGLcall("glDrawBuffer()");
5695 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5696 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5697 } else {
5698 TRACE("Destination surface %p is offscreen\n", dst_surface);
5700 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5701 if(!src_swapchain) {
5702 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5705 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5706 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5707 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5708 checkGLcall("glDrawBuffer()");
5710 glDisable(GL_SCISSOR_TEST);
5711 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5713 if (flip) {
5714 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5715 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5716 checkGLcall("glBlitFramebuffer()");
5717 } else {
5718 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5719 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5720 checkGLcall("glBlitFramebuffer()");
5723 if (This->render_offscreen) {
5724 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5725 } else {
5726 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5727 checkGLcall("glBindFramebuffer()");
5730 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5731 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5732 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5733 glDrawBuffer(GL_BACK);
5734 checkGLcall("glDrawBuffer()");
5736 LEAVE_GL();
5739 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5741 WINED3DVIEWPORT viewport;
5743 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5745 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5746 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5747 return WINED3DERR_INVALIDCALL;
5750 /* MSDN says that null disables the render target
5751 but a device must always be associated with a render target
5752 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5754 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5755 for more details
5757 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5758 FIXME("Trying to set render target 0 to NULL\n");
5759 return WINED3DERR_INVALIDCALL;
5761 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5762 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);
5763 return WINED3DERR_INVALIDCALL;
5766 /* If we are trying to set what we already have, don't bother */
5767 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5768 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5769 return WINED3D_OK;
5771 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5772 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5773 This->render_targets[RenderTargetIndex] = pRenderTarget;
5775 /* Render target 0 is special */
5776 if(RenderTargetIndex == 0) {
5777 /* Finally, reset the viewport as the MSDN states. */
5778 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5779 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5780 viewport.X = 0;
5781 viewport.Y = 0;
5782 viewport.MaxZ = 1.0f;
5783 viewport.MinZ = 0.0f;
5784 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5785 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5786 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5788 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5790 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5791 * ctx properly.
5792 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5793 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5795 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5797 return WINED3D_OK;
5800 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5802 HRESULT hr = WINED3D_OK;
5803 IWineD3DSurface *tmp;
5805 TRACE("(%p) Swapping z-buffer\n",This);
5807 if (pNewZStencil == This->stencilBufferTarget) {
5808 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5809 } else {
5810 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5811 * depending on the renter target implementation being used.
5812 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5813 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5814 * stencil buffer and incure an extra memory overhead
5815 ******************************************************/
5817 tmp = This->stencilBufferTarget;
5818 This->stencilBufferTarget = pNewZStencil;
5819 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5820 /* should we be calling the parent or the wined3d surface? */
5821 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5822 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5823 hr = WINED3D_OK;
5825 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5826 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5827 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5828 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5829 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5833 return hr;
5836 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5837 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5839 /* TODO: the use of Impl is deprecated. */
5840 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5841 WINED3DLOCKED_RECT lockedRect;
5843 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5845 /* some basic validation checks */
5846 if(This->cursorTexture) {
5847 ENTER_GL();
5848 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5849 glDeleteTextures(1, &This->cursorTexture);
5850 LEAVE_GL();
5851 This->cursorTexture = 0;
5854 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5855 This->haveHardwareCursor = TRUE;
5856 else
5857 This->haveHardwareCursor = FALSE;
5859 if(pCursorBitmap) {
5860 WINED3DLOCKED_RECT rect;
5862 /* MSDN: Cursor must be A8R8G8B8 */
5863 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5864 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5865 return WINED3DERR_INVALIDCALL;
5868 /* MSDN: Cursor must be smaller than the display mode */
5869 if(pSur->currentDesc.Width > This->ddraw_width ||
5870 pSur->currentDesc.Height > This->ddraw_height) {
5871 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);
5872 return WINED3DERR_INVALIDCALL;
5875 if (!This->haveHardwareCursor) {
5876 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5878 /* Do not store the surface's pointer because the application may
5879 * release it after setting the cursor image. Windows doesn't
5880 * addref the set surface, so we can't do this either without
5881 * creating circular refcount dependencies. Copy out the gl texture
5882 * instead.
5884 This->cursorWidth = pSur->currentDesc.Width;
5885 This->cursorHeight = pSur->currentDesc.Height;
5886 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5888 const PixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8);
5889 char *mem, *bits = (char *)rect.pBits;
5890 GLint intfmt = tableEntry->glInternal;
5891 GLint format = tableEntry->glFormat;
5892 GLint type = tableEntry->glType;
5893 INT height = This->cursorHeight;
5894 INT width = This->cursorWidth;
5895 INT bpp = tableEntry->bpp;
5896 INT i;
5898 /* Reformat the texture memory (pitch and width can be
5899 * different) */
5900 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5901 for(i = 0; i < height; i++)
5902 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5903 IWineD3DSurface_UnlockRect(pCursorBitmap);
5904 ENTER_GL();
5906 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5907 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5908 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5911 /* Make sure that a proper texture unit is selected */
5912 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5913 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5914 checkGLcall("glActiveTextureARB");
5916 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5917 /* Create a new cursor texture */
5918 glGenTextures(1, &This->cursorTexture);
5919 checkGLcall("glGenTextures");
5920 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5921 checkGLcall("glBindTexture");
5922 /* Copy the bitmap memory into the cursor texture */
5923 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5924 HeapFree(GetProcessHeap(), 0, mem);
5925 checkGLcall("glTexImage2D");
5927 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5928 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5929 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5932 LEAVE_GL();
5934 else
5936 FIXME("A cursor texture was not returned.\n");
5937 This->cursorTexture = 0;
5940 else
5942 /* Draw a hardware cursor */
5943 ICONINFO cursorInfo;
5944 HCURSOR cursor;
5945 /* Create and clear maskBits because it is not needed for
5946 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5947 * chunks. */
5948 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5949 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
5950 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
5951 WINED3DLOCK_NO_DIRTY_UPDATE |
5952 WINED3DLOCK_READONLY
5954 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
5955 pSur->currentDesc.Height);
5957 cursorInfo.fIcon = FALSE;
5958 cursorInfo.xHotspot = XHotSpot;
5959 cursorInfo.yHotspot = YHotSpot;
5960 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
5961 pSur->currentDesc.Height, 1,
5962 1, &maskBits);
5963 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
5964 pSur->currentDesc.Height, 1,
5965 32, lockedRect.pBits);
5966 IWineD3DSurface_UnlockRect(pCursorBitmap);
5967 /* Create our cursor and clean up. */
5968 cursor = CreateIconIndirect(&cursorInfo);
5969 SetCursor(cursor);
5970 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5971 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5972 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5973 This->hardwareCursor = cursor;
5974 HeapFree(GetProcessHeap(), 0, maskBits);
5978 This->xHotSpot = XHotSpot;
5979 This->yHotSpot = YHotSpot;
5980 return WINED3D_OK;
5983 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5985 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5987 This->xScreenSpace = XScreenSpace;
5988 This->yScreenSpace = YScreenSpace;
5990 return;
5994 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5996 BOOL oldVisible = This->bCursorVisible;
5997 POINT pt;
5999 TRACE("(%p) : visible(%d)\n", This, bShow);
6002 * When ShowCursor is first called it should make the cursor appear at the OS's last
6003 * known cursor position. Because of this, some applications just repetitively call
6004 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6006 GetCursorPos(&pt);
6007 This->xScreenSpace = pt.x;
6008 This->yScreenSpace = pt.y;
6010 if (This->haveHardwareCursor) {
6011 This->bCursorVisible = bShow;
6012 if (bShow)
6013 SetCursor(This->hardwareCursor);
6014 else
6015 SetCursor(NULL);
6017 else
6019 if (This->cursorTexture)
6020 This->bCursorVisible = bShow;
6023 return oldVisible;
6026 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6028 TRACE("(%p) : state (%u)\n", This, This->state);
6029 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6030 switch (This->state) {
6031 case WINED3D_OK:
6032 return WINED3D_OK;
6033 case WINED3DERR_DEVICELOST:
6035 ResourceList *resourceList = This->resources;
6036 while (NULL != resourceList) {
6037 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6038 return WINED3DERR_DEVICENOTRESET;
6039 resourceList = resourceList->next;
6041 return WINED3DERR_DEVICELOST;
6043 case WINED3DERR_DRIVERINTERNALERROR:
6044 return WINED3DERR_DRIVERINTERNALERROR;
6047 /* Unknown state */
6048 return WINED3DERR_DRIVERINTERNALERROR;
6052 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6054 /** FIXME: Resource tracking needs to be done,
6055 * The closes we can do to this is set the priorities of all managed textures low
6056 * and then reset them.
6057 ***********************************************************/
6058 FIXME("(%p) : stub\n", This);
6059 return WINED3D_OK;
6062 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6063 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6065 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6066 if(surface->Flags & SFLAG_DIBSECTION) {
6067 /* Release the DC */
6068 SelectObject(surface->hDC, surface->dib.holdbitmap);
6069 DeleteDC(surface->hDC);
6070 /* Release the DIB section */
6071 DeleteObject(surface->dib.DIBsection);
6072 surface->dib.bitmap_data = NULL;
6073 surface->resource.allocatedMemory = NULL;
6074 surface->Flags &= ~SFLAG_DIBSECTION;
6076 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6077 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6078 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6079 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6080 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6081 } else {
6082 surface->pow2Width = surface->pow2Height = 1;
6083 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6084 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6086 if(surface->glDescription.textureName) {
6087 ENTER_GL();
6088 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6089 glDeleteTextures(1, &surface->glDescription.textureName);
6090 LEAVE_GL();
6091 surface->glDescription.textureName = 0;
6092 surface->Flags &= ~SFLAG_CLIENT;
6094 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6095 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6096 surface->Flags |= SFLAG_NONPOW2;
6097 } else {
6098 surface->Flags &= ~SFLAG_NONPOW2;
6100 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6101 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6104 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6106 IWineD3DSwapChainImpl *swapchain;
6107 HRESULT hr;
6108 BOOL DisplayModeChanged = FALSE;
6109 WINED3DDISPLAYMODE mode;
6110 TRACE("(%p)\n", This);
6112 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6113 if(FAILED(hr)) {
6114 ERR("Failed to get the first implicit swapchain\n");
6115 return hr;
6118 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6119 * on an existing gl context, so there's no real need for recreation.
6121 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6123 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6125 TRACE("New params:\n");
6126 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6127 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6128 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6129 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6130 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6131 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6132 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6133 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6134 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6135 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6136 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6137 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6138 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6140 /* No special treatment of these parameters. Just store them */
6141 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6142 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6143 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6144 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6146 /* What to do about these? */
6147 if(pPresentationParameters->BackBufferCount != 0 &&
6148 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6149 ERR("Cannot change the back buffer count yet\n");
6151 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6152 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6153 ERR("Cannot change the back buffer format yet\n");
6155 if(pPresentationParameters->hDeviceWindow != NULL &&
6156 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6157 ERR("Cannot change the device window yet\n");
6159 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6160 ERR("What do do about a changed auto depth stencil parameter?\n");
6163 if(pPresentationParameters->Windowed) {
6164 mode.Width = swapchain->orig_width;
6165 mode.Height = swapchain->orig_height;
6166 mode.RefreshRate = 0;
6167 mode.Format = swapchain->presentParms.BackBufferFormat;
6168 } else {
6169 mode.Width = pPresentationParameters->BackBufferWidth;
6170 mode.Height = pPresentationParameters->BackBufferHeight;
6171 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6172 mode.Format = swapchain->presentParms.BackBufferFormat;
6175 /* Should Width == 800 && Height == 0 set 800x600? */
6176 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6177 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6178 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6180 WINED3DVIEWPORT vp;
6181 int i;
6183 vp.X = 0;
6184 vp.Y = 0;
6185 vp.Width = pPresentationParameters->BackBufferWidth;
6186 vp.Height = pPresentationParameters->BackBufferHeight;
6187 vp.MinZ = 0;
6188 vp.MaxZ = 1;
6190 if(!pPresentationParameters->Windowed) {
6191 DisplayModeChanged = TRUE;
6193 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6194 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6196 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6197 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6198 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6201 /* Now set the new viewport */
6202 IWineD3DDevice_SetViewport(iface, &vp);
6205 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6206 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6207 DisplayModeChanged) {
6209 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6210 if(!pPresentationParameters->Windowed) {
6211 IWineD3DDevice_SetFullscreen(iface, TRUE);
6214 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6216 /* Switching out of fullscreen mode? First set the original res, then change the window */
6217 if(pPresentationParameters->Windowed) {
6218 IWineD3DDevice_SetFullscreen(iface, FALSE);
6220 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6223 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6224 return WINED3D_OK;
6227 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6229 /** FIXME: always true at the moment **/
6230 if(!bEnableDialogs) {
6231 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6233 return WINED3D_OK;
6237 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6238 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6239 TRACE("(%p) : pParameters %p\n", This, pParameters);
6241 *pParameters = This->createParms;
6242 return WINED3D_OK;
6245 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6246 IWineD3DSwapChain *swapchain;
6247 HRESULT hrc = WINED3D_OK;
6249 TRACE("Relaying to swapchain\n");
6251 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6252 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6253 IWineD3DSwapChain_Release(swapchain);
6255 return;
6258 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6259 IWineD3DSwapChain *swapchain;
6260 HRESULT hrc = WINED3D_OK;
6262 TRACE("Relaying to swapchain\n");
6264 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6265 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6266 IWineD3DSwapChain_Release(swapchain);
6268 return;
6272 /** ********************************************************
6273 * Notification functions
6274 ** ********************************************************/
6275 /** This function must be called in the release of a resource when ref == 0,
6276 * the contents of resource must still be correct,
6277 * any handels to other resource held by the caller must be closed
6278 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6279 *****************************************************/
6280 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6282 ResourceList* resourceList;
6284 TRACE("(%p) : resource %p\n", This, resource);
6285 /* add a new texture to the frot of the linked list */
6286 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6287 resourceList->resource = resource;
6289 /* Get the old head */
6290 resourceList->next = This->resources;
6292 This->resources = resourceList;
6293 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6295 return;
6298 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6300 ResourceList* resourceList = NULL;
6301 ResourceList* previousResourceList = NULL;
6303 TRACE("(%p) : resource %p\n", This, resource);
6305 resourceList = This->resources;
6307 while (resourceList != NULL) {
6308 if(resourceList->resource == resource) break;
6309 previousResourceList = resourceList;
6310 resourceList = resourceList->next;
6313 if (resourceList == NULL) {
6314 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6315 return;
6316 } else {
6317 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6319 /* make sure we don't leave a hole in the list */
6320 if (previousResourceList != NULL) {
6321 previousResourceList->next = resourceList->next;
6322 } else {
6323 This->resources = resourceList->next;
6326 return;
6330 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6332 int counter;
6334 TRACE("(%p) : resource %p\n", This, resource);
6335 switch(IWineD3DResource_GetType(resource)){
6336 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6337 case WINED3DRTYPE_SURFACE: {
6338 unsigned int i;
6340 /* Cleanup any FBO attachments */
6341 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6342 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6343 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6344 set_render_target_fbo(iface, i, NULL);
6345 This->fbo_color_attachments[i] = NULL;
6348 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6349 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6350 set_depth_stencil_fbo(iface, NULL);
6351 This->fbo_depth_attachment = NULL;
6354 break;
6357 case WINED3DRTYPE_TEXTURE:
6358 case WINED3DRTYPE_CUBETEXTURE:
6359 case WINED3DRTYPE_VOLUMETEXTURE:
6360 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6361 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6362 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6363 This->stateBlock->textures[counter] = NULL;
6365 if (This->updateStateBlock != This->stateBlock ){
6366 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6367 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6368 This->updateStateBlock->textures[counter] = NULL;
6372 break;
6373 case WINED3DRTYPE_VOLUME:
6374 /* TODO: nothing really? */
6375 break;
6376 case WINED3DRTYPE_VERTEXBUFFER:
6377 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6379 int streamNumber;
6380 TRACE("Cleaning up stream pointers\n");
6382 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6383 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6384 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6386 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6387 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6388 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6389 This->updateStateBlock->streamSource[streamNumber] = 0;
6390 /* Set changed flag? */
6393 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) */
6394 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6395 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6396 This->stateBlock->streamSource[streamNumber] = 0;
6399 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6400 else { /* This shouldn't happen */
6401 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6403 #endif
6407 break;
6408 case WINED3DRTYPE_INDEXBUFFER:
6409 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6410 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6411 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6412 This->updateStateBlock->pIndexData = NULL;
6415 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6416 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6417 This->stateBlock->pIndexData = NULL;
6421 break;
6422 default:
6423 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6424 break;
6428 /* Remove the resoruce from the resourceStore */
6429 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6431 TRACE("Resource released\n");
6435 /**********************************************************
6436 * IWineD3DDevice VTbl follows
6437 **********************************************************/
6439 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6441 /*** IUnknown methods ***/
6442 IWineD3DDeviceImpl_QueryInterface,
6443 IWineD3DDeviceImpl_AddRef,
6444 IWineD3DDeviceImpl_Release,
6445 /*** IWineD3DDevice methods ***/
6446 IWineD3DDeviceImpl_GetParent,
6447 /*** Creation methods**/
6448 IWineD3DDeviceImpl_CreateVertexBuffer,
6449 IWineD3DDeviceImpl_CreateIndexBuffer,
6450 IWineD3DDeviceImpl_CreateStateBlock,
6451 IWineD3DDeviceImpl_CreateSurface,
6452 IWineD3DDeviceImpl_CreateTexture,
6453 IWineD3DDeviceImpl_CreateVolumeTexture,
6454 IWineD3DDeviceImpl_CreateVolume,
6455 IWineD3DDeviceImpl_CreateCubeTexture,
6456 IWineD3DDeviceImpl_CreateQuery,
6457 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6458 IWineD3DDeviceImpl_CreateVertexDeclaration,
6459 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6460 IWineD3DDeviceImpl_CreateVertexShader,
6461 IWineD3DDeviceImpl_CreatePixelShader,
6462 IWineD3DDeviceImpl_CreatePalette,
6463 /*** Odd functions **/
6464 IWineD3DDeviceImpl_Init3D,
6465 IWineD3DDeviceImpl_Uninit3D,
6466 IWineD3DDeviceImpl_SetFullscreen,
6467 IWineD3DDeviceImpl_SetMultithreaded,
6468 IWineD3DDeviceImpl_EvictManagedResources,
6469 IWineD3DDeviceImpl_GetAvailableTextureMem,
6470 IWineD3DDeviceImpl_GetBackBuffer,
6471 IWineD3DDeviceImpl_GetCreationParameters,
6472 IWineD3DDeviceImpl_GetDeviceCaps,
6473 IWineD3DDeviceImpl_GetDirect3D,
6474 IWineD3DDeviceImpl_GetDisplayMode,
6475 IWineD3DDeviceImpl_SetDisplayMode,
6476 IWineD3DDeviceImpl_GetHWND,
6477 IWineD3DDeviceImpl_SetHWND,
6478 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6479 IWineD3DDeviceImpl_GetRasterStatus,
6480 IWineD3DDeviceImpl_GetSwapChain,
6481 IWineD3DDeviceImpl_Reset,
6482 IWineD3DDeviceImpl_SetDialogBoxMode,
6483 IWineD3DDeviceImpl_SetCursorProperties,
6484 IWineD3DDeviceImpl_SetCursorPosition,
6485 IWineD3DDeviceImpl_ShowCursor,
6486 IWineD3DDeviceImpl_TestCooperativeLevel,
6487 /*** Getters and setters **/
6488 IWineD3DDeviceImpl_SetClipPlane,
6489 IWineD3DDeviceImpl_GetClipPlane,
6490 IWineD3DDeviceImpl_SetClipStatus,
6491 IWineD3DDeviceImpl_GetClipStatus,
6492 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6493 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6494 IWineD3DDeviceImpl_SetDepthStencilSurface,
6495 IWineD3DDeviceImpl_GetDepthStencilSurface,
6496 IWineD3DDeviceImpl_SetFVF,
6497 IWineD3DDeviceImpl_GetFVF,
6498 IWineD3DDeviceImpl_SetGammaRamp,
6499 IWineD3DDeviceImpl_GetGammaRamp,
6500 IWineD3DDeviceImpl_SetIndices,
6501 IWineD3DDeviceImpl_GetIndices,
6502 IWineD3DDeviceImpl_SetBaseVertexIndex,
6503 IWineD3DDeviceImpl_GetBaseVertexIndex,
6504 IWineD3DDeviceImpl_SetLight,
6505 IWineD3DDeviceImpl_GetLight,
6506 IWineD3DDeviceImpl_SetLightEnable,
6507 IWineD3DDeviceImpl_GetLightEnable,
6508 IWineD3DDeviceImpl_SetMaterial,
6509 IWineD3DDeviceImpl_GetMaterial,
6510 IWineD3DDeviceImpl_SetNPatchMode,
6511 IWineD3DDeviceImpl_GetNPatchMode,
6512 IWineD3DDeviceImpl_SetPaletteEntries,
6513 IWineD3DDeviceImpl_GetPaletteEntries,
6514 IWineD3DDeviceImpl_SetPixelShader,
6515 IWineD3DDeviceImpl_GetPixelShader,
6516 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6517 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6518 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6519 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6520 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6521 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6522 IWineD3DDeviceImpl_SetRenderState,
6523 IWineD3DDeviceImpl_GetRenderState,
6524 IWineD3DDeviceImpl_SetRenderTarget,
6525 IWineD3DDeviceImpl_GetRenderTarget,
6526 IWineD3DDeviceImpl_SetFrontBackBuffers,
6527 IWineD3DDeviceImpl_SetSamplerState,
6528 IWineD3DDeviceImpl_GetSamplerState,
6529 IWineD3DDeviceImpl_SetScissorRect,
6530 IWineD3DDeviceImpl_GetScissorRect,
6531 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6532 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6533 IWineD3DDeviceImpl_SetStreamSource,
6534 IWineD3DDeviceImpl_GetStreamSource,
6535 IWineD3DDeviceImpl_SetStreamSourceFreq,
6536 IWineD3DDeviceImpl_GetStreamSourceFreq,
6537 IWineD3DDeviceImpl_SetTexture,
6538 IWineD3DDeviceImpl_GetTexture,
6539 IWineD3DDeviceImpl_SetTextureStageState,
6540 IWineD3DDeviceImpl_GetTextureStageState,
6541 IWineD3DDeviceImpl_SetTransform,
6542 IWineD3DDeviceImpl_GetTransform,
6543 IWineD3DDeviceImpl_SetVertexDeclaration,
6544 IWineD3DDeviceImpl_GetVertexDeclaration,
6545 IWineD3DDeviceImpl_SetVertexShader,
6546 IWineD3DDeviceImpl_GetVertexShader,
6547 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6548 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6549 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6550 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6551 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6552 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6553 IWineD3DDeviceImpl_SetViewport,
6554 IWineD3DDeviceImpl_GetViewport,
6555 IWineD3DDeviceImpl_MultiplyTransform,
6556 IWineD3DDeviceImpl_ValidateDevice,
6557 IWineD3DDeviceImpl_ProcessVertices,
6558 /*** State block ***/
6559 IWineD3DDeviceImpl_BeginStateBlock,
6560 IWineD3DDeviceImpl_EndStateBlock,
6561 /*** Scene management ***/
6562 IWineD3DDeviceImpl_BeginScene,
6563 IWineD3DDeviceImpl_EndScene,
6564 IWineD3DDeviceImpl_Present,
6565 IWineD3DDeviceImpl_Clear,
6566 /*** Drawing ***/
6567 IWineD3DDeviceImpl_DrawPrimitive,
6568 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6569 IWineD3DDeviceImpl_DrawPrimitiveUP,
6570 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6571 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6572 IWineD3DDeviceImpl_DrawRectPatch,
6573 IWineD3DDeviceImpl_DrawTriPatch,
6574 IWineD3DDeviceImpl_DeletePatch,
6575 IWineD3DDeviceImpl_ColorFill,
6576 IWineD3DDeviceImpl_UpdateTexture,
6577 IWineD3DDeviceImpl_UpdateSurface,
6578 IWineD3DDeviceImpl_GetFrontBufferData,
6579 /*** object tracking ***/
6580 IWineD3DDeviceImpl_ResourceReleased
6584 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6585 WINED3DRS_ALPHABLENDENABLE ,
6586 WINED3DRS_ALPHAFUNC ,
6587 WINED3DRS_ALPHAREF ,
6588 WINED3DRS_ALPHATESTENABLE ,
6589 WINED3DRS_BLENDOP ,
6590 WINED3DRS_COLORWRITEENABLE ,
6591 WINED3DRS_DESTBLEND ,
6592 WINED3DRS_DITHERENABLE ,
6593 WINED3DRS_FILLMODE ,
6594 WINED3DRS_FOGDENSITY ,
6595 WINED3DRS_FOGEND ,
6596 WINED3DRS_FOGSTART ,
6597 WINED3DRS_LASTPIXEL ,
6598 WINED3DRS_SHADEMODE ,
6599 WINED3DRS_SRCBLEND ,
6600 WINED3DRS_STENCILENABLE ,
6601 WINED3DRS_STENCILFAIL ,
6602 WINED3DRS_STENCILFUNC ,
6603 WINED3DRS_STENCILMASK ,
6604 WINED3DRS_STENCILPASS ,
6605 WINED3DRS_STENCILREF ,
6606 WINED3DRS_STENCILWRITEMASK ,
6607 WINED3DRS_STENCILZFAIL ,
6608 WINED3DRS_TEXTUREFACTOR ,
6609 WINED3DRS_WRAP0 ,
6610 WINED3DRS_WRAP1 ,
6611 WINED3DRS_WRAP2 ,
6612 WINED3DRS_WRAP3 ,
6613 WINED3DRS_WRAP4 ,
6614 WINED3DRS_WRAP5 ,
6615 WINED3DRS_WRAP6 ,
6616 WINED3DRS_WRAP7 ,
6617 WINED3DRS_ZENABLE ,
6618 WINED3DRS_ZFUNC ,
6619 WINED3DRS_ZWRITEENABLE
6622 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6623 WINED3DTSS_ADDRESSW ,
6624 WINED3DTSS_ALPHAARG0 ,
6625 WINED3DTSS_ALPHAARG1 ,
6626 WINED3DTSS_ALPHAARG2 ,
6627 WINED3DTSS_ALPHAOP ,
6628 WINED3DTSS_BUMPENVLOFFSET ,
6629 WINED3DTSS_BUMPENVLSCALE ,
6630 WINED3DTSS_BUMPENVMAT00 ,
6631 WINED3DTSS_BUMPENVMAT01 ,
6632 WINED3DTSS_BUMPENVMAT10 ,
6633 WINED3DTSS_BUMPENVMAT11 ,
6634 WINED3DTSS_COLORARG0 ,
6635 WINED3DTSS_COLORARG1 ,
6636 WINED3DTSS_COLORARG2 ,
6637 WINED3DTSS_COLOROP ,
6638 WINED3DTSS_RESULTARG ,
6639 WINED3DTSS_TEXCOORDINDEX ,
6640 WINED3DTSS_TEXTURETRANSFORMFLAGS
6643 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6644 WINED3DSAMP_ADDRESSU ,
6645 WINED3DSAMP_ADDRESSV ,
6646 WINED3DSAMP_ADDRESSW ,
6647 WINED3DSAMP_BORDERCOLOR ,
6648 WINED3DSAMP_MAGFILTER ,
6649 WINED3DSAMP_MINFILTER ,
6650 WINED3DSAMP_MIPFILTER ,
6651 WINED3DSAMP_MIPMAPLODBIAS ,
6652 WINED3DSAMP_MAXMIPLEVEL ,
6653 WINED3DSAMP_MAXANISOTROPY ,
6654 WINED3DSAMP_SRGBTEXTURE ,
6655 WINED3DSAMP_ELEMENTINDEX
6658 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6659 WINED3DRS_AMBIENT ,
6660 WINED3DRS_AMBIENTMATERIALSOURCE ,
6661 WINED3DRS_CLIPPING ,
6662 WINED3DRS_CLIPPLANEENABLE ,
6663 WINED3DRS_COLORVERTEX ,
6664 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6665 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6666 WINED3DRS_FOGDENSITY ,
6667 WINED3DRS_FOGEND ,
6668 WINED3DRS_FOGSTART ,
6669 WINED3DRS_FOGTABLEMODE ,
6670 WINED3DRS_FOGVERTEXMODE ,
6671 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6672 WINED3DRS_LIGHTING ,
6673 WINED3DRS_LOCALVIEWER ,
6674 WINED3DRS_MULTISAMPLEANTIALIAS ,
6675 WINED3DRS_MULTISAMPLEMASK ,
6676 WINED3DRS_NORMALIZENORMALS ,
6677 WINED3DRS_PATCHEDGESTYLE ,
6678 WINED3DRS_POINTSCALE_A ,
6679 WINED3DRS_POINTSCALE_B ,
6680 WINED3DRS_POINTSCALE_C ,
6681 WINED3DRS_POINTSCALEENABLE ,
6682 WINED3DRS_POINTSIZE ,
6683 WINED3DRS_POINTSIZE_MAX ,
6684 WINED3DRS_POINTSIZE_MIN ,
6685 WINED3DRS_POINTSPRITEENABLE ,
6686 WINED3DRS_RANGEFOGENABLE ,
6687 WINED3DRS_SPECULARMATERIALSOURCE ,
6688 WINED3DRS_TWEENFACTOR ,
6689 WINED3DRS_VERTEXBLEND
6692 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6693 WINED3DTSS_TEXCOORDINDEX ,
6694 WINED3DTSS_TEXTURETRANSFORMFLAGS
6697 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6698 WINED3DSAMP_DMAPOFFSET
6701 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6702 DWORD rep = StateTable[state].representative;
6703 DWORD idx;
6704 BYTE shift;
6705 UINT i;
6706 WineD3DContext *context;
6708 if(!rep) return;
6709 for(i = 0; i < This->numContexts; i++) {
6710 context = This->contexts[i];
6711 if(isStateDirty(context, rep)) continue;
6713 context->dirtyArray[context->numDirtyEntries++] = rep;
6714 idx = rep >> 5;
6715 shift = rep & 0x1f;
6716 context->isStateDirty[idx] |= (1 << shift);