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
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 */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
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 )
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;
74 /* static function declarations */
75 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
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; \
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; \
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); \
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); \
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);
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);
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);
186 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
189 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_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);
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);
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");
260 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
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);
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);
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;
304 case WINED3DUSAGE_WRITEONLY:
306 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
307 glUsage = GL_DYNAMIC_DRAW_ARB;
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);
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));
330 object->Flags |= VBFLAG_VBOCREATEFAIL;
335 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
336 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
339 IWineD3DVertexBufferImpl *object;
340 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
341 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
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);
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
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) ) {
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);
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);
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);
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);
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);
423 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
427 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
428 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
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;
458 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
461 IWineD3DStateBlockImpl *object;
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 */
480 temp_result = allocate_shader_constants(object);
481 if (WINED3D_OK != 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);
488 memset(object->streamFreq, 1, sizeof(object->streamFreq));
490 /* Reset the ref and type after kludging it */
491 object->wineD3DDevice = This;
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++) {
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++) {
572 LIST_FOR_EACH(e, &object->lightMap[j]) {
573 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
574 light->changed = TRUE;
575 light->enabledChanged = TRUE;
579 FIXME("Unrecognized state block type %d\n", Type);
582 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
586 /* ************************************
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.
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
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
613 *******************************/
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
639 *******************************/
641 /* Non-power2 support */
642 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
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
665 *********************************/
666 if (WINED3DFMT_UNKNOWN == Format) {
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));
676 /* The pitch is a multiple of 4 bytes */
677 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
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;
701 object->pow2Width = pow2Width;
702 object->pow2Height = pow2Height;
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;
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 * ****************************************/
727 case WINED3DPOOL_SCRATCH:
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");
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");
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");
747 FIXME("(%p) Unknown pool %d\n", This, Pool);
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 */
768 /* Nothing to do, it's set already */
772 object->lpVtbl = &IWineGDISurface_Vtbl;
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;
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)) {
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 */
839 TRACE("calculating levels %d\n", object->baseTexture.levels);
840 object->baseTexture.levels++;
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 */
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);
861 object->surfaces[i] = NULL;
862 IWineD3DTexture_Release((IWineD3DTexture *)object);
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);
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;
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 */
913 object->baseTexture.levels++;
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 */
931 for (i = 0; i < object->baseTexture.levels; i++)
934 /* Create the volume */
935 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
936 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
939 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
940 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
941 *ppVolumeTexture = NULL;
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);
959 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
960 UINT Width, UINT Height, UINT Depth,
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 **/
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 */
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 */
1033 object->baseTexture.levels++;
1036 tmpW = max(1, tmpW >> 1);
1037 object->baseTexture.levels++;
1039 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1042 /* Generate all the surfaces */
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) {
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;
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;
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 */
1088 case WINED3DQUERYTYPE_OCCLUSION:
1089 TRACE("(%p) occlusion query\n", This);
1090 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1093 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
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);
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:
1119 FIXME("(%p) Unhandled query type %d\n", This, Type);
1121 if(NULL == ppQuery || hr != WINED3D_OK) {
1125 D3DCREATEOBJECTINSTANCE(object, Query)
1126 object->type = Type;
1127 /* allocated the 'extended' data based on the type of query requested */
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));
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");
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:
1162 object->extendedData = 0;
1163 FIXME("(%p) Unhandled query type %d\n",This , Type);
1165 TRACE("(%p) : Created Query %p\n", This, object);
1169 /*****************************************************************************
1170 * IWineD3DDeviceImpl_SetupFullscreenWindow
1172 * Helper function that modifies a HWND's Style and ExStyle for proper
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
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 */
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,
1258 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1259 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1263 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1264 HRESULT hr = WINED3D_OK;
1265 IUnknown *bufferParent;
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))) {
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,
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);
1359 ERR("Failed to create the front buffer\n");
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;
1378 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1381 if (!object->context[0]) {
1382 ERR("Failed to create a new context\n");
1383 hr = WINED3DERR_NOTAVAILABLE;
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) {
1407 /* Get info on the current display setup */
1409 bpp = GetDeviceCaps(hdc, BITSPIXEL);
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) {
1439 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1440 if(!object->backBuffer) {
1441 ERR("Out of memory\n");
1446 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1447 TRACE("calling rendertarget CB\n");
1448 hr = D3DCB_CreateRenderTarget((IUnknown *) This->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);
1461 ERR("Cannot create new back buffer\n");
1465 glDrawBuffer(GL_BACK);
1466 checkGLcall("glDrawBuffer(GL_BACK)");
1470 object->backBuffer = NULL;
1472 /* Single buffering - draw to front buffer */
1474 glDrawBuffer(GL_FRONT);
1475 checkGLcall("glDrawBuffer(GL_FRONT)");
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,
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;
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);
1510 if (object->backBuffer) {
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);
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);
1555 TRACE("Swapchain out of range\n");
1557 return WINED3DERR_INVALIDCALL;
1562 * Vertex Declaration
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);
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;
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));
1614 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1617 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1618 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1619 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1622 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1623 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1625 elements[idx].UsageIndex = 0;
1628 if (has_blend && (num_blends > 0)) {
1629 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1630 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1632 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1633 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1634 elements[idx].UsageIndex = 0;
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;
1644 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1645 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1646 elements[idx].UsageIndex = 0;
1650 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1651 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1652 elements[idx].UsageIndex = 0;
1656 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1657 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1658 elements[idx].UsageIndex = 0;
1662 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1663 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1664 elements[idx].UsageIndex = 0;
1668 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1669 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1670 elements[idx].UsageIndex = 1;
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;
1679 case WINED3DFVF_TEXTUREFORMAT2:
1680 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1682 case WINED3DFVF_TEXTUREFORMAT3:
1683 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1685 case WINED3DFVF_TEXTUREFORMAT4:
1686 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1689 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1690 elements[idx].UsageIndex = idx2;
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;
1706 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1707 WINED3DVERTEXELEMENT* elements = NULL;
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;
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;
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);
1757 WARN("(%p) : Failed to create pixel shader\n", This);
1763 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1765 IWineD3DPaletteImpl *object;
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));
1772 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1773 return E_OUTOFMEMORY;
1776 object->lpVtbl = &IWineD3DPalette_Vtbl;
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));
1786 HeapFree( GetProcessHeap(), 0, object);
1787 return E_OUTOFMEMORY;
1790 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1792 IWineD3DPalette_Release((IWineD3DPalette *) object);
1796 *Palette = (IWineD3DPalette *) object;
1801 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1803 IWineD3DSwapChainImpl *swapchain;
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;
1818 This->texUnitMap[state] = -1;
1819 This->rev_tex_unit_map[state] = -1;
1823 /* Setup the implicit swapchain */
1824 TRACE("Creating implicit swapchain\n");
1825 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1826 if (FAILED(hr) || !swapchain) {
1827 WARN("Failed to create implicit swapchain\n");
1831 This->NumberOfSwapChains = 1;
1832 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1833 if(!This->swapchains) {
1834 ERR("Out of memory!\n");
1835 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1836 return E_OUTOFMEMORY;
1838 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1840 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1842 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1843 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1844 This->render_targets[0] = swapchain->backBuffer[0];
1845 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1848 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1849 This->render_targets[0] = swapchain->frontBuffer;
1850 This->lastActiveRenderTarget = swapchain->frontBuffer;
1852 IWineD3DSurface_AddRef(This->render_targets[0]);
1853 This->activeContext = swapchain->context[0];
1854 This->lastThread = GetCurrentThreadId();
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 */
1865 /* Setup all the devices defaults */
1866 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1868 IWineD3DImpl_CheckGraphicsMemory();
1871 { /* Set a default viewport */
1875 vp.Width = pPresentationParameters->BackBufferWidth;
1876 vp.Height = pPresentationParameters->BackBufferHeight;
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) {
1891 This->offscreenBuffer = GL_BACK;
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;
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);
1909 /* Clear the screen */
1910 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1911 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1914 This->d3d_initialized = TRUE;
1918 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1922 TRACE("(%p)\n", This);
1924 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
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);
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) {
1939 glDeleteTextures(1, &This->cursorTexture);
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;
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
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;
2023 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2027 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
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) ) {
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);
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);
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;
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)));
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);
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");
2132 This->updateStateBlock->fvf = fvf;
2133 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2134 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
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;
2147 * Get / Set Stream Source
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");
2171 This->updateStateBlock->streamSource[StreamNumber] = 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");
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);
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];
2215 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2218 if (*pStream != NULL) {
2219 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
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);
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);
2256 * Get / Set & Multiply Transform
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));
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");
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));
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));
2313 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2314 WINED3DMATRIX *mat = NULL;
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];
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);
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) {
2349 PLIGHTINFOEL *object = NULL;
2350 UINT Hi = LIGHTMAP_HASHFUNC(Index);
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
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
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;
2378 case WINED3DLIGHT_DIRECTIONAL:
2379 /* Ignores attenuation */
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;
2394 TRACE("Adding new light\n");
2395 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*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:
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;
2429 case WINED3DLIGHT_DIRECTIONAL:
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;
2439 case WINED3DLIGHT_SPOT:
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;
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) {
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;
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));
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);
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;
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));
2508 * Get / Set Light Enable
2509 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
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);
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;
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;
2540 if (lightInfo == NULL) {
2541 FIXME("Adding default lights has failed dismally\n");
2542 return WINED3DERR_INVALIDCALL;
2546 lightInfo->enabledChanged = TRUE;
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;
2556 TRACE("Light already disabled, nothing to do\n");
2559 if (lightInfo->glIndex != -1) {
2561 TRACE("Nothing to do as light was enabled\n");
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;
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));
2587 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2589 PLIGHTINFOEL *lightInfo = NULL;
2590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
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;
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;
2611 * Get / Set Clip Planes
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");
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");
2645 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
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];
2668 * Get / Set Clip Plane Status
2669 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
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;
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;
2694 * Get / Set Material
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");
2709 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
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);
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");
2749 if(oldIdxs != pIndexData) {
2750 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
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 */
2762 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2763 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2765 TRACE("(%p) No index data set\n", This);
2767 TRACE("Returning %p\n", *ppIndexData);
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");
2782 This->updateStateBlock->baseVertexIndex = BaseIndex;
2784 if (This->isRecordingState) {
2785 TRACE("Recording... not performing anything\n");
2788 /* The base vertex index affects the stream sources */
2789 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
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);
2805 * Get / Set Viewports
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");
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);
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));
2837 * Get / Set Render States
2838 * TODO: Verify against dx9 definitions
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");
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");
2861 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
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];
2875 * Get / Set Sampler States
2876 * TODO: Verify against dx9 definitions
2879 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
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
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(...).
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");
2916 if(oldValue == Value) {
2917 TRACE("Application is setting the old value over, nothing to do\n");
2921 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
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);
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");
2951 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2953 if(This->isRecordingState) {
2954 TRACE("Recording... not performing anything\n");
2958 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
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);
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");
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");
2990 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
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);
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");
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");
3021 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3023 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
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);
3042 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3043 IWineD3DDevice *iface,
3045 CONST BOOL *srcData,
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);
3071 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3072 IWineD3DDevice *iface,
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));
3090 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3091 IWineD3DDevice *iface,
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);
3120 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3121 IWineD3DDevice *iface,
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);
3139 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3140 IWineD3DDevice *iface,
3142 CONST float *srcData,
3145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
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);
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);
3180 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3181 IWineD3DDevice *iface,
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);
3199 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
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) {
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;
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;
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) {
3263 device_update_fixed_function_usage_map(This);
3265 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || 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);
3278 /* Now work out the mapping */
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);
3293 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3294 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3297 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3298 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3299 device_map_stage(This, i, i);
3300 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3301 if (i < MAX_TEXTURES) {
3302 markTextureStagesDirty(This, i);
3308 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3309 int current_mapping = This->rev_tex_unit_map[unit];
3311 if (current_mapping == -1) {
3312 /* Not currently used */
3316 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3317 /* Used by a fragment sampler */
3319 if (!pshader_sampler_tokens) {
3320 /* No pixel shader, check fixed function */
3321 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3324 /* Pixel shader, check the shader's sampler map */
3325 return !pshader_sampler_tokens[current_mapping];
3328 /* Used by a vertex sampler */
3329 return !vshader_sampler_tokens[current_mapping];
3332 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3333 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3334 DWORD *pshader_sampler_tokens = NULL;
3335 int start = GL_LIMITS(combined_samplers) - 1;
3339 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3341 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3342 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3343 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3346 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3347 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3348 if (vshader_sampler_tokens[i]) {
3349 if (This->texUnitMap[vsampler_idx] != -1) {
3350 /* Already mapped somewhere */
3354 while (start >= 0) {
3355 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3356 device_map_stage(This, vsampler_idx, start);
3357 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3369 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3370 BOOL vs = use_vs(This);
3371 BOOL ps = use_ps(This);
3374 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3375 * that would be really messy and require shader recompilation
3376 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3377 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3380 device_map_psamplers(This);
3382 device_map_fixed_function_samplers(This);
3386 device_map_vsamplers(This, ps);
3390 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3392 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3393 This->updateStateBlock->pixelShader = pShader;
3394 This->updateStateBlock->changed.pixelShader = TRUE;
3395 This->updateStateBlock->set.pixelShader = TRUE;
3397 /* Handle recording of state blocks */
3398 if (This->isRecordingState) {
3399 TRACE("Recording... not performing anything\n");
3402 if (This->isRecordingState) {
3403 TRACE("Recording... not performing anything\n");
3407 if(pShader == oldShader) {
3408 TRACE("App is setting the old pixel shader over, nothing to do\n");
3412 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3413 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3418 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3421 if (NULL == ppShader) {
3422 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3423 return WINED3DERR_INVALIDCALL;
3426 *ppShader = This->stateBlock->pixelShader;
3427 if (NULL != *ppShader) {
3428 IWineD3DPixelShader_AddRef(*ppShader);
3430 TRACE("(%p) : returning %p\n", This, *ppShader);
3434 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3435 IWineD3DDevice *iface,
3437 CONST BOOL *srcData,
3440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3441 int i, cnt = min(count, MAX_CONST_B - start);
3443 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3444 iface, srcData, start, count);
3446 if (srcData == NULL || cnt < 0)
3447 return WINED3DERR_INVALIDCALL;
3449 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3450 for (i = 0; i < cnt; i++)
3451 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3453 for (i = start; i < cnt + start; ++i) {
3454 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3455 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3458 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3463 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3464 IWineD3DDevice *iface,
3469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3470 int cnt = min(count, MAX_CONST_B - start);
3472 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3473 iface, dstData, start, count);
3475 if (dstData == NULL || cnt < 0)
3476 return WINED3DERR_INVALIDCALL;
3478 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3482 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3483 IWineD3DDevice *iface,
3488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3489 int i, cnt = min(count, MAX_CONST_I - start);
3491 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3492 iface, srcData, start, count);
3494 if (srcData == NULL || cnt < 0)
3495 return WINED3DERR_INVALIDCALL;
3497 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3498 for (i = 0; i < cnt; i++)
3499 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3500 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3502 for (i = start; i < cnt + start; ++i) {
3503 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3504 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3507 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3512 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3513 IWineD3DDevice *iface,
3518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3519 int cnt = min(count, MAX_CONST_I - start);
3521 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3522 iface, dstData, start, count);
3524 if (dstData == NULL || cnt < 0)
3525 return WINED3DERR_INVALIDCALL;
3527 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3531 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3532 IWineD3DDevice *iface,
3534 CONST float *srcData,
3537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3540 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3541 iface, srcData, start, count);
3543 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3544 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3545 return WINED3DERR_INVALIDCALL;
3547 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3549 for (i = 0; i < count; i++)
3550 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3551 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3554 for (i = start; i < count + start; ++i) {
3555 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3556 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3557 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3558 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3559 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3561 ptr->idx[ptr->count++] = i;
3562 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3564 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3567 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3572 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3573 IWineD3DDevice *iface,
3578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3579 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3581 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3582 iface, dstData, start, count);
3584 if (dstData == NULL || cnt < 0)
3585 return WINED3DERR_INVALIDCALL;
3587 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3591 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3593 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3594 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3596 DWORD DestFVF = dest->fvf;
3598 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3602 if (lpStrideData->u.s.normal.lpData) {
3603 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3606 if (lpStrideData->u.s.position.lpData == NULL) {
3607 ERR("Source has no position mask\n");
3608 return WINED3DERR_INVALIDCALL;
3611 /* We might access VBOs from this code, so hold the lock */
3614 if (dest->resource.allocatedMemory == NULL) {
3615 /* This may happen if we do direct locking into a vbo. Unlikely,
3616 * but theoretically possible(ddraw processvertices test)
3618 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3619 if(!dest->resource.allocatedMemory) {
3621 ERR("Out of memory\n");
3622 return E_OUTOFMEMORY;
3626 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3627 checkGLcall("glBindBufferARB");
3628 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3630 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3632 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3633 checkGLcall("glUnmapBufferARB");
3637 /* Get a pointer into the destination vbo(create one if none exists) and
3638 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3640 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3645 unsigned char extrabytes = 0;
3646 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3647 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3648 * this may write 4 extra bytes beyond the area that should be written
3650 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3651 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3652 if(!dest_conv_addr) {
3653 ERR("Out of memory\n");
3654 /* Continue without storing converted vertices */
3656 dest_conv = dest_conv_addr;
3660 * a) WINED3DRS_CLIPPING is enabled
3661 * b) WINED3DVOP_CLIP is passed
3663 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3664 static BOOL warned = FALSE;
3666 * The clipping code is not quite correct. Some things need
3667 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3668 * so disable clipping for now.
3669 * (The graphics in Half-Life are broken, and my processvertices
3670 * test crashes with IDirect3DDevice3)
3676 FIXME("Clipping is broken and disabled for now\n");
3678 } else doClip = FALSE;
3679 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3681 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3684 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3685 WINED3DTS_PROJECTION,
3687 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3688 WINED3DTS_WORLDMATRIX(0),
3691 TRACE("View mat:\n");
3692 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);
3693 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);
3694 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);
3695 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);
3697 TRACE("Proj mat:\n");
3698 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);
3699 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);
3700 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);
3701 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);
3703 TRACE("World mat:\n");
3704 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);
3705 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);
3706 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);
3707 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);
3709 /* Get the viewport */
3710 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3711 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3712 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3714 multiply_matrix(&mat,&view_mat,&world_mat);
3715 multiply_matrix(&mat,&proj_mat,&mat);
3717 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3719 for (i = 0; i < dwCount; i+= 1) {
3720 unsigned int tex_index;
3722 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3723 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3724 /* The position first */
3726 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3728 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3730 /* Multiplication with world, view and projection matrix */
3731 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);
3732 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);
3733 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);
3734 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);
3736 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3738 /* WARNING: The following things are taken from d3d7 and were not yet checked
3739 * against d3d8 or d3d9!
3742 /* Clipping conditions: From
3743 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3745 * A vertex is clipped if it does not match the following requirements
3749 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3751 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3752 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3757 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3758 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3761 /* "Normal" viewport transformation (not clipped)
3762 * 1) The values are divided by rhw
3763 * 2) The y axis is negative, so multiply it with -1
3764 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3765 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3766 * 4) Multiply x with Width/2 and add Width/2
3767 * 5) The same for the height
3768 * 6) Add the viewpoint X and Y to the 2D coordinates and
3769 * The minimum Z value to z
3770 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3772 * Well, basically it's simply a linear transformation into viewport
3784 z *= vp.MaxZ - vp.MinZ;
3786 x += vp.Width / 2 + vp.X;
3787 y += vp.Height / 2 + vp.Y;
3792 /* That vertex got clipped
3793 * Contrary to OpenGL it is not dropped completely, it just
3794 * undergoes a different calculation.
3796 TRACE("Vertex got clipped\n");
3803 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3804 * outside of the main vertex buffer memory. That needs some more
3809 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3812 ( (float *) dest_ptr)[0] = x;
3813 ( (float *) dest_ptr)[1] = y;
3814 ( (float *) dest_ptr)[2] = z;
3815 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3817 dest_ptr += 3 * sizeof(float);
3819 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3820 dest_ptr += sizeof(float);
3825 ( (float *) dest_conv)[0] = x * w;
3826 ( (float *) dest_conv)[1] = y * w;
3827 ( (float *) dest_conv)[2] = z * w;
3828 ( (float *) dest_conv)[3] = w;
3830 dest_conv += 3 * sizeof(float);
3832 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3833 dest_conv += sizeof(float);
3837 if (DestFVF & WINED3DFVF_PSIZE) {
3838 dest_ptr += sizeof(DWORD);
3839 if(dest_conv) dest_conv += sizeof(DWORD);
3841 if (DestFVF & WINED3DFVF_NORMAL) {
3843 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3844 /* AFAIK this should go into the lighting information */
3845 FIXME("Didn't expect the destination to have a normal\n");
3846 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3848 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3852 if (DestFVF & WINED3DFVF_DIFFUSE) {
3854 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3856 static BOOL warned = FALSE;
3859 ERR("No diffuse color in source, but destination has one\n");
3863 *( (DWORD *) dest_ptr) = 0xffffffff;
3864 dest_ptr += sizeof(DWORD);
3867 *( (DWORD *) dest_conv) = 0xffffffff;
3868 dest_conv += sizeof(DWORD);
3872 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3874 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3875 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3876 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3877 dest_conv += sizeof(DWORD);
3882 if (DestFVF & WINED3DFVF_SPECULAR) {
3883 /* What's the color value in the feedback buffer? */
3885 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3887 static BOOL warned = FALSE;
3890 ERR("No specular color in source, but destination has one\n");
3894 *( (DWORD *) dest_ptr) = 0xFF000000;
3895 dest_ptr += sizeof(DWORD);
3898 *( (DWORD *) dest_conv) = 0xFF000000;
3899 dest_conv += sizeof(DWORD);
3903 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3905 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3906 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3907 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3908 dest_conv += sizeof(DWORD);
3913 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3915 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3916 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3918 ERR("No source texture, but destination requests one\n");
3919 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3920 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3923 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3925 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3932 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3933 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3934 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3935 dwCount * get_flexible_vertex_size(DestFVF),
3937 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3938 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3945 #undef copy_and_next
3947 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3949 WineDirect3DVertexStridedData strided;
3950 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3951 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3954 ERR("Output vertex declaration not implemented yet\n");
3957 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3958 * and this call is quite performance critical, so don't call needlessly
3960 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3962 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3966 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3967 * control the streamIsUP flag, thus restore it afterwards.
3969 This->stateBlock->streamIsUP = FALSE;
3970 memset(&strided, 0, sizeof(strided));
3971 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
3972 This->stateBlock->streamIsUP = streamWasUP;
3974 if(vbo || SrcStartIndex) {
3976 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
3977 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
3979 * Also get the start index in, but only loop over all elements if there's something to add at all.
3981 #define FIXSRC(type) \
3982 if(strided.u.s.type.VBO) { \
3983 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
3984 strided.u.s.type.VBO = 0; \
3985 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
3987 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
3991 if(strided.u.s.type.lpData) { \
3992 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
3995 FIXSRC(blendWeights);
3996 FIXSRC(blendMatrixIndices);
4001 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4002 FIXSRC(texCoords[i]);
4015 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4019 * Get / Set Texture Stage States
4020 * TODO: Verify against dx9 definitions
4022 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4024 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4026 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4028 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4030 if (Stage >= MAX_TEXTURES) {
4031 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4035 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4036 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
4037 This->updateStateBlock->textureState[Stage][Type] = Value;
4039 if (This->isRecordingState) {
4040 TRACE("Recording... not performing anything\n");
4044 /* Checked after the assignments to allow proper stateblock recording */
4045 if(oldValue == Value) {
4046 TRACE("App is setting the old value over, nothing to do\n");
4050 if(Stage > This->stateBlock->lowest_disabled_stage &&
4051 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4052 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4053 * Changes in other states are important on disabled stages too
4058 if(Type == WINED3DTSS_COLOROP) {
4061 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4062 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4063 * they have to be disabled
4065 * The current stage is dirtified below.
4067 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4068 TRACE("Additionally dirtifying stage %d\n", i);
4069 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4071 This->stateBlock->lowest_disabled_stage = Stage;
4072 TRACE("New lowest disabled: %d\n", Stage);
4073 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4074 /* Previously disabled stage enabled. Stages above it may need enabling
4075 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4076 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4078 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4081 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4082 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4085 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4086 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4088 This->stateBlock->lowest_disabled_stage = i;
4089 TRACE("New lowest disabled: %d\n", i);
4091 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4092 /* TODO: Built a stage -> texture unit mapping for register combiners */
4096 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4101 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4103 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4104 *pValue = This->updateStateBlock->textureState[Stage][Type];
4111 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4113 IWineD3DBaseTexture *oldTexture;
4115 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4117 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4118 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4121 oldTexture = This->updateStateBlock->textures[Stage];
4123 if(pTexture != NULL) {
4124 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4126 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4127 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4128 return WINED3DERR_INVALIDCALL;
4130 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4133 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4134 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4136 This->updateStateBlock->set.textures[Stage] = TRUE;
4137 This->updateStateBlock->changed.textures[Stage] = TRUE;
4138 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4139 This->updateStateBlock->textures[Stage] = pTexture;
4141 /* Handle recording of state blocks */
4142 if (This->isRecordingState) {
4143 TRACE("Recording... not performing anything\n");
4147 if(oldTexture == pTexture) {
4148 TRACE("App is setting the same texture again, nothing to do\n");
4152 /** NOTE: MSDN says that setTexture increases the reference count,
4153 * and the the application must set the texture back to null (or have a leaky application),
4154 * This means we should pass the refcount up to the parent
4155 *******************************/
4156 if (NULL != This->updateStateBlock->textures[Stage]) {
4157 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4158 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4160 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4161 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4162 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4163 * so the COLOROP and ALPHAOP have to be dirtified.
4165 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4166 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4168 if(bindCount == 1) {
4169 new->baseTexture.sampler = Stage;
4171 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4175 if (NULL != oldTexture) {
4176 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4177 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4179 IWineD3DBaseTexture_Release(oldTexture);
4180 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4181 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4182 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4185 if(bindCount && old->baseTexture.sampler == Stage) {
4187 /* Have to do a search for the other sampler(s) where the texture is bound to
4188 * Shouldn't happen as long as apps bind a texture only to one stage
4190 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4191 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4192 if(This->updateStateBlock->textures[i] == oldTexture) {
4193 old->baseTexture.sampler = i;
4200 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4205 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4208 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4210 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4211 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4214 *ppTexture=This->stateBlock->textures[Stage];
4216 IWineD3DBaseTexture_AddRef(*ppTexture);
4218 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4226 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4227 IWineD3DSurface **ppBackBuffer) {
4228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4229 IWineD3DSwapChain *swapChain;
4232 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4234 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4235 if (hr == WINED3D_OK) {
4236 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4237 IWineD3DSwapChain_Release(swapChain);
4239 *ppBackBuffer = NULL;
4244 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4246 WARN("(%p) : stub, calling idirect3d for now\n", This);
4247 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4250 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4252 IWineD3DSwapChain *swapChain;
4255 if(iSwapChain > 0) {
4256 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4257 if (hr == WINED3D_OK) {
4258 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4259 IWineD3DSwapChain_Release(swapChain);
4261 FIXME("(%p) Error getting display mode\n", This);
4264 /* Don't read the real display mode,
4265 but return the stored mode instead. X11 can't change the color
4266 depth, and some apps are pretty angry if they SetDisplayMode from
4267 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4269 Also don't relay to the swapchain because with ddraw it's possible
4270 that there isn't a swapchain at all */
4271 pMode->Width = This->ddraw_width;
4272 pMode->Height = This->ddraw_height;
4273 pMode->Format = This->ddraw_format;
4274 pMode->RefreshRate = 0;
4281 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4283 TRACE("(%p)->(%p)\n", This, hWnd);
4285 if(This->ddraw_fullscreen) {
4286 if(This->ddraw_window && This->ddraw_window != hWnd) {
4287 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4289 if(hWnd && This->ddraw_window != hWnd) {
4290 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4294 This->ddraw_window = hWnd;
4298 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4300 TRACE("(%p)->(%p)\n", This, hWnd);
4302 *hWnd = This->ddraw_window;
4307 * Stateblock related functions
4310 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4312 IWineD3DStateBlockImpl *object;
4313 HRESULT temp_result;
4316 TRACE("(%p)\n", This);
4318 if (This->isRecordingState) {
4319 return WINED3DERR_INVALIDCALL;
4322 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4323 if (NULL == object ) {
4324 FIXME("(%p)Error allocating memory for stateblock\n", This);
4325 return E_OUTOFMEMORY;
4327 TRACE("(%p) created object %p\n", This, object);
4328 object->wineD3DDevice= This;
4329 /** FIXME: object->parent = parent; **/
4330 object->parent = NULL;
4331 object->blockType = WINED3DSBT_ALL;
4333 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4335 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4336 list_init(&object->lightMap[i]);
4339 temp_result = allocate_shader_constants(object);
4340 if (WINED3D_OK != temp_result)
4343 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4344 This->updateStateBlock = object;
4345 This->isRecordingState = TRUE;
4347 TRACE("(%p) recording stateblock %p\n",This , object);
4351 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4354 if (!This->isRecordingState) {
4355 FIXME("(%p) not recording! returning error\n", This);
4356 *ppStateBlock = NULL;
4357 return WINED3DERR_INVALIDCALL;
4360 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4361 This->isRecordingState = FALSE;
4362 This->updateStateBlock = This->stateBlock;
4363 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4364 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4365 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4370 * Scene related functions
4372 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4373 /* At the moment we have no need for any functionality at the beginning
4375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4376 TRACE("(%p)\n", This);
4379 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4380 return WINED3DERR_INVALIDCALL;
4382 This->inScene = TRUE;
4386 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4388 TRACE("(%p)\n", This);
4390 if(!This->inScene) {
4391 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4392 return WINED3DERR_INVALIDCALL;
4396 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4397 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4399 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4401 checkGLcall("glFlush");
4404 This->inScene = FALSE;
4408 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4409 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4410 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4412 IWineD3DSwapChain *swapChain = NULL;
4414 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4416 TRACE("(%p) Presenting the frame\n", This);
4418 for(i = 0 ; i < swapchains ; i ++) {
4420 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4421 TRACE("presentinng chain %d, %p\n", i, swapChain);
4422 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4423 IWineD3DSwapChain_Release(swapChain);
4429 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4430 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4432 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4434 GLbitfield glMask = 0;
4436 CONST WINED3DRECT* curRect;
4438 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4439 Count, pRects, Flags, Color, Z, Stencil);
4441 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4442 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4443 /* TODO: What about depth stencil buffers without stencil bits? */
4444 return WINED3DERR_INVALIDCALL;
4448 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4449 * and not the last active one.
4452 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4453 apply_fbo_state(iface);
4456 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
4458 glEnable(GL_SCISSOR_TEST);
4459 checkGLcall("glEnable GL_SCISSOR_TEST");
4460 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4461 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4463 if (Count > 0 && pRects) {
4469 /* Only set the values up once, as they are not changing */
4470 if (Flags & WINED3DCLEAR_STENCIL) {
4471 glClearStencil(Stencil);
4472 checkGLcall("glClearStencil");
4473 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4474 glStencilMask(0xFFFFFFFF);
4477 if (Flags & WINED3DCLEAR_ZBUFFER) {
4478 glDepthMask(GL_TRUE);
4480 checkGLcall("glClearDepth");
4481 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4485 if (Flags & WINED3DCLEAR_TARGET) {
4486 TRACE("Clearing screen with glClear to color %x\n", Color);
4487 glClearColor(D3DCOLOR_R(Color),
4491 checkGLcall("glClearColor");
4493 /* Clear ALL colors! */
4494 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4495 glMask = glMask | GL_COLOR_BUFFER_BIT;
4499 /* In drawable flag is set below */
4501 glScissor(This->stateBlock->viewport.X,
4502 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4503 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4504 This->stateBlock->viewport.Width,
4505 This->stateBlock->viewport.Height);
4506 checkGLcall("glScissor");
4508 checkGLcall("glClear");
4510 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4511 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4513 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4514 curRect[0].x2 < target->currentDesc.Width ||
4515 curRect[0].y2 < target->currentDesc.Height) {
4516 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4517 blt_to_drawable(This, target);
4521 /* Now process each rect in turn */
4522 for (i = 0; i < Count; i++) {
4523 /* Note gl uses lower left, width/height */
4524 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4525 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4526 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4527 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4529 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4530 * The rectangle is not cleared, no error is returned, but further rectanlges are
4531 * still cleared if they are valid
4533 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4534 TRACE("Rectangle with negative dimensions, ignoring\n");
4538 if(This->render_offscreen) {
4539 glScissor(curRect[i].x1, curRect[i].y1,
4540 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4542 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4543 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4545 checkGLcall("glScissor");
4548 checkGLcall("glClear");
4552 /* Restore the old values (why..?) */
4553 if (Flags & WINED3DCLEAR_STENCIL) {
4554 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4556 if (Flags & WINED3DCLEAR_TARGET) {
4557 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4558 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4559 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4560 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4561 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4566 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4567 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4569 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4570 target->Flags |= SFLAG_INTEXTURE;
4571 target->Flags &= ~SFLAG_INSYSMEM;
4573 target->Flags |= SFLAG_INDRAWABLE;
4574 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4582 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4583 UINT PrimitiveCount) {
4585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4587 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4588 debug_d3dprimitivetype(PrimitiveType),
4589 StartVertex, PrimitiveCount);
4591 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4592 if(This->stateBlock->streamIsUP) {
4593 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4594 This->stateBlock->streamIsUP = FALSE;
4597 if(This->stateBlock->loadBaseVertexIndex != 0) {
4598 This->stateBlock->loadBaseVertexIndex = 0;
4599 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4601 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4602 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4603 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4607 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4608 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4609 WINED3DPRIMITIVETYPE PrimitiveType,
4610 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4614 IWineD3DIndexBuffer *pIB;
4615 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4618 pIB = This->stateBlock->pIndexData;
4620 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4621 * without an index buffer set. (The first time at least...)
4622 * D3D8 simply dies, but I doubt it can do much harm to return
4623 * D3DERR_INVALIDCALL there as well. */
4624 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4625 return WINED3DERR_INVALIDCALL;
4628 if(This->stateBlock->streamIsUP) {
4629 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4630 This->stateBlock->streamIsUP = FALSE;
4632 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4634 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4635 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4636 minIndex, NumVertices, startIndex, primCount);
4638 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4639 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4645 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4646 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4647 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4650 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4651 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4656 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4657 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4658 UINT VertexStreamZeroStride) {
4659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4661 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4662 debug_d3dprimitivetype(PrimitiveType),
4663 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4665 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4666 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4667 This->stateBlock->streamOffset[0] = 0;
4668 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4669 This->stateBlock->streamIsUP = TRUE;
4670 This->stateBlock->loadBaseVertexIndex = 0;
4672 /* TODO: Only mark dirty if drawing from a different UP address */
4673 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4675 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4676 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4678 /* MSDN specifies stream zero settings must be set to NULL */
4679 This->stateBlock->streamStride[0] = 0;
4680 This->stateBlock->streamSource[0] = NULL;
4682 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4683 * the new stream sources or use UP drawing again
4688 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4689 UINT MinVertexIndex, UINT NumVertices,
4690 UINT PrimitiveCount, CONST void* pIndexData,
4691 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4692 UINT VertexStreamZeroStride) {
4694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4696 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4697 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4698 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4699 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4701 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4707 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4708 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4709 This->stateBlock->streamIsUP = TRUE;
4710 This->stateBlock->streamOffset[0] = 0;
4711 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4713 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4714 This->stateBlock->baseVertexIndex = 0;
4715 This->stateBlock->loadBaseVertexIndex = 0;
4716 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4718 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4720 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4722 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4723 This->stateBlock->streamSource[0] = NULL;
4724 This->stateBlock->streamStride[0] = 0;
4725 This->stateBlock->pIndexData = NULL;
4726 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4727 * SetStreamSource to specify a vertex buffer
4733 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4736 /* Mark the state dirty until we have nicer tracking
4737 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4740 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4741 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4742 This->stateBlock->baseVertexIndex = 0;
4743 This->up_strided = DrawPrimStrideData;
4744 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4745 This->up_strided = NULL;
4748 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4749 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4751 HRESULT hr = WINED3D_OK;
4752 WINED3DRESOURCETYPE sourceType;
4753 WINED3DRESOURCETYPE destinationType;
4756 /* TODO: think about moving the code into IWineD3DBaseTexture */
4758 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4760 /* verify that the source and destination textures aren't NULL */
4761 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4762 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4763 This, pSourceTexture, pDestinationTexture);
4764 hr = WINED3DERR_INVALIDCALL;
4767 if (pSourceTexture == pDestinationTexture) {
4768 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4769 This, pSourceTexture, pDestinationTexture);
4770 hr = WINED3DERR_INVALIDCALL;
4772 /* Verify that the source and destination textures are the same type */
4773 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4774 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4776 if (sourceType != destinationType) {
4777 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4779 hr = WINED3DERR_INVALIDCALL;
4782 /* check that both textures have the identical numbers of levels */
4783 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4784 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4785 hr = WINED3DERR_INVALIDCALL;
4788 if (WINED3D_OK == hr) {
4790 /* Make sure that the destination texture is loaded */
4791 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4793 /* Update every surface level of the texture */
4794 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4796 switch (sourceType) {
4797 case WINED3DRTYPE_TEXTURE:
4799 IWineD3DSurface *srcSurface;
4800 IWineD3DSurface *destSurface;
4802 for (i = 0 ; i < levels ; ++i) {
4803 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4804 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4805 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4806 IWineD3DSurface_Release(srcSurface);
4807 IWineD3DSurface_Release(destSurface);
4808 if (WINED3D_OK != hr) {
4809 WARN("(%p) : Call to update surface failed\n", This);
4815 case WINED3DRTYPE_CUBETEXTURE:
4817 IWineD3DSurface *srcSurface;
4818 IWineD3DSurface *destSurface;
4819 WINED3DCUBEMAP_FACES faceType;
4821 for (i = 0 ; i < levels ; ++i) {
4822 /* Update each cube face */
4823 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4824 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4825 if (WINED3D_OK != hr) {
4826 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4828 TRACE("Got srcSurface %p\n", srcSurface);
4830 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4831 if (WINED3D_OK != hr) {
4832 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4834 TRACE("Got desrSurface %p\n", destSurface);
4836 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4837 IWineD3DSurface_Release(srcSurface);
4838 IWineD3DSurface_Release(destSurface);
4839 if (WINED3D_OK != hr) {
4840 WARN("(%p) : Call to update surface failed\n", This);
4847 #if 0 /* TODO: Add support for volume textures */
4848 case WINED3DRTYPE_VOLUMETEXTURE:
4850 IWineD3DVolume srcVolume = NULL;
4851 IWineD3DSurface destVolume = NULL;
4853 for (i = 0 ; i < levels ; ++i) {
4854 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4855 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4856 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4857 IWineD3DVolume_Release(srcSurface);
4858 IWineD3DVolume_Release(destSurface);
4859 if (WINED3D_OK != hr) {
4860 WARN("(%p) : Call to update volume failed\n", This);
4868 FIXME("(%p) : Unsupported source and destination type\n", This);
4869 hr = WINED3DERR_INVALIDCALL;
4876 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4877 IWineD3DSwapChain *swapChain;
4879 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4880 if(hr == WINED3D_OK) {
4881 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4882 IWineD3DSwapChain_Release(swapChain);
4887 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4889 /* return a sensible default */
4891 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4892 FIXME("(%p) : stub\n", This);
4896 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4899 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4900 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4901 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4902 return WINED3DERR_INVALIDCALL;
4904 for (j = 0; j < 256; ++j) {
4905 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4906 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4907 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4908 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4910 TRACE("(%p) : returning\n", This);
4914 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4917 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4918 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4919 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4920 return WINED3DERR_INVALIDCALL;
4922 for (j = 0; j < 256; ++j) {
4923 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4924 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4925 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4926 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4928 TRACE("(%p) : returning\n", This);
4932 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4934 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4935 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4936 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4937 return WINED3DERR_INVALIDCALL;
4939 /*TODO: stateblocks */
4940 This->currentPalette = PaletteNumber;
4941 TRACE("(%p) : returning\n", This);
4945 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4947 if (PaletteNumber == NULL) {
4948 WARN("(%p) : returning Invalid Call\n", This);
4949 return WINED3DERR_INVALIDCALL;
4951 /*TODO: stateblocks */
4952 *PaletteNumber = This->currentPalette;
4953 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4957 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4959 static BOOL showFixmes = TRUE;
4961 FIXME("(%p) : stub\n", This);
4965 This->softwareVertexProcessing = bSoftware;
4970 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4972 static BOOL showFixmes = TRUE;
4974 FIXME("(%p) : stub\n", This);
4977 return This->softwareVertexProcessing;
4981 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4983 IWineD3DSwapChain *swapChain;
4986 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4988 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4989 if(hr == WINED3D_OK){
4990 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4991 IWineD3DSwapChain_Release(swapChain);
4993 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4999 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5001 static BOOL showfixmes = TRUE;
5002 if(nSegments != 0.0f) {
5004 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5011 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5013 static BOOL showfixmes = TRUE;
5015 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5021 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5023 /** TODO: remove casts to IWineD3DSurfaceImpl
5024 * NOTE: move code to surface to accomplish this
5025 ****************************************/
5026 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5027 int srcWidth, srcHeight;
5028 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5029 WINED3DFORMAT destFormat, srcFormat;
5031 int srcLeft, destLeft, destTop;
5032 WINED3DPOOL srcPool, destPool;
5034 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5035 glDescriptor *glDescription = NULL;
5037 WINED3DSURFACE_DESC winedesc;
5039 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5040 memset(&winedesc, 0, sizeof(winedesc));
5041 winedesc.Width = &srcSurfaceWidth;
5042 winedesc.Height = &srcSurfaceHeight;
5043 winedesc.Pool = &srcPool;
5044 winedesc.Format = &srcFormat;
5046 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5048 winedesc.Width = &destSurfaceWidth;
5049 winedesc.Height = &destSurfaceHeight;
5050 winedesc.Pool = &destPool;
5051 winedesc.Format = &destFormat;
5052 winedesc.Size = &destSize;
5054 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5056 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5057 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5058 return WINED3DERR_INVALIDCALL;
5061 if (destFormat == WINED3DFMT_UNKNOWN) {
5062 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5063 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5065 /* Get the update surface description */
5066 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5071 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5073 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5074 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5075 checkGLcall("glActiveTextureARB");
5078 /* Make sure the surface is loaded and up to date */
5079 IWineD3DSurface_PreLoad(pDestinationSurface);
5081 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5083 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5084 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5085 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5086 srcLeft = pSourceRect ? pSourceRect->left : 0;
5087 destLeft = pDestPoint ? pDestPoint->x : 0;
5088 destTop = pDestPoint ? pDestPoint->y : 0;
5091 /* This function doesn't support compressed textures
5092 the pitch is just bytesPerPixel * width */
5093 if(srcWidth != srcSurfaceWidth || srcLeft ){
5094 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5095 offset += srcLeft * pSrcSurface->bytesPerPixel;
5096 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5098 /* TODO DXT formats */
5100 if(pSourceRect != NULL && pSourceRect->top != 0){
5101 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5103 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5105 ,glDescription->level
5110 ,glDescription->glFormat
5111 ,glDescription->glType
5112 ,IWineD3DSurface_GetData(pSourceSurface)
5116 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5118 /* need to lock the surface to get the data */
5119 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5122 /* TODO: Cube and volume support */
5124 /* not a whole row so we have to do it a line at a time */
5127 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5128 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5130 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5132 glTexSubImage2D(glDescription->target
5133 ,glDescription->level
5138 ,glDescription->glFormat
5139 ,glDescription->glType
5140 ,data /* could be quicker using */
5145 } else { /* Full width, so just write out the whole texture */
5147 if (WINED3DFMT_DXT1 == destFormat ||
5148 WINED3DFMT_DXT2 == destFormat ||
5149 WINED3DFMT_DXT3 == destFormat ||
5150 WINED3DFMT_DXT4 == destFormat ||
5151 WINED3DFMT_DXT5 == destFormat) {
5152 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5153 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5154 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5155 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5156 } if (destFormat != srcFormat) {
5157 FIXME("Updating mixed format compressed texture is not curretly support\n");
5159 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5160 glDescription->level,
5161 glDescription->glFormatInternal,
5166 IWineD3DSurface_GetData(pSourceSurface));
5169 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5174 glTexSubImage2D(glDescription->target
5175 ,glDescription->level
5180 ,glDescription->glFormat
5181 ,glDescription->glType
5182 ,IWineD3DSurface_GetData(pSourceSurface)
5186 checkGLcall("glTexSubImage2D");
5190 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5191 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5192 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5197 /* Implementation details at http://developer.nvidia.com/attach/6494
5199 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5200 hmm.. no longer supported use
5201 OpenGL evaluators or tessellate surfaces within your application.
5204 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5205 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5207 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5208 FIXME("(%p) : Stub\n", This);
5213 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5214 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5216 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5217 FIXME("(%p) : Stub\n", This);
5221 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5223 TRACE("(%p) Handle(%d)\n", This, Handle);
5224 FIXME("(%p) : Stub\n", This);
5228 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5230 IWineD3DSwapChain *swapchain;
5232 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5233 if (SUCCEEDED(hr)) {
5234 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5241 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5245 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5246 checkGLcall("glGenFramebuffersEXT()");
5248 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5249 checkGLcall("glBindFramebuffer()");
5252 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5253 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5254 IWineD3DBaseTextureImpl *texture_impl;
5255 GLenum texttarget, target;
5258 texttarget = surface_impl->glDescription.target;
5259 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5260 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5262 IWineD3DSurface_PreLoad(surface);
5264 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5265 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5266 glBindTexture(target, old_binding);
5268 /* Update base texture states array */
5269 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5270 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5271 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5272 if (texture_impl->baseTexture.bindCount) {
5273 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5276 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5279 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5281 checkGLcall("attach_surface_fbo");
5284 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5286 IWineD3DSwapChain *swapchain;
5288 swapchain = get_swapchain(surface);
5292 TRACE("Surface %p is onscreen\n", surface);
5294 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5295 buffer = surface_get_gl_buffer(surface, swapchain);
5296 glDrawBuffer(buffer);
5297 checkGLcall("glDrawBuffer()");
5299 TRACE("Surface %p is offscreen\n", surface);
5300 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5301 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5305 glEnable(GL_SCISSOR_TEST);
5307 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5309 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5310 rect->x2 - rect->x1, rect->y2 - rect->y1);
5312 checkGLcall("glScissor");
5314 glDisable(GL_SCISSOR_TEST);
5316 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5318 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5319 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5321 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5322 glClear(GL_COLOR_BUFFER_BIT);
5323 checkGLcall("glClear");
5325 if (This->render_offscreen) {
5326 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5328 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5329 checkGLcall("glBindFramebuffer()");
5332 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5333 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5334 glDrawBuffer(GL_BACK);
5335 checkGLcall("glDrawBuffer()");
5339 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5341 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5343 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5345 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5346 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5347 return WINED3DERR_INVALIDCALL;
5350 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5351 color_fill_fbo(iface, pSurface, pRect, color);
5354 /* Just forward this to the DirectDraw blitting engine */
5355 memset(&BltFx, 0, sizeof(BltFx));
5356 BltFx.dwSize = sizeof(BltFx);
5357 BltFx.u5.dwFillColor = color;
5358 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5362 /* rendertarget and deptth stencil functions */
5363 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5366 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5367 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5368 return WINED3DERR_INVALIDCALL;
5371 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5372 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5373 /* Note inc ref on returned surface */
5374 if(*ppRenderTarget != NULL)
5375 IWineD3DSurface_AddRef(*ppRenderTarget);
5379 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5381 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5382 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5383 IWineD3DSwapChainImpl *Swapchain;
5386 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5388 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5389 if(hr != WINED3D_OK) {
5390 ERR("Can't get the swapchain\n");
5394 /* Make sure to release the swapchain */
5395 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5397 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5398 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5399 return WINED3DERR_INVALIDCALL;
5401 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5402 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5403 return WINED3DERR_INVALIDCALL;
5406 if(Swapchain->frontBuffer != Front) {
5407 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5409 if(Swapchain->frontBuffer)
5410 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5411 Swapchain->frontBuffer = Front;
5413 if(Swapchain->frontBuffer) {
5414 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5418 if(Back && !Swapchain->backBuffer) {
5419 /* We need memory for the back buffer array - only one back buffer this way */
5420 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5421 if(!Swapchain->backBuffer) {
5422 ERR("Out of memory\n");
5423 return E_OUTOFMEMORY;
5427 if(Swapchain->backBuffer[0] != Back) {
5428 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5430 /* What to do about the context here in the case of multithreading? Not sure.
5431 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5434 if(!Swapchain->backBuffer[0]) {
5435 /* GL was told to draw to the front buffer at creation,
5438 glDrawBuffer(GL_BACK);
5439 checkGLcall("glDrawBuffer(GL_BACK)");
5440 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5441 Swapchain->presentParms.BackBufferCount = 1;
5443 /* That makes problems - disable for now */
5444 /* glDrawBuffer(GL_FRONT); */
5445 checkGLcall("glDrawBuffer(GL_FRONT)");
5446 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5447 Swapchain->presentParms.BackBufferCount = 0;
5451 if(Swapchain->backBuffer[0])
5452 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5453 Swapchain->backBuffer[0] = Back;
5455 if(Swapchain->backBuffer[0]) {
5456 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5458 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5466 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5467 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5468 *ppZStencilSurface = This->depthStencilBuffer;
5469 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5471 if(*ppZStencilSurface != NULL) {
5472 /* Note inc ref on returned surface */
5473 IWineD3DSurface_AddRef(*ppZStencilSurface);
5478 /* TODO: Handle stencil attachments */
5479 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5481 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5483 TRACE("Set depth stencil to %p\n", depth_stencil);
5485 if (depth_stencil_impl) {
5486 if (depth_stencil_impl->current_renderbuffer) {
5487 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5488 checkGLcall("glFramebufferRenderbufferEXT()");
5490 IWineD3DBaseTextureImpl *texture_impl;
5491 GLenum texttarget, target;
5492 GLint old_binding = 0;
5494 texttarget = depth_stencil_impl->glDescription.target;
5495 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5496 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5498 IWineD3DSurface_PreLoad(depth_stencil);
5500 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5501 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5502 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5503 glBindTexture(target, old_binding);
5505 /* Update base texture states array */
5506 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5507 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5508 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5509 if (texture_impl->baseTexture.bindCount) {
5510 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5513 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5516 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5517 checkGLcall("glFramebufferTexture2DEXT()");
5520 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5521 checkGLcall("glFramebufferTexture2DEXT()");
5525 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5527 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5529 TRACE("Set render target %u to %p\n", idx, render_target);
5532 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5533 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5535 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5536 checkGLcall("glFramebufferTexture2DEXT()");
5538 This->draw_buffers[idx] = GL_NONE;
5542 static void check_fbo_status(IWineD3DDevice *iface) {
5543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5546 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5547 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5548 TRACE("FBO complete\n");
5550 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5552 /* Dump the FBO attachments */
5553 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5554 IWineD3DSurfaceImpl *attachment;
5557 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5558 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5560 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5561 attachment->pow2Width, attachment->pow2Height);
5564 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5566 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5567 attachment->pow2Width, attachment->pow2Height);
5573 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5575 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5576 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5578 if (!ds_impl) return FALSE;
5580 if (ds_impl->current_renderbuffer) {
5581 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5582 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5585 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5586 rt_impl->pow2Height != ds_impl->pow2Height);
5589 void apply_fbo_state(IWineD3DDevice *iface) {
5590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5593 if (This->render_offscreen) {
5594 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5596 /* Apply render targets */
5597 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5598 IWineD3DSurface *render_target = This->render_targets[i];
5599 if (This->fbo_color_attachments[i] != render_target) {
5600 set_render_target_fbo(iface, i, render_target);
5601 This->fbo_color_attachments[i] = render_target;
5605 /* Apply depth targets */
5606 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5607 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5608 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5610 if (This->stencilBufferTarget) {
5611 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5613 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5614 This->fbo_depth_attachment = This->stencilBufferTarget;
5617 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5618 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5619 checkGLcall("glDrawBuffers()");
5621 glDrawBuffer(This->draw_buffers[0]);
5622 checkGLcall("glDrawBuffer()");
5625 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5628 check_fbo_status(iface);
5631 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5632 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5634 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5635 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5638 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5639 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5640 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5641 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5644 case WINED3DTEXF_LINEAR:
5645 gl_filter = GL_LINEAR;
5649 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5650 case WINED3DTEXF_NONE:
5651 case WINED3DTEXF_POINT:
5652 gl_filter = GL_NEAREST;
5656 /* Attach src surface to src fbo */
5657 src_swapchain = get_swapchain(src_surface);
5659 if (src_swapchain) {
5662 TRACE("Source surface %p is onscreen\n", src_surface);
5663 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5665 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5666 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5667 glReadBuffer(buffer);
5668 checkGLcall("glReadBuffer()");
5670 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5671 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5673 TRACE("Source surface %p is offscreen\n", src_surface);
5674 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5675 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5676 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5677 checkGLcall("glReadBuffer()");
5680 /* Attach dst surface to dst fbo */
5681 dst_swapchain = get_swapchain(dst_surface);
5682 if (dst_swapchain) {
5685 TRACE("Destination surface %p is onscreen\n", dst_surface);
5686 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5688 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5689 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5690 glDrawBuffer(buffer);
5691 checkGLcall("glDrawBuffer()");
5693 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5694 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5696 TRACE("Destination surface %p is offscreen\n", dst_surface);
5698 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5699 if(!src_swapchain) {
5700 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5703 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5704 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5705 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5706 checkGLcall("glDrawBuffer()");
5708 glDisable(GL_SCISSOR_TEST);
5709 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5712 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5713 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5714 checkGLcall("glBlitFramebuffer()");
5716 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5717 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5718 checkGLcall("glBlitFramebuffer()");
5721 if (This->render_offscreen) {
5722 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5724 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5725 checkGLcall("glBindFramebuffer()");
5728 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5729 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5730 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5731 glDrawBuffer(GL_BACK);
5732 checkGLcall("glDrawBuffer()");
5737 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5739 WINED3DVIEWPORT viewport;
5741 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5743 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5744 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5745 return WINED3DERR_INVALIDCALL;
5748 /* MSDN says that null disables the render target
5749 but a device must always be associated with a render target
5750 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5752 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5755 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5756 FIXME("Trying to set render target 0 to NULL\n");
5757 return WINED3DERR_INVALIDCALL;
5759 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5760 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);
5761 return WINED3DERR_INVALIDCALL;
5764 /* If we are trying to set what we already have, don't bother */
5765 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5766 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5769 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5770 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5771 This->render_targets[RenderTargetIndex] = pRenderTarget;
5773 /* Render target 0 is special */
5774 if(RenderTargetIndex == 0) {
5775 /* Finally, reset the viewport as the MSDN states. */
5776 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5777 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5780 viewport.MaxZ = 1.0f;
5781 viewport.MinZ = 0.0f;
5782 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5783 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5784 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5786 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5788 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5790 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5791 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5793 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5798 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5800 HRESULT hr = WINED3D_OK;
5801 IWineD3DSurface *tmp;
5803 TRACE("(%p) Swapping z-buffer\n",This);
5805 if (pNewZStencil == This->stencilBufferTarget) {
5806 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5808 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5809 * depending on the renter target implementation being used.
5810 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5811 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5812 * stencil buffer and incure an extra memory overhead
5813 ******************************************************/
5815 tmp = This->stencilBufferTarget;
5816 This->stencilBufferTarget = pNewZStencil;
5817 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5818 /* should we be calling the parent or the wined3d surface? */
5819 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5820 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5823 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5824 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5825 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5826 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5827 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5834 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5835 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5836 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5837 /* TODO: the use of Impl is deprecated. */
5838 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5839 WINED3DLOCKED_RECT lockedRect;
5841 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5843 /* some basic validation checks */
5844 if(This->cursorTexture) {
5846 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5847 glDeleteTextures(1, &This->cursorTexture);
5849 This->cursorTexture = 0;
5852 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5853 This->haveHardwareCursor = TRUE;
5855 This->haveHardwareCursor = FALSE;
5858 WINED3DLOCKED_RECT rect;
5860 /* MSDN: Cursor must be A8R8G8B8 */
5861 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5862 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5863 return WINED3DERR_INVALIDCALL;
5866 /* MSDN: Cursor must be smaller than the display mode */
5867 if(pSur->currentDesc.Width > This->ddraw_width ||
5868 pSur->currentDesc.Height > This->ddraw_height) {
5869 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);
5870 return WINED3DERR_INVALIDCALL;
5873 if (!This->haveHardwareCursor) {
5874 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5876 /* Do not store the surface's pointer because the application may
5877 * release it after setting the cursor image. Windows doesn't
5878 * addref the set surface, so we can't do this either without
5879 * creating circular refcount dependencies. Copy out the gl texture
5882 This->cursorWidth = pSur->currentDesc.Width;
5883 This->cursorHeight = pSur->currentDesc.Height;
5884 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5886 const PixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8);
5887 char *mem, *bits = (char *)rect.pBits;
5888 GLint intfmt = tableEntry->glInternal;
5889 GLint format = tableEntry->glFormat;
5890 GLint type = tableEntry->glType;
5891 INT height = This->cursorHeight;
5892 INT width = This->cursorWidth;
5893 INT bpp = tableEntry->bpp;
5896 /* Reformat the texture memory (pitch and width can be
5898 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5899 for(i = 0; i < height; i++)
5900 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5901 IWineD3DSurface_UnlockRect(pCursorBitmap);
5904 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5905 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5906 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5909 /* Make sure that a proper texture unit is selected */
5910 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5911 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5912 checkGLcall("glActiveTextureARB");
5914 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5915 /* Create a new cursor texture */
5916 glGenTextures(1, &This->cursorTexture);
5917 checkGLcall("glGenTextures");
5918 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5919 checkGLcall("glBindTexture");
5920 /* Copy the bitmap memory into the cursor texture */
5921 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5922 HeapFree(GetProcessHeap(), 0, mem);
5923 checkGLcall("glTexImage2D");
5925 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5926 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5927 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5934 FIXME("A cursor texture was not returned.\n");
5935 This->cursorTexture = 0;
5940 /* Draw a hardware cursor */
5941 ICONINFO cursorInfo;
5943 /* Create and clear maskBits because it is not needed for
5944 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5946 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5947 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
5948 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
5949 WINED3DLOCK_NO_DIRTY_UPDATE |
5950 WINED3DLOCK_READONLY
5952 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
5953 pSur->currentDesc.Height);
5955 cursorInfo.fIcon = FALSE;
5956 cursorInfo.xHotspot = XHotSpot;
5957 cursorInfo.yHotspot = YHotSpot;
5958 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
5959 pSur->currentDesc.Height, 1,
5961 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
5962 pSur->currentDesc.Height, 1,
5963 32, lockedRect.pBits);
5964 IWineD3DSurface_UnlockRect(pCursorBitmap);
5965 /* Create our cursor and clean up. */
5966 cursor = CreateIconIndirect(&cursorInfo);
5968 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5969 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5970 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5971 This->hardwareCursor = cursor;
5972 HeapFree(GetProcessHeap(), 0, maskBits);
5976 This->xHotSpot = XHotSpot;
5977 This->yHotSpot = YHotSpot;
5981 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5983 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5985 This->xScreenSpace = XScreenSpace;
5986 This->yScreenSpace = YScreenSpace;
5992 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5994 BOOL oldVisible = This->bCursorVisible;
5997 TRACE("(%p) : visible(%d)\n", This, bShow);
6000 * When ShowCursor is first called it should make the cursor appear at the OS's last
6001 * known cursor position. Because of this, some applications just repetitively call
6002 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6005 This->xScreenSpace = pt.x;
6006 This->yScreenSpace = pt.y;
6008 if (This->haveHardwareCursor) {
6009 This->bCursorVisible = bShow;
6011 SetCursor(This->hardwareCursor);
6017 if (This->cursorTexture)
6018 This->bCursorVisible = bShow;
6024 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6026 TRACE("(%p) : state (%u)\n", This, This->state);
6027 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6028 switch (This->state) {
6031 case WINED3DERR_DEVICELOST:
6033 ResourceList *resourceList = This->resources;
6034 while (NULL != resourceList) {
6035 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6036 return WINED3DERR_DEVICENOTRESET;
6037 resourceList = resourceList->next;
6039 return WINED3DERR_DEVICELOST;
6041 case WINED3DERR_DRIVERINTERNALERROR:
6042 return WINED3DERR_DRIVERINTERNALERROR;
6046 return WINED3DERR_DRIVERINTERNALERROR;
6050 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6052 /** FIXME: Resource tracking needs to be done,
6053 * The closes we can do to this is set the priorities of all managed textures low
6054 * and then reset them.
6055 ***********************************************************/
6056 FIXME("(%p) : stub\n", This);
6060 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6061 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6063 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6064 if(surface->Flags & SFLAG_DIBSECTION) {
6065 /* Release the DC */
6066 SelectObject(surface->hDC, surface->dib.holdbitmap);
6067 DeleteDC(surface->hDC);
6068 /* Release the DIB section */
6069 DeleteObject(surface->dib.DIBsection);
6070 surface->dib.bitmap_data = NULL;
6071 surface->resource.allocatedMemory = NULL;
6072 surface->Flags &= ~SFLAG_DIBSECTION;
6074 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6075 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6076 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6077 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6078 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6080 surface->pow2Width = surface->pow2Height = 1;
6081 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6082 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6084 if(surface->glDescription.textureName) {
6086 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6087 glDeleteTextures(1, &surface->glDescription.textureName);
6089 surface->glDescription.textureName = 0;
6090 surface->Flags &= ~SFLAG_CLIENT;
6092 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6093 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6094 surface->Flags |= SFLAG_NONPOW2;
6096 surface->Flags &= ~SFLAG_NONPOW2;
6098 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6099 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6102 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6104 IWineD3DSwapChainImpl *swapchain;
6106 BOOL DisplayModeChanged = FALSE;
6107 WINED3DDISPLAYMODE mode;
6108 TRACE("(%p)\n", This);
6110 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6112 ERR("Failed to get the first implicit swapchain\n");
6116 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6117 * on an existing gl context, so there's no real need for recreation.
6119 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6121 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6123 TRACE("New params:\n");
6124 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6125 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6126 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6127 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6128 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6129 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6130 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6131 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6132 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6133 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6134 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6135 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6136 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6138 /* No special treatment of these parameters. Just store them */
6139 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6140 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6141 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6142 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6144 /* What to do about these? */
6145 if(pPresentationParameters->BackBufferCount != 0 &&
6146 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6147 ERR("Cannot change the back buffer count yet\n");
6149 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6150 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6151 ERR("Cannot change the back buffer format yet\n");
6153 if(pPresentationParameters->hDeviceWindow != NULL &&
6154 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6155 ERR("Cannot change the device window yet\n");
6157 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6158 ERR("What do do about a changed auto depth stencil parameter?\n");
6161 if(pPresentationParameters->Windowed) {
6162 mode.Width = swapchain->orig_width;
6163 mode.Height = swapchain->orig_height;
6164 mode.RefreshRate = 0;
6165 mode.Format = swapchain->presentParms.BackBufferFormat;
6167 mode.Width = pPresentationParameters->BackBufferWidth;
6168 mode.Height = pPresentationParameters->BackBufferHeight;
6169 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6170 mode.Format = swapchain->presentParms.BackBufferFormat;
6173 /* Should Width == 800 && Height == 0 set 800x600? */
6174 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6175 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6176 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6183 vp.Width = pPresentationParameters->BackBufferWidth;
6184 vp.Height = pPresentationParameters->BackBufferHeight;
6188 if(!pPresentationParameters->Windowed) {
6189 DisplayModeChanged = TRUE;
6191 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6192 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6194 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6195 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6196 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6199 /* Now set the new viewport */
6200 IWineD3DDevice_SetViewport(iface, &vp);
6203 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6204 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6205 DisplayModeChanged) {
6207 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6208 if(!pPresentationParameters->Windowed) {
6209 IWineD3DDevice_SetFullscreen(iface, TRUE);
6212 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6214 /* Switching out of fullscreen mode? First set the original res, then change the window */
6215 if(pPresentationParameters->Windowed) {
6216 IWineD3DDevice_SetFullscreen(iface, FALSE);
6218 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6221 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6225 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6227 /** FIXME: always true at the moment **/
6228 if(!bEnableDialogs) {
6229 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6235 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6237 TRACE("(%p) : pParameters %p\n", This, pParameters);
6239 *pParameters = This->createParms;
6243 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6244 IWineD3DSwapChain *swapchain;
6245 HRESULT hrc = WINED3D_OK;
6247 TRACE("Relaying to swapchain\n");
6249 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6250 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6251 IWineD3DSwapChain_Release(swapchain);
6256 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6257 IWineD3DSwapChain *swapchain;
6258 HRESULT hrc = WINED3D_OK;
6260 TRACE("Relaying to swapchain\n");
6262 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6263 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6264 IWineD3DSwapChain_Release(swapchain);
6270 /** ********************************************************
6271 * Notification functions
6272 ** ********************************************************/
6273 /** This function must be called in the release of a resource when ref == 0,
6274 * the contents of resource must still be correct,
6275 * any handels to other resource held by the caller must be closed
6276 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6277 *****************************************************/
6278 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6280 ResourceList* resourceList;
6282 TRACE("(%p) : resource %p\n", This, resource);
6283 /* add a new texture to the frot of the linked list */
6284 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6285 resourceList->resource = resource;
6287 /* Get the old head */
6288 resourceList->next = This->resources;
6290 This->resources = resourceList;
6291 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6296 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6298 ResourceList* resourceList = NULL;
6299 ResourceList* previousResourceList = NULL;
6301 TRACE("(%p) : resource %p\n", This, resource);
6303 resourceList = This->resources;
6305 while (resourceList != NULL) {
6306 if(resourceList->resource == resource) break;
6307 previousResourceList = resourceList;
6308 resourceList = resourceList->next;
6311 if (resourceList == NULL) {
6312 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6315 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6317 /* make sure we don't leave a hole in the list */
6318 if (previousResourceList != NULL) {
6319 previousResourceList->next = resourceList->next;
6321 This->resources = resourceList->next;
6328 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6332 TRACE("(%p) : resource %p\n", This, resource);
6333 switch(IWineD3DResource_GetType(resource)){
6334 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6335 case WINED3DRTYPE_SURFACE: {
6338 /* Cleanup any FBO attachments */
6339 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6340 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6341 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6342 set_render_target_fbo(iface, i, NULL);
6343 This->fbo_color_attachments[i] = NULL;
6346 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6347 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6348 set_depth_stencil_fbo(iface, NULL);
6349 This->fbo_depth_attachment = NULL;
6355 case WINED3DRTYPE_TEXTURE:
6356 case WINED3DRTYPE_CUBETEXTURE:
6357 case WINED3DRTYPE_VOLUMETEXTURE:
6358 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6359 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6360 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6361 This->stateBlock->textures[counter] = NULL;
6363 if (This->updateStateBlock != This->stateBlock ){
6364 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6365 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6366 This->updateStateBlock->textures[counter] = NULL;
6371 case WINED3DRTYPE_VOLUME:
6372 /* TODO: nothing really? */
6374 case WINED3DRTYPE_VERTEXBUFFER:
6375 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6378 TRACE("Cleaning up stream pointers\n");
6380 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6381 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6382 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6384 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6385 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6386 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6387 This->updateStateBlock->streamSource[streamNumber] = 0;
6388 /* Set changed flag? */
6391 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) */
6392 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6393 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6394 This->stateBlock->streamSource[streamNumber] = 0;
6397 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6398 else { /* This shouldn't happen */
6399 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6406 case WINED3DRTYPE_INDEXBUFFER:
6407 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6408 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6409 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6410 This->updateStateBlock->pIndexData = NULL;
6413 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6414 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6415 This->stateBlock->pIndexData = NULL;
6421 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6426 /* Remove the resoruce from the resourceStore */
6427 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6429 TRACE("Resource released\n");
6433 /**********************************************************
6434 * IWineD3DDevice VTbl follows
6435 **********************************************************/
6437 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6439 /*** IUnknown methods ***/
6440 IWineD3DDeviceImpl_QueryInterface,
6441 IWineD3DDeviceImpl_AddRef,
6442 IWineD3DDeviceImpl_Release,
6443 /*** IWineD3DDevice methods ***/
6444 IWineD3DDeviceImpl_GetParent,
6445 /*** Creation methods**/
6446 IWineD3DDeviceImpl_CreateVertexBuffer,
6447 IWineD3DDeviceImpl_CreateIndexBuffer,
6448 IWineD3DDeviceImpl_CreateStateBlock,
6449 IWineD3DDeviceImpl_CreateSurface,
6450 IWineD3DDeviceImpl_CreateTexture,
6451 IWineD3DDeviceImpl_CreateVolumeTexture,
6452 IWineD3DDeviceImpl_CreateVolume,
6453 IWineD3DDeviceImpl_CreateCubeTexture,
6454 IWineD3DDeviceImpl_CreateQuery,
6455 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6456 IWineD3DDeviceImpl_CreateVertexDeclaration,
6457 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6458 IWineD3DDeviceImpl_CreateVertexShader,
6459 IWineD3DDeviceImpl_CreatePixelShader,
6460 IWineD3DDeviceImpl_CreatePalette,
6461 /*** Odd functions **/
6462 IWineD3DDeviceImpl_Init3D,
6463 IWineD3DDeviceImpl_Uninit3D,
6464 IWineD3DDeviceImpl_SetFullscreen,
6465 IWineD3DDeviceImpl_SetMultithreaded,
6466 IWineD3DDeviceImpl_EvictManagedResources,
6467 IWineD3DDeviceImpl_GetAvailableTextureMem,
6468 IWineD3DDeviceImpl_GetBackBuffer,
6469 IWineD3DDeviceImpl_GetCreationParameters,
6470 IWineD3DDeviceImpl_GetDeviceCaps,
6471 IWineD3DDeviceImpl_GetDirect3D,
6472 IWineD3DDeviceImpl_GetDisplayMode,
6473 IWineD3DDeviceImpl_SetDisplayMode,
6474 IWineD3DDeviceImpl_GetHWND,
6475 IWineD3DDeviceImpl_SetHWND,
6476 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6477 IWineD3DDeviceImpl_GetRasterStatus,
6478 IWineD3DDeviceImpl_GetSwapChain,
6479 IWineD3DDeviceImpl_Reset,
6480 IWineD3DDeviceImpl_SetDialogBoxMode,
6481 IWineD3DDeviceImpl_SetCursorProperties,
6482 IWineD3DDeviceImpl_SetCursorPosition,
6483 IWineD3DDeviceImpl_ShowCursor,
6484 IWineD3DDeviceImpl_TestCooperativeLevel,
6485 /*** Getters and setters **/
6486 IWineD3DDeviceImpl_SetClipPlane,
6487 IWineD3DDeviceImpl_GetClipPlane,
6488 IWineD3DDeviceImpl_SetClipStatus,
6489 IWineD3DDeviceImpl_GetClipStatus,
6490 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6491 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6492 IWineD3DDeviceImpl_SetDepthStencilSurface,
6493 IWineD3DDeviceImpl_GetDepthStencilSurface,
6494 IWineD3DDeviceImpl_SetFVF,
6495 IWineD3DDeviceImpl_GetFVF,
6496 IWineD3DDeviceImpl_SetGammaRamp,
6497 IWineD3DDeviceImpl_GetGammaRamp,
6498 IWineD3DDeviceImpl_SetIndices,
6499 IWineD3DDeviceImpl_GetIndices,
6500 IWineD3DDeviceImpl_SetBaseVertexIndex,
6501 IWineD3DDeviceImpl_GetBaseVertexIndex,
6502 IWineD3DDeviceImpl_SetLight,
6503 IWineD3DDeviceImpl_GetLight,
6504 IWineD3DDeviceImpl_SetLightEnable,
6505 IWineD3DDeviceImpl_GetLightEnable,
6506 IWineD3DDeviceImpl_SetMaterial,
6507 IWineD3DDeviceImpl_GetMaterial,
6508 IWineD3DDeviceImpl_SetNPatchMode,
6509 IWineD3DDeviceImpl_GetNPatchMode,
6510 IWineD3DDeviceImpl_SetPaletteEntries,
6511 IWineD3DDeviceImpl_GetPaletteEntries,
6512 IWineD3DDeviceImpl_SetPixelShader,
6513 IWineD3DDeviceImpl_GetPixelShader,
6514 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6515 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6516 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6517 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6518 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6519 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6520 IWineD3DDeviceImpl_SetRenderState,
6521 IWineD3DDeviceImpl_GetRenderState,
6522 IWineD3DDeviceImpl_SetRenderTarget,
6523 IWineD3DDeviceImpl_GetRenderTarget,
6524 IWineD3DDeviceImpl_SetFrontBackBuffers,
6525 IWineD3DDeviceImpl_SetSamplerState,
6526 IWineD3DDeviceImpl_GetSamplerState,
6527 IWineD3DDeviceImpl_SetScissorRect,
6528 IWineD3DDeviceImpl_GetScissorRect,
6529 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6530 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6531 IWineD3DDeviceImpl_SetStreamSource,
6532 IWineD3DDeviceImpl_GetStreamSource,
6533 IWineD3DDeviceImpl_SetStreamSourceFreq,
6534 IWineD3DDeviceImpl_GetStreamSourceFreq,
6535 IWineD3DDeviceImpl_SetTexture,
6536 IWineD3DDeviceImpl_GetTexture,
6537 IWineD3DDeviceImpl_SetTextureStageState,
6538 IWineD3DDeviceImpl_GetTextureStageState,
6539 IWineD3DDeviceImpl_SetTransform,
6540 IWineD3DDeviceImpl_GetTransform,
6541 IWineD3DDeviceImpl_SetVertexDeclaration,
6542 IWineD3DDeviceImpl_GetVertexDeclaration,
6543 IWineD3DDeviceImpl_SetVertexShader,
6544 IWineD3DDeviceImpl_GetVertexShader,
6545 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6546 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6547 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6548 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6549 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6550 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6551 IWineD3DDeviceImpl_SetViewport,
6552 IWineD3DDeviceImpl_GetViewport,
6553 IWineD3DDeviceImpl_MultiplyTransform,
6554 IWineD3DDeviceImpl_ValidateDevice,
6555 IWineD3DDeviceImpl_ProcessVertices,
6556 /*** State block ***/
6557 IWineD3DDeviceImpl_BeginStateBlock,
6558 IWineD3DDeviceImpl_EndStateBlock,
6559 /*** Scene management ***/
6560 IWineD3DDeviceImpl_BeginScene,
6561 IWineD3DDeviceImpl_EndScene,
6562 IWineD3DDeviceImpl_Present,
6563 IWineD3DDeviceImpl_Clear,
6565 IWineD3DDeviceImpl_DrawPrimitive,
6566 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6567 IWineD3DDeviceImpl_DrawPrimitiveUP,
6568 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6569 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6570 IWineD3DDeviceImpl_DrawRectPatch,
6571 IWineD3DDeviceImpl_DrawTriPatch,
6572 IWineD3DDeviceImpl_DeletePatch,
6573 IWineD3DDeviceImpl_ColorFill,
6574 IWineD3DDeviceImpl_UpdateTexture,
6575 IWineD3DDeviceImpl_UpdateSurface,
6576 IWineD3DDeviceImpl_GetFrontBufferData,
6577 /*** object tracking ***/
6578 IWineD3DDeviceImpl_ResourceReleased
6582 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6583 WINED3DRS_ALPHABLENDENABLE ,
6584 WINED3DRS_ALPHAFUNC ,
6585 WINED3DRS_ALPHAREF ,
6586 WINED3DRS_ALPHATESTENABLE ,
6588 WINED3DRS_COLORWRITEENABLE ,
6589 WINED3DRS_DESTBLEND ,
6590 WINED3DRS_DITHERENABLE ,
6591 WINED3DRS_FILLMODE ,
6592 WINED3DRS_FOGDENSITY ,
6594 WINED3DRS_FOGSTART ,
6595 WINED3DRS_LASTPIXEL ,
6596 WINED3DRS_SHADEMODE ,
6597 WINED3DRS_SRCBLEND ,
6598 WINED3DRS_STENCILENABLE ,
6599 WINED3DRS_STENCILFAIL ,
6600 WINED3DRS_STENCILFUNC ,
6601 WINED3DRS_STENCILMASK ,
6602 WINED3DRS_STENCILPASS ,
6603 WINED3DRS_STENCILREF ,
6604 WINED3DRS_STENCILWRITEMASK ,
6605 WINED3DRS_STENCILZFAIL ,
6606 WINED3DRS_TEXTUREFACTOR ,
6617 WINED3DRS_ZWRITEENABLE
6620 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6621 WINED3DTSS_ADDRESSW ,
6622 WINED3DTSS_ALPHAARG0 ,
6623 WINED3DTSS_ALPHAARG1 ,
6624 WINED3DTSS_ALPHAARG2 ,
6625 WINED3DTSS_ALPHAOP ,
6626 WINED3DTSS_BUMPENVLOFFSET ,
6627 WINED3DTSS_BUMPENVLSCALE ,
6628 WINED3DTSS_BUMPENVMAT00 ,
6629 WINED3DTSS_BUMPENVMAT01 ,
6630 WINED3DTSS_BUMPENVMAT10 ,
6631 WINED3DTSS_BUMPENVMAT11 ,
6632 WINED3DTSS_COLORARG0 ,
6633 WINED3DTSS_COLORARG1 ,
6634 WINED3DTSS_COLORARG2 ,
6635 WINED3DTSS_COLOROP ,
6636 WINED3DTSS_RESULTARG ,
6637 WINED3DTSS_TEXCOORDINDEX ,
6638 WINED3DTSS_TEXTURETRANSFORMFLAGS
6641 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6642 WINED3DSAMP_ADDRESSU ,
6643 WINED3DSAMP_ADDRESSV ,
6644 WINED3DSAMP_ADDRESSW ,
6645 WINED3DSAMP_BORDERCOLOR ,
6646 WINED3DSAMP_MAGFILTER ,
6647 WINED3DSAMP_MINFILTER ,
6648 WINED3DSAMP_MIPFILTER ,
6649 WINED3DSAMP_MIPMAPLODBIAS ,
6650 WINED3DSAMP_MAXMIPLEVEL ,
6651 WINED3DSAMP_MAXANISOTROPY ,
6652 WINED3DSAMP_SRGBTEXTURE ,
6653 WINED3DSAMP_ELEMENTINDEX
6656 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6658 WINED3DRS_AMBIENTMATERIALSOURCE ,
6659 WINED3DRS_CLIPPING ,
6660 WINED3DRS_CLIPPLANEENABLE ,
6661 WINED3DRS_COLORVERTEX ,
6662 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6663 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6664 WINED3DRS_FOGDENSITY ,
6666 WINED3DRS_FOGSTART ,
6667 WINED3DRS_FOGTABLEMODE ,
6668 WINED3DRS_FOGVERTEXMODE ,
6669 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6670 WINED3DRS_LIGHTING ,
6671 WINED3DRS_LOCALVIEWER ,
6672 WINED3DRS_MULTISAMPLEANTIALIAS ,
6673 WINED3DRS_MULTISAMPLEMASK ,
6674 WINED3DRS_NORMALIZENORMALS ,
6675 WINED3DRS_PATCHEDGESTYLE ,
6676 WINED3DRS_POINTSCALE_A ,
6677 WINED3DRS_POINTSCALE_B ,
6678 WINED3DRS_POINTSCALE_C ,
6679 WINED3DRS_POINTSCALEENABLE ,
6680 WINED3DRS_POINTSIZE ,
6681 WINED3DRS_POINTSIZE_MAX ,
6682 WINED3DRS_POINTSIZE_MIN ,
6683 WINED3DRS_POINTSPRITEENABLE ,
6684 WINED3DRS_RANGEFOGENABLE ,
6685 WINED3DRS_SPECULARMATERIALSOURCE ,
6686 WINED3DRS_TWEENFACTOR ,
6687 WINED3DRS_VERTEXBLEND
6690 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6691 WINED3DTSS_TEXCOORDINDEX ,
6692 WINED3DTSS_TEXTURETRANSFORMFLAGS
6695 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6696 WINED3DSAMP_DMAPOFFSET
6699 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6700 DWORD rep = StateTable[state].representative;
6704 WineD3DContext *context;
6707 for(i = 0; i < This->numContexts; i++) {
6708 context = This->contexts[i];
6709 if(isStateDirty(context, rep)) continue;
6711 context->dirtyArray[context->numDirtyEntries++] = rep;
6714 context->isStateDirty[idx] |= (1 << shift);