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_SAMPLERS; state++) {
1814 if (state < GL_LIMITS(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;
1822 This->oneToOneTexUnitMap = TRUE;
1824 /* Setup the implicit swapchain */
1825 TRACE("Creating implicit swapchain\n");
1826 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1827 if (FAILED(hr) || !swapchain) {
1828 WARN("Failed to create implicit swapchain\n");
1832 This->NumberOfSwapChains = 1;
1833 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1834 if(!This->swapchains) {
1835 ERR("Out of memory!\n");
1836 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1837 return E_OUTOFMEMORY;
1839 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1841 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1843 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1844 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1845 This->render_targets[0] = swapchain->backBuffer[0];
1846 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1849 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1850 This->render_targets[0] = swapchain->frontBuffer;
1851 This->lastActiveRenderTarget = swapchain->frontBuffer;
1853 IWineD3DSurface_AddRef(This->render_targets[0]);
1854 This->activeContext = swapchain->context[0];
1856 /* Depth Stencil support */
1857 This->stencilBufferTarget = This->depthStencilBuffer;
1858 if (NULL != This->stencilBufferTarget) {
1859 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1862 /* Set up some starting GL setup */
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_SAMPLERS; ++sampler) {
1945 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1948 /* Release the buffers (with sanity checks)*/
1949 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1950 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1951 if(This->depthStencilBuffer != This->stencilBufferTarget)
1952 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1954 This->stencilBufferTarget = NULL;
1956 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1957 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1958 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1960 TRACE("Setting rendertarget to NULL\n");
1961 This->render_targets[0] = NULL;
1963 if (This->depthStencilBuffer) {
1964 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1965 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1967 This->depthStencilBuffer = NULL;
1970 for(i=0; i < This->NumberOfSwapChains; i++) {
1971 TRACE("Releasing the implicit swapchain %d\n", i);
1972 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1973 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1977 HeapFree(GetProcessHeap(), 0, This->swapchains);
1978 This->swapchains = NULL;
1979 This->NumberOfSwapChains = 0;
1981 This->d3d_initialized = FALSE;
1985 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1987 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1989 /* Setup the window for fullscreen mode */
1990 if(fullscreen && !This->ddraw_fullscreen) {
1991 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1992 } else if(!fullscreen && This->ddraw_fullscreen) {
1993 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1996 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1997 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1998 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2001 This->ddraw_fullscreen = fullscreen;
2004 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2005 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2006 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2008 * There is no way to deactivate thread safety once it is enabled
2010 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2012 FIXME("No thread safety in wined3d yet\n");
2014 /*For now just store the flag(needed in case of ddraw) */
2015 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2020 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2024 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2027 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2029 /* Resize the screen even without a window:
2030 * The app could have unset it with SetCooperativeLevel, but not called
2031 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2032 * but we don't have any hwnd
2035 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2036 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2037 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2038 devmode.dmPelsWidth = pMode->Width;
2039 devmode.dmPelsHeight = pMode->Height;
2041 devmode.dmDisplayFrequency = pMode->RefreshRate;
2042 if (pMode->RefreshRate != 0) {
2043 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2046 /* Only change the mode if necessary */
2047 if( (This->ddraw_width == pMode->Width) &&
2048 (This->ddraw_height == pMode->Height) &&
2049 (This->ddraw_format == pMode->Format) &&
2050 (pMode->RefreshRate == 0) ) {
2054 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2055 if (ret != DISP_CHANGE_SUCCESSFUL) {
2056 if(devmode.dmDisplayFrequency != 0) {
2057 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2058 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2059 devmode.dmDisplayFrequency = 0;
2060 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2062 if(ret != DISP_CHANGE_SUCCESSFUL) {
2063 return WINED3DERR_NOTAVAILABLE;
2067 /* Store the new values */
2068 This->ddraw_width = pMode->Width;
2069 This->ddraw_height = pMode->Height;
2070 This->ddraw_format = pMode->Format;
2072 /* Only do this with a window of course */
2073 if(This->ddraw_window)
2074 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2076 /* And finally clip mouse to our screen */
2077 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2078 ClipCursor(&clip_rc);
2083 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2085 *ppD3D= This->wineD3D;
2086 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2087 IWineD3D_AddRef(*ppD3D);
2091 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2092 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2093 * into the video ram as possible and seeing how many fit
2094 * you can also get the correct initial value from nvidia and ATI's driver via X
2095 * texture memory is video memory + AGP memory
2096 *******************/
2097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2098 static BOOL showfixmes = TRUE;
2100 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2101 (wined3d_settings.emulated_textureram/(1024*1024)),
2102 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2105 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2106 (wined3d_settings.emulated_textureram/(1024*1024)),
2107 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2108 /* return simulated texture memory left */
2109 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2117 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2120 /* Update the current state block */
2121 This->updateStateBlock->changed.fvf = TRUE;
2122 This->updateStateBlock->set.fvf = TRUE;
2124 if(This->updateStateBlock->fvf == fvf) {
2125 TRACE("Application is setting the old fvf over, nothing to do\n");
2129 This->updateStateBlock->fvf = fvf;
2130 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2131 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2136 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2138 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2139 *pfvf = This->stateBlock->fvf;
2144 * Get / Set Stream Source
2146 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2148 IWineD3DVertexBuffer *oldSrc;
2150 if (StreamNumber >= MAX_STREAMS) {
2151 WARN("Stream out of range %d\n", StreamNumber);
2152 return WINED3DERR_INVALIDCALL;
2155 oldSrc = This->stateBlock->streamSource[StreamNumber];
2156 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2158 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2159 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2161 if(oldSrc == pStreamData &&
2162 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2163 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2164 TRACE("Application is setting the old values over, nothing to do\n");
2168 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2170 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2171 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2174 /* Handle recording of state blocks */
2175 if (This->isRecordingState) {
2176 TRACE("Recording... not performing anything\n");
2180 /* Need to do a getParent and pass the reffs up */
2181 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2182 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2183 so for now, just count internally */
2184 if (pStreamData != NULL) {
2185 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2186 InterlockedIncrement(&vbImpl->bindCount);
2188 if (oldSrc != NULL) {
2189 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2192 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2197 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2200 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2201 This->stateBlock->streamSource[StreamNumber],
2202 This->stateBlock->streamOffset[StreamNumber],
2203 This->stateBlock->streamStride[StreamNumber]);
2205 if (StreamNumber >= MAX_STREAMS) {
2206 WARN("Stream out of range %d\n", StreamNumber);
2207 return WINED3DERR_INVALIDCALL;
2209 *pStream = This->stateBlock->streamSource[StreamNumber];
2210 *pStride = This->stateBlock->streamStride[StreamNumber];
2212 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2215 if (*pStream != NULL) {
2216 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2221 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2223 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2224 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2226 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2227 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2229 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2230 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2231 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2233 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2234 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2235 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2241 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2244 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2245 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2247 TRACE("(%p) : returning %d\n", This, *Divider);
2253 * Get / Set & Multiply Transform
2255 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2258 /* Most of this routine, comments included copied from ddraw tree initially: */
2259 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2261 /* Handle recording of state blocks */
2262 if (This->isRecordingState) {
2263 TRACE("Recording... not performing anything\n");
2264 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2265 This->updateStateBlock->set.transform[d3dts] = TRUE;
2266 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2271 * If the new matrix is the same as the current one,
2272 * we cut off any further processing. this seems to be a reasonable
2273 * optimization because as was noticed, some apps (warcraft3 for example)
2274 * tend towards setting the same matrix repeatedly for some reason.
2276 * From here on we assume that the new matrix is different, wherever it matters.
2278 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2279 TRACE("The app is setting the same matrix over again\n");
2282 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2286 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2287 where ViewMat = Camera space, WorldMat = world space.
2289 In OpenGL, camera and world space is combined into GL_MODELVIEW
2290 matrix. The Projection matrix stay projection matrix.
2293 /* Capture the times we can just ignore the change for now */
2294 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2295 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2296 /* Handled by the state manager */
2299 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2303 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2305 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2306 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2310 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2311 WINED3DMATRIX *mat = NULL;
2314 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2315 * below means it will be recorded in a state block change, but it
2316 * works regardless where it is recorded.
2317 * If this is found to be wrong, change to StateBlock.
2319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2320 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2322 if (State < HIGHEST_TRANSFORMSTATE)
2324 mat = &This->updateStateBlock->transforms[State];
2326 FIXME("Unhandled transform state!!\n");
2329 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2331 /* Apply change via set transform - will reapply to eg. lights this way */
2332 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2338 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2339 you can reference any indexes you want as long as that number max are enabled at any
2340 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2341 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2342 but when recording, just build a chain pretty much of commands to be replayed. */
2344 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2346 PLIGHTINFOEL *object = NULL;
2347 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2351 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2353 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2357 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2358 return WINED3DERR_INVALIDCALL;
2361 switch(pLight->Type) {
2362 case WINED3DLIGHT_POINT:
2363 case WINED3DLIGHT_SPOT:
2364 case WINED3DLIGHT_PARALLELPOINT:
2365 case WINED3DLIGHT_GLSPOT:
2366 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2369 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2370 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2371 return WINED3DERR_INVALIDCALL;
2375 case WINED3DLIGHT_DIRECTIONAL:
2376 /* Ignores attenuation */
2380 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2381 return WINED3DERR_INVALIDCALL;
2384 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2385 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2386 if(object->OriginalIndex == Index) break;
2391 TRACE("Adding new light\n");
2392 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2394 ERR("Out of memory error when allocating a light\n");
2395 return E_OUTOFMEMORY;
2397 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2398 object->glIndex = -1;
2399 object->OriginalIndex = Index;
2400 object->changed = TRUE;
2403 /* Initialize the object */
2404 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,
2405 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2406 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2407 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2408 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2409 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2410 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2412 /* Save away the information */
2413 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2415 switch (pLight->Type) {
2416 case WINED3DLIGHT_POINT:
2418 object->lightPosn[0] = pLight->Position.x;
2419 object->lightPosn[1] = pLight->Position.y;
2420 object->lightPosn[2] = pLight->Position.z;
2421 object->lightPosn[3] = 1.0f;
2422 object->cutoff = 180.0f;
2426 case WINED3DLIGHT_DIRECTIONAL:
2428 object->lightPosn[0] = -pLight->Direction.x;
2429 object->lightPosn[1] = -pLight->Direction.y;
2430 object->lightPosn[2] = -pLight->Direction.z;
2431 object->lightPosn[3] = 0.0;
2432 object->exponent = 0.0f;
2433 object->cutoff = 180.0f;
2436 case WINED3DLIGHT_SPOT:
2438 object->lightPosn[0] = pLight->Position.x;
2439 object->lightPosn[1] = pLight->Position.y;
2440 object->lightPosn[2] = pLight->Position.z;
2441 object->lightPosn[3] = 1.0;
2444 object->lightDirn[0] = pLight->Direction.x;
2445 object->lightDirn[1] = pLight->Direction.y;
2446 object->lightDirn[2] = pLight->Direction.z;
2447 object->lightDirn[3] = 1.0;
2450 * opengl-ish and d3d-ish spot lights use too different models for the
2451 * light "intensity" as a function of the angle towards the main light direction,
2452 * so we only can approximate very roughly.
2453 * however spot lights are rather rarely used in games (if ever used at all).
2454 * furthermore if still used, probably nobody pays attention to such details.
2456 if (pLight->Falloff == 0) {
2459 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2461 if (rho < 0.0001) rho = 0.0001f;
2462 object->exponent = -0.3/log(cos(rho/2));
2463 if (object->exponent > 128.0) {
2464 object->exponent = 128.0;
2466 object->cutoff = pLight->Phi*90/M_PI;
2472 FIXME("Unrecognized light type %d\n", pLight->Type);
2475 /* Update the live definitions if the light is currently assigned a glIndex */
2476 if (object->glIndex != -1 && !This->isRecordingState) {
2477 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2482 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2483 PLIGHTINFOEL *lightInfo = NULL;
2484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2485 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2487 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2489 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2490 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2491 if(lightInfo->OriginalIndex == Index) break;
2495 if (lightInfo == NULL) {
2496 TRACE("Light information requested but light not defined\n");
2497 return WINED3DERR_INVALIDCALL;
2500 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2505 * Get / Set Light Enable
2506 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2508 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2509 PLIGHTINFOEL *lightInfo = NULL;
2510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2511 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2513 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2515 /* Tests show true = 128...not clear why */
2516 Enable = Enable? 128: 0;
2518 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2519 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2520 if(lightInfo->OriginalIndex == Index) break;
2523 TRACE("Found light: %p\n", lightInfo);
2525 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2526 if (lightInfo == NULL) {
2528 TRACE("Light enabled requested but light not defined, so defining one!\n");
2529 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2531 /* Search for it again! Should be fairly quick as near head of list */
2532 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2533 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2534 if(lightInfo->OriginalIndex == Index) break;
2537 if (lightInfo == NULL) {
2538 FIXME("Adding default lights has failed dismally\n");
2539 return WINED3DERR_INVALIDCALL;
2543 lightInfo->enabledChanged = TRUE;
2545 if(lightInfo->glIndex != -1) {
2546 if(!This->isRecordingState) {
2547 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2550 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2551 lightInfo->glIndex = -1;
2553 TRACE("Light already disabled, nothing to do\n");
2556 if (lightInfo->glIndex != -1) {
2558 TRACE("Nothing to do as light was enabled\n");
2561 /* Find a free gl light */
2562 for(i = 0; i < This->maxConcurrentLights; i++) {
2563 if(This->stateBlock->activeLights[i] == NULL) {
2564 This->stateBlock->activeLights[i] = lightInfo;
2565 lightInfo->glIndex = i;
2569 if(lightInfo->glIndex == -1) {
2570 ERR("Too many concurrently active lights\n");
2571 return WINED3DERR_INVALIDCALL;
2574 /* i == lightInfo->glIndex */
2575 if(!This->isRecordingState) {
2576 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2584 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2586 PLIGHTINFOEL *lightInfo = NULL;
2587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2589 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2590 TRACE("(%p) : for idx(%d)\n", This, Index);
2592 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2593 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2594 if(lightInfo->OriginalIndex == Index) break;
2598 if (lightInfo == NULL) {
2599 TRACE("Light enabled state requested but light not defined\n");
2600 return WINED3DERR_INVALIDCALL;
2602 /* true is 128 according to SetLightEnable */
2603 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2608 * Get / Set Clip Planes
2610 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2612 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2614 /* Validate Index */
2615 if (Index >= GL_LIMITS(clipplanes)) {
2616 TRACE("Application has requested clipplane this device doesn't support\n");
2617 return WINED3DERR_INVALIDCALL;
2620 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2621 This->updateStateBlock->set.clipplane[Index] = TRUE;
2623 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2624 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2625 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2626 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2627 TRACE("Application is setting old values over, nothing to do\n");
2631 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2632 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2633 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2634 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2636 /* Handle recording of state blocks */
2637 if (This->isRecordingState) {
2638 TRACE("Recording... not performing anything\n");
2642 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2647 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2649 TRACE("(%p) : for idx %d\n", This, Index);
2651 /* Validate Index */
2652 if (Index >= GL_LIMITS(clipplanes)) {
2653 TRACE("Application has requested clipplane this device doesn't support\n");
2654 return WINED3DERR_INVALIDCALL;
2657 pPlane[0] = This->stateBlock->clipplane[Index][0];
2658 pPlane[1] = This->stateBlock->clipplane[Index][1];
2659 pPlane[2] = This->stateBlock->clipplane[Index][2];
2660 pPlane[3] = This->stateBlock->clipplane[Index][3];
2665 * Get / Set Clip Plane Status
2666 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2668 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2670 FIXME("(%p) : stub\n", This);
2671 if (NULL == pClipStatus) {
2672 return WINED3DERR_INVALIDCALL;
2674 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2675 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2679 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2681 FIXME("(%p) : stub\n", This);
2682 if (NULL == pClipStatus) {
2683 return WINED3DERR_INVALIDCALL;
2685 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2686 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2691 * Get / Set Material
2693 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2696 This->updateStateBlock->changed.material = TRUE;
2697 This->updateStateBlock->set.material = TRUE;
2698 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2700 /* Handle recording of state blocks */
2701 if (This->isRecordingState) {
2702 TRACE("Recording... not performing anything\n");
2706 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2710 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2712 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2713 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2714 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2715 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2716 pMaterial->Ambient.b, pMaterial->Ambient.a);
2717 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2718 pMaterial->Specular.b, pMaterial->Specular.a);
2719 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2720 pMaterial->Emissive.b, pMaterial->Emissive.a);
2721 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2729 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2731 IWineD3DIndexBuffer *oldIdxs;
2733 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2734 oldIdxs = This->updateStateBlock->pIndexData;
2736 This->updateStateBlock->changed.indices = TRUE;
2737 This->updateStateBlock->set.indices = TRUE;
2738 This->updateStateBlock->pIndexData = pIndexData;
2740 /* Handle recording of state blocks */
2741 if (This->isRecordingState) {
2742 TRACE("Recording... not performing anything\n");
2746 if(oldIdxs != pIndexData) {
2747 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2752 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2755 *ppIndexData = This->stateBlock->pIndexData;
2757 /* up ref count on ppindexdata */
2759 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2760 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2762 TRACE("(%p) No index data set\n", This);
2764 TRACE("Returning %p\n", *ppIndexData);
2769 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2770 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2772 TRACE("(%p)->(%d)\n", This, BaseIndex);
2774 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2775 TRACE("Application is setting the old value over, nothing to do\n");
2779 This->updateStateBlock->baseVertexIndex = BaseIndex;
2781 if (This->isRecordingState) {
2782 TRACE("Recording... not performing anything\n");
2785 /* The base vertex index affects the stream sources */
2786 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2790 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) {
2791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2792 TRACE("(%p) : base_index %p\n", This, base_index);
2794 *base_index = This->stateBlock->baseVertexIndex;
2796 TRACE("Returning %u\n", *base_index);
2802 * Get / Set Viewports
2804 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2807 TRACE("(%p)\n", This);
2808 This->updateStateBlock->changed.viewport = TRUE;
2809 This->updateStateBlock->set.viewport = TRUE;
2810 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2812 /* Handle recording of state blocks */
2813 if (This->isRecordingState) {
2814 TRACE("Recording... not performing anything\n");
2818 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2819 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2821 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2826 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2828 TRACE("(%p)\n", This);
2829 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2834 * Get / Set Render States
2835 * TODO: Verify against dx9 definitions
2837 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2840 DWORD oldValue = This->stateBlock->renderState[State];
2842 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2844 This->updateStateBlock->changed.renderState[State] = TRUE;
2845 This->updateStateBlock->set.renderState[State] = TRUE;
2846 This->updateStateBlock->renderState[State] = Value;
2848 /* Handle recording of state blocks */
2849 if (This->isRecordingState) {
2850 TRACE("Recording... not performing anything\n");
2854 /* Compared here and not before the assignment to allow proper stateblock recording */
2855 if(Value == oldValue) {
2856 TRACE("Application is setting the old value over, nothing to do\n");
2858 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2864 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2866 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2867 *pValue = This->stateBlock->renderState[State];
2872 * Get / Set Sampler States
2873 * TODO: Verify against dx9 definitions
2876 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2878 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2881 * SetSampler is designed to allow for more than the standard up to 8 textures
2882 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2883 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2885 * http://developer.nvidia.com/object/General_FAQ.html#t6
2887 * There are two new settings for GForce
2889 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2890 * and the texture one:
2891 * GL_MAX_TEXTURE_COORDS_ARB.
2892 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2895 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2896 debug_d3dsamplerstate(Type), Type, Value);
2897 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2898 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2899 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2901 /* Handle recording of state blocks */
2902 if (This->isRecordingState) {
2903 TRACE("Recording... not performing anything\n");
2907 if(oldValue == Value) {
2908 TRACE("Application is setting the old value over, nothing to do\n");
2912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2917 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2919 *Value = This->stateBlock->samplerState[Sampler][Type];
2920 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2925 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2928 This->updateStateBlock->set.scissorRect = TRUE;
2929 This->updateStateBlock->changed.scissorRect = TRUE;
2930 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2931 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2934 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2936 if(This->isRecordingState) {
2937 TRACE("Recording... not performing anything\n");
2941 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2946 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2949 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2950 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2954 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2956 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2958 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2960 This->updateStateBlock->vertexDecl = pDecl;
2961 This->updateStateBlock->changed.vertexDecl = TRUE;
2962 This->updateStateBlock->set.vertexDecl = TRUE;
2964 if (This->isRecordingState) {
2965 TRACE("Recording... not performing anything\n");
2967 } else if(pDecl == oldDecl) {
2968 /* Checked after the assignment to allow proper stateblock recording */
2969 TRACE("Application is setting the old declaration over, nothing to do\n");
2973 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2977 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2980 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2982 *ppDecl = This->stateBlock->vertexDecl;
2983 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2987 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2989 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2991 This->updateStateBlock->vertexShader = pShader;
2992 This->updateStateBlock->changed.vertexShader = TRUE;
2993 This->updateStateBlock->set.vertexShader = TRUE;
2995 if (This->isRecordingState) {
2996 TRACE("Recording... not performing anything\n");
2998 } else if(oldShader == pShader) {
2999 /* Checked here to allow proper stateblock recording */
3000 TRACE("App is setting the old shader over, nothing to do\n");
3004 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3006 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3011 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3014 if (NULL == ppShader) {
3015 return WINED3DERR_INVALIDCALL;
3017 *ppShader = This->stateBlock->vertexShader;
3018 if( NULL != *ppShader)
3019 IWineD3DVertexShader_AddRef(*ppShader);
3021 TRACE("(%p) : returning %p\n", This, *ppShader);
3025 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3026 IWineD3DDevice *iface,
3028 CONST BOOL *srcData,
3031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3032 int i, cnt = min(count, MAX_CONST_B - start);
3034 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3035 iface, srcData, start, count);
3037 if (srcData == NULL || cnt < 0)
3038 return WINED3DERR_INVALIDCALL;
3040 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3041 for (i = 0; i < cnt; i++)
3042 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3044 for (i = start; i < cnt + start; ++i) {
3045 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3046 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3049 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3054 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3055 IWineD3DDevice *iface,
3060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3061 int cnt = min(count, MAX_CONST_B - start);
3063 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3064 iface, dstData, start, count);
3066 if (dstData == NULL || cnt < 0)
3067 return WINED3DERR_INVALIDCALL;
3069 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3073 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3074 IWineD3DDevice *iface,
3079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3080 int i, cnt = min(count, MAX_CONST_I - start);
3082 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3083 iface, srcData, start, count);
3085 if (srcData == NULL || cnt < 0)
3086 return WINED3DERR_INVALIDCALL;
3088 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3089 for (i = 0; i < cnt; i++)
3090 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3091 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3093 for (i = start; i < cnt + start; ++i) {
3094 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3095 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3098 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3103 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3104 IWineD3DDevice *iface,
3109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3110 int cnt = min(count, MAX_CONST_I - start);
3112 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3113 iface, dstData, start, count);
3115 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3116 return WINED3DERR_INVALIDCALL;
3118 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3122 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3123 IWineD3DDevice *iface,
3125 CONST float *srcData,
3128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3131 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3132 iface, srcData, start, count);
3134 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3135 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3136 return WINED3DERR_INVALIDCALL;
3138 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3140 for (i = 0; i < count; i++)
3141 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3142 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3145 for (i = start; i < count + start; ++i) {
3146 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3147 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3148 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3149 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3150 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3152 ptr->idx[ptr->count++] = i;
3153 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3155 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3158 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3163 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3164 IWineD3DDevice *iface,
3169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3170 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3172 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3173 iface, dstData, start, count);
3175 if (dstData == NULL || cnt < 0)
3176 return WINED3DERR_INVALIDCALL;
3178 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3182 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3184 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3185 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3189 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3190 int i = This->rev_tex_unit_map[unit];
3191 int j = This->texUnitMap[stage];
3193 This->texUnitMap[stage] = unit;
3194 if (i != -1 && i != stage) {
3195 This->texUnitMap[i] = -1;
3198 This->rev_tex_unit_map[unit] = stage;
3199 if (j != -1 && j != unit) {
3200 This->rev_tex_unit_map[j] = -1;
3204 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3207 for (i = 0; i < MAX_TEXTURES; ++i) {
3208 This->fixed_function_usage_map[i] = This->stateBlock->textures[i] ? TRUE : FALSE;
3212 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3215 device_update_fixed_function_usage_map(This);
3217 if (This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3218 for (i = 0; i < MAX_SAMPLERS; ++i) {
3219 if (This->texUnitMap[i] != i) {
3220 device_map_stage(This, i, i);
3221 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3222 if (i < MAX_TEXTURES) {
3223 markTextureStagesDirty(This, i);
3230 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3231 * First, see if we can succeed at all
3234 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3235 if (!This->fixed_function_usage_map[i]) ++tex;
3238 if (GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3239 FIXME("Too many bound textures to support the combiner settings\n");
3243 /* Now work out the mapping */
3245 This->oneToOneTexUnitMap = FALSE;
3246 WARN("Non 1:1 mapping UNTESTED!\n");
3247 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3248 /* Skip NULL textures */
3249 if (!This->fixed_function_usage_map[i]) {
3250 /* Map to -1, so the check below doesn't fail if a non-NULL
3251 * texture is set on this stage */
3252 TRACE("Mapping texture stage %d to -1\n", i);
3253 device_map_stage(This, i, -1);
3258 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3259 if (This->texUnitMap[i] != tex) {
3260 device_map_stage(This, i, tex);
3261 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3262 markTextureStagesDirty(This, i);
3269 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3272 for (i = 0; i < MAX_SAMPLERS; ++i) {
3273 if (This->texUnitMap[i] != i) {
3274 device_map_stage(This, i, i);
3275 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3276 if (i < MAX_TEXTURES) {
3277 markTextureStagesDirty(This, i);
3283 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3284 BOOL ps = use_ps(This);
3285 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3286 * it is never called.
3289 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3290 * that would be really messy and require shader recompilation
3291 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3292 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3295 device_map_psamplers(This);
3297 device_map_fixed_function_samplers(This);
3301 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3303 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3304 This->updateStateBlock->pixelShader = pShader;
3305 This->updateStateBlock->changed.pixelShader = TRUE;
3306 This->updateStateBlock->set.pixelShader = TRUE;
3308 /* Handle recording of state blocks */
3309 if (This->isRecordingState) {
3310 TRACE("Recording... not performing anything\n");
3313 if (This->isRecordingState) {
3314 TRACE("Recording... not performing anything\n");
3318 if(pShader == oldShader) {
3319 TRACE("App is setting the old pixel shader over, nothing to do\n");
3323 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3324 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3329 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3332 if (NULL == ppShader) {
3333 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3334 return WINED3DERR_INVALIDCALL;
3337 *ppShader = This->stateBlock->pixelShader;
3338 if (NULL != *ppShader) {
3339 IWineD3DPixelShader_AddRef(*ppShader);
3341 TRACE("(%p) : returning %p\n", This, *ppShader);
3345 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3346 IWineD3DDevice *iface,
3348 CONST BOOL *srcData,
3351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3352 int i, cnt = min(count, MAX_CONST_B - start);
3354 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3355 iface, srcData, start, count);
3357 if (srcData == NULL || cnt < 0)
3358 return WINED3DERR_INVALIDCALL;
3360 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3361 for (i = 0; i < cnt; i++)
3362 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3364 for (i = start; i < cnt + start; ++i) {
3365 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3366 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3369 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3374 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3375 IWineD3DDevice *iface,
3380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3381 int cnt = min(count, MAX_CONST_B - start);
3383 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3384 iface, dstData, start, count);
3386 if (dstData == NULL || cnt < 0)
3387 return WINED3DERR_INVALIDCALL;
3389 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3393 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3394 IWineD3DDevice *iface,
3399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3400 int i, cnt = min(count, MAX_CONST_I - start);
3402 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3403 iface, srcData, start, count);
3405 if (srcData == NULL || cnt < 0)
3406 return WINED3DERR_INVALIDCALL;
3408 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3409 for (i = 0; i < cnt; i++)
3410 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3411 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3413 for (i = start; i < cnt + start; ++i) {
3414 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3415 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3418 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3423 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3424 IWineD3DDevice *iface,
3429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3430 int cnt = min(count, MAX_CONST_I - start);
3432 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3433 iface, dstData, start, count);
3435 if (dstData == NULL || cnt < 0)
3436 return WINED3DERR_INVALIDCALL;
3438 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3442 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3443 IWineD3DDevice *iface,
3445 CONST float *srcData,
3448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3451 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3452 iface, srcData, start, count);
3454 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3455 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3456 return WINED3DERR_INVALIDCALL;
3458 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3460 for (i = 0; i < count; i++)
3461 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3462 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3465 for (i = start; i < count + start; ++i) {
3466 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3467 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3468 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3469 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3470 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3472 ptr->idx[ptr->count++] = i;
3473 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3475 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3478 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3483 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3484 IWineD3DDevice *iface,
3489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3490 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3492 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3493 iface, dstData, start, count);
3495 if (dstData == NULL || cnt < 0)
3496 return WINED3DERR_INVALIDCALL;
3498 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3502 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3504 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3505 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3507 DWORD DestFVF = dest->fvf;
3509 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3513 if (lpStrideData->u.s.normal.lpData) {
3514 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3517 if (lpStrideData->u.s.position.lpData == NULL) {
3518 ERR("Source has no position mask\n");
3519 return WINED3DERR_INVALIDCALL;
3522 /* We might access VBOs from this code, so hold the lock */
3525 if (dest->resource.allocatedMemory == NULL) {
3526 /* This may happen if we do direct locking into a vbo. Unlikely,
3527 * but theoretically possible(ddraw processvertices test)
3529 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3530 if(!dest->resource.allocatedMemory) {
3532 ERR("Out of memory\n");
3533 return E_OUTOFMEMORY;
3537 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3538 checkGLcall("glBindBufferARB");
3539 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3541 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3543 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3544 checkGLcall("glUnmapBufferARB");
3548 /* Get a pointer into the destination vbo(create one if none exists) and
3549 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3551 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3556 unsigned char extrabytes = 0;
3557 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3558 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3559 * this may write 4 extra bytes beyond the area that should be written
3561 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3562 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3563 if(!dest_conv_addr) {
3564 ERR("Out of memory\n");
3565 /* Continue without storing converted vertices */
3567 dest_conv = dest_conv_addr;
3571 * a) WINED3DRS_CLIPPING is enabled
3572 * b) WINED3DVOP_CLIP is passed
3574 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3575 static BOOL warned = FALSE;
3577 * The clipping code is not quite correct. Some things need
3578 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3579 * so disable clipping for now.
3580 * (The graphics in Half-Life are broken, and my processvertices
3581 * test crashes with IDirect3DDevice3)
3587 FIXME("Clipping is broken and disabled for now\n");
3589 } else doClip = FALSE;
3590 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3592 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3595 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3596 WINED3DTS_PROJECTION,
3598 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3599 WINED3DTS_WORLDMATRIX(0),
3602 TRACE("View mat:\n");
3603 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);
3604 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);
3605 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);
3606 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);
3608 TRACE("Proj mat:\n");
3609 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);
3610 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);
3611 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);
3612 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);
3614 TRACE("World mat:\n");
3615 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);
3616 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);
3617 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);
3618 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);
3620 /* Get the viewport */
3621 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3622 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3623 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3625 multiply_matrix(&mat,&view_mat,&world_mat);
3626 multiply_matrix(&mat,&proj_mat,&mat);
3628 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3630 for (i = 0; i < dwCount; i+= 1) {
3631 unsigned int tex_index;
3633 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3634 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3635 /* The position first */
3637 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3639 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3641 /* Multiplication with world, view and projection matrix */
3642 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);
3643 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);
3644 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);
3645 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);
3647 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3649 /* WARNING: The following things are taken from d3d7 and were not yet checked
3650 * against d3d8 or d3d9!
3653 /* Clipping conditions: From
3654 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3656 * A vertex is clipped if it does not match the following requirements
3660 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3662 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3663 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3668 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3669 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3672 /* "Normal" viewport transformation (not clipped)
3673 * 1) The values are divided by rhw
3674 * 2) The y axis is negative, so multiply it with -1
3675 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3676 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3677 * 4) Multiply x with Width/2 and add Width/2
3678 * 5) The same for the height
3679 * 6) Add the viewpoint X and Y to the 2D coordinates and
3680 * The minimum Z value to z
3681 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3683 * Well, basically it's simply a linear transformation into viewport
3695 z *= vp.MaxZ - vp.MinZ;
3697 x += vp.Width / 2 + vp.X;
3698 y += vp.Height / 2 + vp.Y;
3703 /* That vertex got clipped
3704 * Contrary to OpenGL it is not dropped completely, it just
3705 * undergoes a different calculation.
3707 TRACE("Vertex got clipped\n");
3714 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3715 * outside of the main vertex buffer memory. That needs some more
3720 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3723 ( (float *) dest_ptr)[0] = x;
3724 ( (float *) dest_ptr)[1] = y;
3725 ( (float *) dest_ptr)[2] = z;
3726 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3728 dest_ptr += 3 * sizeof(float);
3730 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3731 dest_ptr += sizeof(float);
3736 ( (float *) dest_conv)[0] = x * w;
3737 ( (float *) dest_conv)[1] = y * w;
3738 ( (float *) dest_conv)[2] = z * w;
3739 ( (float *) dest_conv)[3] = w;
3741 dest_conv += 3 * sizeof(float);
3743 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3744 dest_conv += sizeof(float);
3748 if (DestFVF & WINED3DFVF_PSIZE) {
3749 dest_ptr += sizeof(DWORD);
3750 if(dest_conv) dest_conv += sizeof(DWORD);
3752 if (DestFVF & WINED3DFVF_NORMAL) {
3754 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3755 /* AFAIK this should go into the lighting information */
3756 FIXME("Didn't expect the destination to have a normal\n");
3757 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3759 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3763 if (DestFVF & WINED3DFVF_DIFFUSE) {
3765 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3767 static BOOL warned = FALSE;
3770 ERR("No diffuse color in source, but destination has one\n");
3774 *( (DWORD *) dest_ptr) = 0xffffffff;
3775 dest_ptr += sizeof(DWORD);
3778 *( (DWORD *) dest_conv) = 0xffffffff;
3779 dest_conv += sizeof(DWORD);
3783 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3785 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3786 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3787 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3788 dest_conv += sizeof(DWORD);
3793 if (DestFVF & WINED3DFVF_SPECULAR) {
3794 /* What's the color value in the feedback buffer? */
3796 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3798 static BOOL warned = FALSE;
3801 ERR("No specular color in source, but destination has one\n");
3805 *( (DWORD *) dest_ptr) = 0xFF000000;
3806 dest_ptr += sizeof(DWORD);
3809 *( (DWORD *) dest_conv) = 0xFF000000;
3810 dest_conv += sizeof(DWORD);
3814 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3816 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3817 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3818 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3819 dest_conv += sizeof(DWORD);
3824 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3826 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3827 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3829 ERR("No source texture, but destination requests one\n");
3830 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3831 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3834 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3836 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3843 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3844 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3845 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3846 dwCount * get_flexible_vertex_size(DestFVF),
3848 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3849 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3856 #undef copy_and_next
3858 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3860 WineDirect3DVertexStridedData strided;
3861 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3862 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3865 ERR("Output vertex declaration not implemented yet\n");
3868 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3869 * and this call is quite performance critical, so don't call needlessly
3871 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3873 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3877 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3878 * control the streamIsUP flag, thus restore it afterwards.
3880 This->stateBlock->streamIsUP = FALSE;
3881 memset(&strided, 0, sizeof(strided));
3882 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
3883 This->stateBlock->streamIsUP = streamWasUP;
3885 if(vbo || SrcStartIndex) {
3887 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
3888 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
3890 * Also get the start index in, but only loop over all elements if there's something to add at all.
3892 #define FIXSRC(type) \
3893 if(strided.u.s.type.VBO) { \
3894 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
3895 strided.u.s.type.VBO = 0; \
3896 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
3898 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
3902 if(strided.u.s.type.lpData) { \
3903 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
3906 FIXSRC(blendWeights);
3907 FIXSRC(blendMatrixIndices);
3912 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
3913 FIXSRC(texCoords[i]);
3926 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3930 * Get / Set Texture Stage States
3931 * TODO: Verify against dx9 definitions
3933 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3935 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3937 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3939 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3941 if (Stage >= MAX_TEXTURES) {
3942 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
3946 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3947 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3948 This->updateStateBlock->textureState[Stage][Type] = Value;
3950 if (This->isRecordingState) {
3951 TRACE("Recording... not performing anything\n");
3955 /* Checked after the assignments to allow proper stateblock recording */
3956 if(oldValue == Value) {
3957 TRACE("App is setting the old value over, nothing to do\n");
3961 if(Stage > This->stateBlock->lowest_disabled_stage &&
3962 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3963 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3964 * Changes in other states are important on disabled stages too
3969 if(Type == WINED3DTSS_COLOROP) {
3972 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3973 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3974 * they have to be disabled
3976 * The current stage is dirtified below.
3978 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3979 TRACE("Additionally dirtifying stage %d\n", i);
3980 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3982 This->stateBlock->lowest_disabled_stage = Stage;
3983 TRACE("New lowest disabled: %d\n", Stage);
3984 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3985 /* Previously disabled stage enabled. Stages above it may need enabling
3986 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3987 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3989 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3992 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3993 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3996 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3997 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3999 This->stateBlock->lowest_disabled_stage = i;
4000 TRACE("New lowest disabled: %d\n", i);
4002 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4003 /* TODO: Built a stage -> texture unit mapping for register combiners */
4007 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4012 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4014 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4015 *pValue = This->updateStateBlock->textureState[Stage][Type];
4022 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4025 IWineD3DBaseTexture *oldTexture;
4027 oldTexture = This->updateStateBlock->textures[Stage];
4028 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4030 #if 0 /* TODO: check so vertex textures */
4031 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4032 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4037 if(pTexture != NULL) {
4038 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4040 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4041 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4042 return WINED3DERR_INVALIDCALL;
4044 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4047 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4048 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4050 This->updateStateBlock->set.textures[Stage] = TRUE;
4051 This->updateStateBlock->changed.textures[Stage] = TRUE;
4052 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4053 This->updateStateBlock->textures[Stage] = pTexture;
4055 /* Handle recording of state blocks */
4056 if (This->isRecordingState) {
4057 TRACE("Recording... not performing anything\n");
4061 if(oldTexture == pTexture) {
4062 TRACE("App is setting the same texture again, nothing to do\n");
4066 /** NOTE: MSDN says that setTexture increases the reference count,
4067 * and the the application must set the texture back to null (or have a leaky application),
4068 * This means we should pass the refcount up to the parent
4069 *******************************/
4070 if (NULL != This->updateStateBlock->textures[Stage]) {
4071 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4072 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4074 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4075 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4076 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4077 * so the COLOROP and ALPHAOP have to be dirtified.
4079 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4080 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4082 if(bindCount == 1) {
4083 new->baseTexture.sampler = Stage;
4085 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4089 if (NULL != oldTexture) {
4090 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4091 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4093 IWineD3DBaseTexture_Release(oldTexture);
4094 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4095 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4096 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4099 if(bindCount && old->baseTexture.sampler == Stage) {
4101 /* Have to do a search for the other sampler(s) where the texture is bound to
4102 * Shouldn't happen as long as apps bind a texture only to one stage
4104 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4105 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
4106 if(This->updateStateBlock->textures[i] == oldTexture) {
4107 old->baseTexture.sampler = i;
4114 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4119 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4121 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4123 *ppTexture=This->stateBlock->textures[Stage];
4125 IWineD3DBaseTexture_AddRef(*ppTexture);
4133 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4134 IWineD3DSurface **ppBackBuffer) {
4135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4136 IWineD3DSwapChain *swapChain;
4139 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4141 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4142 if (hr == WINED3D_OK) {
4143 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4144 IWineD3DSwapChain_Release(swapChain);
4146 *ppBackBuffer = NULL;
4151 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4153 WARN("(%p) : stub, calling idirect3d for now\n", This);
4154 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4157 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4159 IWineD3DSwapChain *swapChain;
4162 if(iSwapChain > 0) {
4163 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4164 if (hr == WINED3D_OK) {
4165 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4166 IWineD3DSwapChain_Release(swapChain);
4168 FIXME("(%p) Error getting display mode\n", This);
4171 /* Don't read the real display mode,
4172 but return the stored mode instead. X11 can't change the color
4173 depth, and some apps are pretty angry if they SetDisplayMode from
4174 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4176 Also don't relay to the swapchain because with ddraw it's possible
4177 that there isn't a swapchain at all */
4178 pMode->Width = This->ddraw_width;
4179 pMode->Height = This->ddraw_height;
4180 pMode->Format = This->ddraw_format;
4181 pMode->RefreshRate = 0;
4188 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4190 TRACE("(%p)->(%p)\n", This, hWnd);
4192 if(This->ddraw_fullscreen) {
4193 if(This->ddraw_window && This->ddraw_window != hWnd) {
4194 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4196 if(hWnd && This->ddraw_window != hWnd) {
4197 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4201 This->ddraw_window = hWnd;
4205 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4207 TRACE("(%p)->(%p)\n", This, hWnd);
4209 *hWnd = This->ddraw_window;
4214 * Stateblock related functions
4217 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4219 IWineD3DStateBlockImpl *object;
4220 HRESULT temp_result;
4223 TRACE("(%p)\n", This);
4225 if (This->isRecordingState) {
4226 return WINED3DERR_INVALIDCALL;
4229 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4230 if (NULL == object ) {
4231 FIXME("(%p)Error allocating memory for stateblock\n", This);
4232 return E_OUTOFMEMORY;
4234 TRACE("(%p) created object %p\n", This, object);
4235 object->wineD3DDevice= This;
4236 /** FIXME: object->parent = parent; **/
4237 object->parent = NULL;
4238 object->blockType = WINED3DSBT_ALL;
4240 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4242 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4243 list_init(&object->lightMap[i]);
4246 temp_result = allocate_shader_constants(object);
4247 if (WINED3D_OK != temp_result)
4250 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4251 This->updateStateBlock = object;
4252 This->isRecordingState = TRUE;
4254 TRACE("(%p) recording stateblock %p\n",This , object);
4258 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4261 if (!This->isRecordingState) {
4262 FIXME("(%p) not recording! returning error\n", This);
4263 *ppStateBlock = NULL;
4264 return WINED3DERR_INVALIDCALL;
4267 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4268 This->isRecordingState = FALSE;
4269 This->updateStateBlock = This->stateBlock;
4270 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4271 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4272 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4277 * Scene related functions
4279 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4280 /* At the moment we have no need for any functionality at the beginning
4282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4283 TRACE("(%p)\n", This);
4286 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4287 return WINED3DERR_INVALIDCALL;
4289 This->inScene = TRUE;
4293 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4295 TRACE("(%p)\n", This);
4297 if(!This->inScene) {
4298 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4299 return WINED3DERR_INVALIDCALL;
4303 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4304 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4306 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4308 checkGLcall("glFlush");
4311 This->inScene = FALSE;
4315 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4316 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4317 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4319 IWineD3DSwapChain *swapChain = NULL;
4321 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4323 TRACE("(%p) Presenting the frame\n", This);
4325 for(i = 0 ; i < swapchains ; i ++) {
4327 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4328 TRACE("presentinng chain %d, %p\n", i, swapChain);
4329 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4330 IWineD3DSwapChain_Release(swapChain);
4336 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4337 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4339 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4341 GLbitfield glMask = 0;
4343 CONST WINED3DRECT* curRect;
4345 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4346 Count, pRects, Flags, Color, Z, Stencil);
4348 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4349 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4350 /* TODO: What about depth stencil buffers without stencil bits? */
4351 return WINED3DERR_INVALIDCALL;
4355 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4356 * and not the last active one.
4359 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4360 apply_fbo_state(iface);
4363 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
4365 glEnable(GL_SCISSOR_TEST);
4366 checkGLcall("glEnable GL_SCISSOR_TEST");
4367 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4368 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4370 if (Count > 0 && pRects) {
4376 /* Only set the values up once, as they are not changing */
4377 if (Flags & WINED3DCLEAR_STENCIL) {
4378 glClearStencil(Stencil);
4379 checkGLcall("glClearStencil");
4380 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4381 glStencilMask(0xFFFFFFFF);
4384 if (Flags & WINED3DCLEAR_ZBUFFER) {
4385 glDepthMask(GL_TRUE);
4387 checkGLcall("glClearDepth");
4388 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4389 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4392 if (Flags & WINED3DCLEAR_TARGET) {
4393 TRACE("Clearing screen with glClear to color %x\n", Color);
4394 glClearColor(D3DCOLOR_R(Color),
4398 checkGLcall("glClearColor");
4400 /* Clear ALL colors! */
4401 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4402 glMask = glMask | GL_COLOR_BUFFER_BIT;
4406 /* In drawable flag is set below */
4408 glScissor(This->stateBlock->viewport.X,
4409 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4410 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4411 This->stateBlock->viewport.Width,
4412 This->stateBlock->viewport.Height);
4413 checkGLcall("glScissor");
4415 checkGLcall("glClear");
4417 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4418 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4420 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4421 curRect[0].x2 < target->currentDesc.Width ||
4422 curRect[0].y2 < target->currentDesc.Height) {
4423 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4424 blt_to_drawable(This, target);
4428 /* Now process each rect in turn */
4429 for (i = 0; i < Count; i++) {
4430 /* Note gl uses lower left, width/height */
4431 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4432 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4433 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4434 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4436 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4437 * The rectangle is not cleared, no error is returned, but further rectanlges are
4438 * still cleared if they are valid
4440 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4441 TRACE("Rectangle with negative dimensions, ignoring\n");
4445 if(This->render_offscreen) {
4446 glScissor(curRect[i].x1, curRect[i].y1,
4447 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4449 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4450 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4452 checkGLcall("glScissor");
4455 checkGLcall("glClear");
4459 /* Restore the old values (why..?) */
4460 if (Flags & WINED3DCLEAR_STENCIL) {
4461 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4463 if (Flags & WINED3DCLEAR_TARGET) {
4464 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4465 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4466 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4467 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4468 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4473 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4474 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4476 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4477 target->Flags |= SFLAG_INTEXTURE;
4478 target->Flags &= ~SFLAG_INSYSMEM;
4480 target->Flags |= SFLAG_INDRAWABLE;
4481 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4489 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4490 UINT PrimitiveCount) {
4492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4494 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4495 debug_d3dprimitivetype(PrimitiveType),
4496 StartVertex, PrimitiveCount);
4498 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4499 if(This->stateBlock->streamIsUP) {
4500 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4501 This->stateBlock->streamIsUP = FALSE;
4504 if(This->stateBlock->loadBaseVertexIndex != 0) {
4505 This->stateBlock->loadBaseVertexIndex = 0;
4506 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4508 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4509 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4510 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4514 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4515 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4516 WINED3DPRIMITIVETYPE PrimitiveType,
4517 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4521 IWineD3DIndexBuffer *pIB;
4522 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4525 pIB = This->stateBlock->pIndexData;
4527 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4528 * without an index buffer set. (The first time at least...)
4529 * D3D8 simply dies, but I doubt it can do much harm to return
4530 * D3DERR_INVALIDCALL there as well. */
4531 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4532 return WINED3DERR_INVALIDCALL;
4535 if(This->stateBlock->streamIsUP) {
4536 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4537 This->stateBlock->streamIsUP = FALSE;
4539 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4541 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4542 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4543 minIndex, NumVertices, startIndex, primCount);
4545 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4546 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4552 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4553 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4554 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4557 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4558 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4563 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4564 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4565 UINT VertexStreamZeroStride) {
4566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4568 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4569 debug_d3dprimitivetype(PrimitiveType),
4570 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4572 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4573 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4574 This->stateBlock->streamOffset[0] = 0;
4575 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4576 This->stateBlock->streamIsUP = TRUE;
4577 This->stateBlock->loadBaseVertexIndex = 0;
4579 /* TODO: Only mark dirty if drawing from a different UP address */
4580 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4582 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4583 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4585 /* MSDN specifies stream zero settings must be set to NULL */
4586 This->stateBlock->streamStride[0] = 0;
4587 This->stateBlock->streamSource[0] = NULL;
4589 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4590 * the new stream sources or use UP drawing again
4595 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4596 UINT MinVertexIndex, UINT NumVertices,
4597 UINT PrimitiveCount, CONST void* pIndexData,
4598 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4599 UINT VertexStreamZeroStride) {
4601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4603 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4604 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4605 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4606 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4608 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4614 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4615 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4616 This->stateBlock->streamIsUP = TRUE;
4617 This->stateBlock->streamOffset[0] = 0;
4618 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4620 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4621 This->stateBlock->baseVertexIndex = 0;
4622 This->stateBlock->loadBaseVertexIndex = 0;
4623 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4624 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4625 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4627 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4629 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4630 This->stateBlock->streamSource[0] = NULL;
4631 This->stateBlock->streamStride[0] = 0;
4632 This->stateBlock->pIndexData = NULL;
4633 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4634 * SetStreamSource to specify a vertex buffer
4640 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4643 /* Mark the state dirty until we have nicer tracking
4644 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4647 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4648 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4649 This->stateBlock->baseVertexIndex = 0;
4650 This->up_strided = DrawPrimStrideData;
4651 This->stateBlock->streamIsUP = TRUE;
4652 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4653 This->up_strided = NULL;
4656 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4657 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4659 HRESULT hr = WINED3D_OK;
4660 WINED3DRESOURCETYPE sourceType;
4661 WINED3DRESOURCETYPE destinationType;
4664 /* TODO: think about moving the code into IWineD3DBaseTexture */
4666 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4668 /* verify that the source and destination textures aren't NULL */
4669 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4670 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4671 This, pSourceTexture, pDestinationTexture);
4672 hr = WINED3DERR_INVALIDCALL;
4675 if (pSourceTexture == pDestinationTexture) {
4676 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4677 This, pSourceTexture, pDestinationTexture);
4678 hr = WINED3DERR_INVALIDCALL;
4680 /* Verify that the source and destination textures are the same type */
4681 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4682 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4684 if (sourceType != destinationType) {
4685 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4687 hr = WINED3DERR_INVALIDCALL;
4690 /* check that both textures have the identical numbers of levels */
4691 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4692 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4693 hr = WINED3DERR_INVALIDCALL;
4696 if (WINED3D_OK == hr) {
4698 /* Make sure that the destination texture is loaded */
4699 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4701 /* Update every surface level of the texture */
4702 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4704 switch (sourceType) {
4705 case WINED3DRTYPE_TEXTURE:
4707 IWineD3DSurface *srcSurface;
4708 IWineD3DSurface *destSurface;
4710 for (i = 0 ; i < levels ; ++i) {
4711 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4712 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4713 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4714 IWineD3DSurface_Release(srcSurface);
4715 IWineD3DSurface_Release(destSurface);
4716 if (WINED3D_OK != hr) {
4717 WARN("(%p) : Call to update surface failed\n", This);
4723 case WINED3DRTYPE_CUBETEXTURE:
4725 IWineD3DSurface *srcSurface;
4726 IWineD3DSurface *destSurface;
4727 WINED3DCUBEMAP_FACES faceType;
4729 for (i = 0 ; i < levels ; ++i) {
4730 /* Update each cube face */
4731 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4732 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4733 if (WINED3D_OK != hr) {
4734 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4736 TRACE("Got srcSurface %p\n", srcSurface);
4738 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4739 if (WINED3D_OK != hr) {
4740 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4742 TRACE("Got desrSurface %p\n", destSurface);
4744 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4745 IWineD3DSurface_Release(srcSurface);
4746 IWineD3DSurface_Release(destSurface);
4747 if (WINED3D_OK != hr) {
4748 WARN("(%p) : Call to update surface failed\n", This);
4755 #if 0 /* TODO: Add support for volume textures */
4756 case WINED3DRTYPE_VOLUMETEXTURE:
4758 IWineD3DVolume srcVolume = NULL;
4759 IWineD3DSurface destVolume = NULL;
4761 for (i = 0 ; i < levels ; ++i) {
4762 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4763 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4764 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4765 IWineD3DVolume_Release(srcSurface);
4766 IWineD3DVolume_Release(destSurface);
4767 if (WINED3D_OK != hr) {
4768 WARN("(%p) : Call to update volume failed\n", This);
4776 FIXME("(%p) : Unsupported source and destination type\n", This);
4777 hr = WINED3DERR_INVALIDCALL;
4784 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4785 IWineD3DSwapChain *swapChain;
4787 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4788 if(hr == WINED3D_OK) {
4789 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4790 IWineD3DSwapChain_Release(swapChain);
4795 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4797 /* return a sensible default */
4799 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4800 FIXME("(%p) : stub\n", This);
4804 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4807 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4808 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4809 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4810 return WINED3DERR_INVALIDCALL;
4812 for (j = 0; j < 256; ++j) {
4813 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4814 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4815 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4816 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4818 TRACE("(%p) : returning\n", This);
4822 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4825 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4826 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4827 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4828 return WINED3DERR_INVALIDCALL;
4830 for (j = 0; j < 256; ++j) {
4831 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4832 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4833 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4834 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4836 TRACE("(%p) : returning\n", This);
4840 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4842 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4843 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4844 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4845 return WINED3DERR_INVALIDCALL;
4847 /*TODO: stateblocks */
4848 This->currentPalette = PaletteNumber;
4849 TRACE("(%p) : returning\n", This);
4853 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4854 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4855 if (PaletteNumber == NULL) {
4856 WARN("(%p) : returning Invalid Call\n", This);
4857 return WINED3DERR_INVALIDCALL;
4859 /*TODO: stateblocks */
4860 *PaletteNumber = This->currentPalette;
4861 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4865 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4867 static BOOL showFixmes = TRUE;
4869 FIXME("(%p) : stub\n", This);
4873 This->softwareVertexProcessing = bSoftware;
4878 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4880 static BOOL showFixmes = TRUE;
4882 FIXME("(%p) : stub\n", This);
4885 return This->softwareVertexProcessing;
4889 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4891 IWineD3DSwapChain *swapChain;
4894 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4896 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4897 if(hr == WINED3D_OK){
4898 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4899 IWineD3DSwapChain_Release(swapChain);
4901 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4907 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4909 static BOOL showfixmes = TRUE;
4910 if(nSegments != 0.0f) {
4912 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4919 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4920 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4921 static BOOL showfixmes = TRUE;
4923 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4929 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4931 /** TODO: remove casts to IWineD3DSurfaceImpl
4932 * NOTE: move code to surface to accomplish this
4933 ****************************************/
4934 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4935 int srcWidth, srcHeight;
4936 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4937 WINED3DFORMAT destFormat, srcFormat;
4939 int srcLeft, destLeft, destTop;
4940 WINED3DPOOL srcPool, destPool;
4942 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4943 glDescriptor *glDescription = NULL;
4945 WINED3DSURFACE_DESC winedesc;
4947 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4948 memset(&winedesc, 0, sizeof(winedesc));
4949 winedesc.Width = &srcSurfaceWidth;
4950 winedesc.Height = &srcSurfaceHeight;
4951 winedesc.Pool = &srcPool;
4952 winedesc.Format = &srcFormat;
4954 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4956 winedesc.Width = &destSurfaceWidth;
4957 winedesc.Height = &destSurfaceHeight;
4958 winedesc.Pool = &destPool;
4959 winedesc.Format = &destFormat;
4960 winedesc.Size = &destSize;
4962 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4964 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4965 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4966 return WINED3DERR_INVALIDCALL;
4969 if (destFormat == WINED3DFMT_UNKNOWN) {
4970 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4971 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4973 /* Get the update surface description */
4974 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4979 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4981 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
4982 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4983 checkGLcall("glActiveTextureARB");
4986 /* Make sure the surface is loaded and up to date */
4987 IWineD3DSurface_PreLoad(pDestinationSurface);
4989 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4991 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4992 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4993 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
4994 srcLeft = pSourceRect ? pSourceRect->left : 0;
4995 destLeft = pDestPoint ? pDestPoint->x : 0;
4996 destTop = pDestPoint ? pDestPoint->y : 0;
4999 /* This function doesn't support compressed textures
5000 the pitch is just bytesPerPixel * width */
5001 if(srcWidth != srcSurfaceWidth || srcLeft ){
5002 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5003 offset += srcLeft * pSrcSurface->bytesPerPixel;
5004 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5006 /* TODO DXT formats */
5008 if(pSourceRect != NULL && pSourceRect->top != 0){
5009 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5011 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5013 ,glDescription->level
5018 ,glDescription->glFormat
5019 ,glDescription->glType
5020 ,IWineD3DSurface_GetData(pSourceSurface)
5024 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5026 /* need to lock the surface to get the data */
5027 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5030 /* TODO: Cube and volume support */
5032 /* not a whole row so we have to do it a line at a time */
5035 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5036 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5038 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5040 glTexSubImage2D(glDescription->target
5041 ,glDescription->level
5046 ,glDescription->glFormat
5047 ,glDescription->glType
5048 ,data /* could be quicker using */
5053 } else { /* Full width, so just write out the whole texture */
5055 if (WINED3DFMT_DXT1 == destFormat ||
5056 WINED3DFMT_DXT2 == destFormat ||
5057 WINED3DFMT_DXT3 == destFormat ||
5058 WINED3DFMT_DXT4 == destFormat ||
5059 WINED3DFMT_DXT5 == destFormat) {
5060 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5061 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5062 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5063 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5064 } if (destFormat != srcFormat) {
5065 FIXME("Updating mixed format compressed texture is not curretly support\n");
5067 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5068 glDescription->level,
5069 glDescription->glFormatInternal,
5074 IWineD3DSurface_GetData(pSourceSurface));
5077 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5082 glTexSubImage2D(glDescription->target
5083 ,glDescription->level
5088 ,glDescription->glFormat
5089 ,glDescription->glType
5090 ,IWineD3DSurface_GetData(pSourceSurface)
5094 checkGLcall("glTexSubImage2D");
5098 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5099 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5100 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5105 /* Implementation details at http://developer.nvidia.com/attach/6494
5107 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5108 hmm.. no longer supported use
5109 OpenGL evaluators or tessellate surfaces within your application.
5112 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5113 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5114 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5115 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5116 FIXME("(%p) : Stub\n", This);
5121 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5122 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5124 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5125 FIXME("(%p) : Stub\n", This);
5129 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5131 TRACE("(%p) Handle(%d)\n", This, Handle);
5132 FIXME("(%p) : Stub\n", This);
5136 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5138 IWineD3DSwapChain *swapchain;
5140 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5141 if (SUCCEEDED(hr)) {
5142 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5149 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5153 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5154 checkGLcall("glGenFramebuffersEXT()");
5156 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5157 checkGLcall("glBindFramebuffer()");
5160 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5161 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5162 IWineD3DBaseTextureImpl *texture_impl;
5163 GLenum texttarget, target;
5166 texttarget = surface_impl->glDescription.target;
5167 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5168 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5170 IWineD3DSurface_PreLoad(surface);
5172 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5173 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5174 glBindTexture(target, old_binding);
5176 /* Update base texture states array */
5177 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5178 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5179 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5180 if (texture_impl->baseTexture.bindCount) {
5181 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5184 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5187 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5189 checkGLcall("attach_surface_fbo");
5192 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5194 IWineD3DSwapChain *swapchain;
5196 swapchain = get_swapchain(surface);
5200 TRACE("Surface %p is onscreen\n", surface);
5202 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5203 buffer = surface_get_gl_buffer(surface, swapchain);
5204 glDrawBuffer(buffer);
5205 checkGLcall("glDrawBuffer()");
5207 TRACE("Surface %p is offscreen\n", surface);
5208 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5209 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5213 glEnable(GL_SCISSOR_TEST);
5215 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5217 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5218 rect->x2 - rect->x1, rect->y2 - rect->y1);
5220 checkGLcall("glScissor");
5222 glDisable(GL_SCISSOR_TEST);
5224 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5226 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5227 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5229 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5230 glClear(GL_COLOR_BUFFER_BIT);
5231 checkGLcall("glClear");
5233 if (This->render_offscreen) {
5234 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5236 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5237 checkGLcall("glBindFramebuffer()");
5240 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5241 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5242 glDrawBuffer(GL_BACK);
5243 checkGLcall("glDrawBuffer()");
5247 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5249 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5251 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5253 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5254 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5255 return WINED3DERR_INVALIDCALL;
5258 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5259 color_fill_fbo(iface, pSurface, pRect, color);
5262 /* Just forward this to the DirectDraw blitting engine */
5263 memset(&BltFx, 0, sizeof(BltFx));
5264 BltFx.dwSize = sizeof(BltFx);
5265 BltFx.u5.dwFillColor = color;
5266 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5270 /* rendertarget and deptth stencil functions */
5271 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5274 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5275 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5276 return WINED3DERR_INVALIDCALL;
5279 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5280 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5281 /* Note inc ref on returned surface */
5282 if(*ppRenderTarget != NULL)
5283 IWineD3DSurface_AddRef(*ppRenderTarget);
5287 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5289 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5290 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5291 IWineD3DSwapChainImpl *Swapchain;
5294 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5296 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5297 if(hr != WINED3D_OK) {
5298 ERR("Can't get the swapchain\n");
5302 /* Make sure to release the swapchain */
5303 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5305 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5306 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5307 return WINED3DERR_INVALIDCALL;
5309 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5310 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5311 return WINED3DERR_INVALIDCALL;
5314 if(Swapchain->frontBuffer != Front) {
5315 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5317 if(Swapchain->frontBuffer)
5318 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5319 Swapchain->frontBuffer = Front;
5321 if(Swapchain->frontBuffer) {
5322 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5326 if(Back && !Swapchain->backBuffer) {
5327 /* We need memory for the back buffer array - only one back buffer this way */
5328 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5329 if(!Swapchain->backBuffer) {
5330 ERR("Out of memory\n");
5331 return E_OUTOFMEMORY;
5335 if(Swapchain->backBuffer[0] != Back) {
5336 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5338 /* What to do about the context here in the case of multithreading? Not sure.
5339 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5342 if(!Swapchain->backBuffer[0]) {
5343 /* GL was told to draw to the front buffer at creation,
5346 glDrawBuffer(GL_BACK);
5347 checkGLcall("glDrawBuffer(GL_BACK)");
5348 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5349 Swapchain->presentParms.BackBufferCount = 1;
5351 /* That makes problems - disable for now */
5352 /* glDrawBuffer(GL_FRONT); */
5353 checkGLcall("glDrawBuffer(GL_FRONT)");
5354 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5355 Swapchain->presentParms.BackBufferCount = 0;
5359 if(Swapchain->backBuffer[0])
5360 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5361 Swapchain->backBuffer[0] = Back;
5363 if(Swapchain->backBuffer[0]) {
5364 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5366 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5374 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5376 *ppZStencilSurface = This->depthStencilBuffer;
5377 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5379 if(*ppZStencilSurface != NULL) {
5380 /* Note inc ref on returned surface */
5381 IWineD3DSurface_AddRef(*ppZStencilSurface);
5386 /* TODO: Handle stencil attachments */
5387 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5389 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5391 TRACE("Set depth stencil to %p\n", depth_stencil);
5393 if (depth_stencil_impl) {
5394 if (depth_stencil_impl->current_renderbuffer) {
5395 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5396 checkGLcall("glFramebufferRenderbufferEXT()");
5398 IWineD3DBaseTextureImpl *texture_impl;
5399 GLenum texttarget, target;
5400 GLint old_binding = 0;
5402 texttarget = depth_stencil_impl->glDescription.target;
5403 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5404 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5406 IWineD3DSurface_PreLoad(depth_stencil);
5408 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5409 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5410 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5411 glBindTexture(target, old_binding);
5413 /* Update base texture states array */
5414 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5415 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5416 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5417 if (texture_impl->baseTexture.bindCount) {
5418 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5421 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5424 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5425 checkGLcall("glFramebufferTexture2DEXT()");
5428 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5429 checkGLcall("glFramebufferTexture2DEXT()");
5433 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5435 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5437 TRACE("Set render target %u to %p\n", idx, render_target);
5440 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5441 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5443 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5444 checkGLcall("glFramebufferTexture2DEXT()");
5446 This->draw_buffers[idx] = GL_NONE;
5450 static void check_fbo_status(IWineD3DDevice *iface) {
5451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5454 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5455 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5456 TRACE("FBO complete\n");
5458 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5460 /* Dump the FBO attachments */
5461 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5462 IWineD3DSurfaceImpl *attachment;
5465 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5466 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5468 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5469 attachment->pow2Width, attachment->pow2Height);
5472 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5474 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5475 attachment->pow2Width, attachment->pow2Height);
5481 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5483 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5484 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5486 if (!ds_impl) return FALSE;
5488 if (ds_impl->current_renderbuffer) {
5489 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5490 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5493 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5494 rt_impl->pow2Height != ds_impl->pow2Height);
5497 void apply_fbo_state(IWineD3DDevice *iface) {
5498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5501 if (This->render_offscreen) {
5502 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5504 /* Apply render targets */
5505 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5506 IWineD3DSurface *render_target = This->render_targets[i];
5507 if (This->fbo_color_attachments[i] != render_target) {
5508 set_render_target_fbo(iface, i, render_target);
5509 This->fbo_color_attachments[i] = render_target;
5513 /* Apply depth targets */
5514 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5515 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5516 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5518 if (This->stencilBufferTarget) {
5519 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5521 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5522 This->fbo_depth_attachment = This->stencilBufferTarget;
5525 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5526 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5527 checkGLcall("glDrawBuffers()");
5529 glDrawBuffer(This->draw_buffers[0]);
5530 checkGLcall("glDrawBuffer()");
5533 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5536 check_fbo_status(iface);
5539 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5540 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5542 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5543 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5546 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5547 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5548 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5549 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5552 case WINED3DTEXF_LINEAR:
5553 gl_filter = GL_LINEAR;
5557 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5558 case WINED3DTEXF_NONE:
5559 case WINED3DTEXF_POINT:
5560 gl_filter = GL_NEAREST;
5564 /* Attach src surface to src fbo */
5565 src_swapchain = get_swapchain(src_surface);
5567 if (src_swapchain) {
5570 TRACE("Source surface %p is onscreen\n", src_surface);
5571 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5573 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5574 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5575 glReadBuffer(buffer);
5576 checkGLcall("glReadBuffer()");
5578 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5579 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5581 TRACE("Source surface %p is offscreen\n", src_surface);
5582 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5583 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5584 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5585 checkGLcall("glReadBuffer()");
5588 /* Attach dst surface to dst fbo */
5589 dst_swapchain = get_swapchain(dst_surface);
5590 if (dst_swapchain) {
5593 TRACE("Destination surface %p is onscreen\n", dst_surface);
5594 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5596 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5597 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5598 glDrawBuffer(buffer);
5599 checkGLcall("glDrawBuffer()");
5601 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5602 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5604 TRACE("Destination surface %p is offscreen\n", dst_surface);
5606 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5607 if(!src_swapchain) {
5608 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5611 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5612 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5613 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5614 checkGLcall("glDrawBuffer()");
5616 glDisable(GL_SCISSOR_TEST);
5617 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5620 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5621 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5622 checkGLcall("glBlitFramebuffer()");
5624 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5625 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5626 checkGLcall("glBlitFramebuffer()");
5629 if (This->render_offscreen) {
5630 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5632 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5633 checkGLcall("glBindFramebuffer()");
5636 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5637 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5638 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5639 glDrawBuffer(GL_BACK);
5640 checkGLcall("glDrawBuffer()");
5645 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5647 WINED3DVIEWPORT viewport;
5649 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5651 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5652 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5653 return WINED3DERR_INVALIDCALL;
5656 /* MSDN says that null disables the render target
5657 but a device must always be associated with a render target
5658 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5660 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5663 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5664 FIXME("Trying to set render target 0 to NULL\n");
5665 return WINED3DERR_INVALIDCALL;
5667 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5668 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);
5669 return WINED3DERR_INVALIDCALL;
5672 /* If we are trying to set what we already have, don't bother */
5673 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5674 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5677 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5678 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5679 This->render_targets[RenderTargetIndex] = pRenderTarget;
5681 /* Render target 0 is special */
5682 if(RenderTargetIndex == 0) {
5683 /* Finally, reset the viewport as the MSDN states. */
5684 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5685 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5688 viewport.MaxZ = 1.0f;
5689 viewport.MinZ = 0.0f;
5690 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5691 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5692 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5694 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5696 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5698 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5699 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5701 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5706 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5708 HRESULT hr = WINED3D_OK;
5709 IWineD3DSurface *tmp;
5711 TRACE("(%p) Swapping z-buffer\n",This);
5713 if (pNewZStencil == This->stencilBufferTarget) {
5714 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5716 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5717 * depending on the renter target implementation being used.
5718 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5719 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5720 * stencil buffer and incure an extra memory overhead
5721 ******************************************************/
5723 tmp = This->stencilBufferTarget;
5724 This->stencilBufferTarget = pNewZStencil;
5725 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5726 /* should we be calling the parent or the wined3d surface? */
5727 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5728 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5731 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5732 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5733 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5734 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5735 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5742 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5743 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5745 /* TODO: the use of Impl is deprecated. */
5746 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5747 WINED3DLOCKED_RECT lockedRect;
5749 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5751 /* some basic validation checks */
5752 if(This->cursorTexture) {
5754 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5755 glDeleteTextures(1, &This->cursorTexture);
5757 This->cursorTexture = 0;
5760 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5761 This->haveHardwareCursor = TRUE;
5763 This->haveHardwareCursor = FALSE;
5766 WINED3DLOCKED_RECT rect;
5768 /* MSDN: Cursor must be A8R8G8B8 */
5769 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5770 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5771 return WINED3DERR_INVALIDCALL;
5774 /* MSDN: Cursor must be smaller than the display mode */
5775 if(pSur->currentDesc.Width > This->ddraw_width ||
5776 pSur->currentDesc.Height > This->ddraw_height) {
5777 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);
5778 return WINED3DERR_INVALIDCALL;
5781 if (!This->haveHardwareCursor) {
5782 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5784 /* Do not store the surface's pointer because the application may
5785 * release it after setting the cursor image. Windows doesn't
5786 * addref the set surface, so we can't do this either without
5787 * creating circular refcount dependencies. Copy out the gl texture
5790 This->cursorWidth = pSur->currentDesc.Width;
5791 This->cursorHeight = pSur->currentDesc.Height;
5792 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5794 const PixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8);
5795 char *mem, *bits = (char *)rect.pBits;
5796 GLint intfmt = tableEntry->glInternal;
5797 GLint format = tableEntry->glFormat;
5798 GLint type = tableEntry->glType;
5799 INT height = This->cursorHeight;
5800 INT width = This->cursorWidth;
5801 INT bpp = tableEntry->bpp;
5804 /* Reformat the texture memory (pitch and width can be
5806 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5807 for(i = 0; i < height; i++)
5808 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5809 IWineD3DSurface_UnlockRect(pCursorBitmap);
5812 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5813 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5814 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5817 /* Make sure that a proper texture unit is selected */
5818 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5819 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5820 checkGLcall("glActiveTextureARB");
5822 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5823 /* Create a new cursor texture */
5824 glGenTextures(1, &This->cursorTexture);
5825 checkGLcall("glGenTextures");
5826 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5827 checkGLcall("glBindTexture");
5828 /* Copy the bitmap memory into the cursor texture */
5829 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5830 HeapFree(GetProcessHeap(), 0, mem);
5831 checkGLcall("glTexImage2D");
5833 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5834 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5835 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5842 FIXME("A cursor texture was not returned.\n");
5843 This->cursorTexture = 0;
5848 /* Draw a hardware cursor */
5849 ICONINFO cursorInfo;
5851 /* Create and clear maskBits because it is not needed for
5852 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5854 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5855 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
5856 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
5857 WINED3DLOCK_NO_DIRTY_UPDATE |
5858 WINED3DLOCK_READONLY
5860 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
5861 pSur->currentDesc.Height);
5863 cursorInfo.fIcon = FALSE;
5864 cursorInfo.xHotspot = XHotSpot;
5865 cursorInfo.yHotspot = YHotSpot;
5866 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
5867 pSur->currentDesc.Height, 1,
5869 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
5870 pSur->currentDesc.Height, 1,
5871 32, lockedRect.pBits);
5872 IWineD3DSurface_UnlockRect(pCursorBitmap);
5873 /* Create our cursor and clean up. */
5874 cursor = CreateIconIndirect(&cursorInfo);
5876 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5877 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5878 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5879 This->hardwareCursor = cursor;
5880 HeapFree(GetProcessHeap(), 0, maskBits);
5884 This->xHotSpot = XHotSpot;
5885 This->yHotSpot = YHotSpot;
5889 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5891 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5893 This->xScreenSpace = XScreenSpace;
5894 This->yScreenSpace = YScreenSpace;
5900 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5902 BOOL oldVisible = This->bCursorVisible;
5905 TRACE("(%p) : visible(%d)\n", This, bShow);
5908 * When ShowCursor is first called it should make the cursor appear at the OS's last
5909 * known cursor position. Because of this, some applications just repetitively call
5910 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5913 This->xScreenSpace = pt.x;
5914 This->yScreenSpace = pt.y;
5916 if (This->haveHardwareCursor) {
5917 This->bCursorVisible = bShow;
5919 SetCursor(This->hardwareCursor);
5925 if (This->cursorTexture)
5926 This->bCursorVisible = bShow;
5932 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5934 TRACE("(%p) : state (%u)\n", This, This->state);
5935 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5936 switch (This->state) {
5939 case WINED3DERR_DEVICELOST:
5941 ResourceList *resourceList = This->resources;
5942 while (NULL != resourceList) {
5943 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5944 return WINED3DERR_DEVICENOTRESET;
5945 resourceList = resourceList->next;
5947 return WINED3DERR_DEVICELOST;
5949 case WINED3DERR_DRIVERINTERNALERROR:
5950 return WINED3DERR_DRIVERINTERNALERROR;
5954 return WINED3DERR_DRIVERINTERNALERROR;
5958 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5960 /** FIXME: Resource tracking needs to be done,
5961 * The closes we can do to this is set the priorities of all managed textures low
5962 * and then reset them.
5963 ***********************************************************/
5964 FIXME("(%p) : stub\n", This);
5968 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5969 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5971 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5972 if(surface->Flags & SFLAG_DIBSECTION) {
5973 /* Release the DC */
5974 SelectObject(surface->hDC, surface->dib.holdbitmap);
5975 DeleteDC(surface->hDC);
5976 /* Release the DIB section */
5977 DeleteObject(surface->dib.DIBsection);
5978 surface->dib.bitmap_data = NULL;
5979 surface->resource.allocatedMemory = NULL;
5980 surface->Flags &= ~SFLAG_DIBSECTION;
5982 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5983 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5984 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5985 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5986 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5988 surface->pow2Width = surface->pow2Height = 1;
5989 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5990 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5992 if(surface->glDescription.textureName) {
5994 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5995 glDeleteTextures(1, &surface->glDescription.textureName);
5997 surface->glDescription.textureName = 0;
5998 surface->Flags &= ~SFLAG_CLIENT;
6000 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6001 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6002 surface->Flags |= SFLAG_NONPOW2;
6004 surface->Flags &= ~SFLAG_NONPOW2;
6006 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6007 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6010 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6012 IWineD3DSwapChainImpl *swapchain;
6014 BOOL DisplayModeChanged = FALSE;
6015 WINED3DDISPLAYMODE mode;
6016 TRACE("(%p)\n", This);
6018 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6020 ERR("Failed to get the first implicit swapchain\n");
6024 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6025 * on an existing gl context, so there's no real need for recreation.
6027 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6029 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6031 TRACE("New params:\n");
6032 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6033 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6034 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6035 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6036 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6037 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6038 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6039 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6040 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6041 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6042 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6043 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6044 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6046 /* No special treatment of these parameters. Just store them */
6047 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6048 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6049 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6050 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6052 /* What to do about these? */
6053 if(pPresentationParameters->BackBufferCount != 0 &&
6054 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6055 ERR("Cannot change the back buffer count yet\n");
6057 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6058 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6059 ERR("Cannot change the back buffer format yet\n");
6061 if(pPresentationParameters->hDeviceWindow != NULL &&
6062 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6063 ERR("Cannot change the device window yet\n");
6065 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6066 ERR("What do do about a changed auto depth stencil parameter?\n");
6069 if(pPresentationParameters->Windowed) {
6070 mode.Width = swapchain->orig_width;
6071 mode.Height = swapchain->orig_height;
6072 mode.RefreshRate = 0;
6073 mode.Format = swapchain->presentParms.BackBufferFormat;
6075 mode.Width = pPresentationParameters->BackBufferWidth;
6076 mode.Height = pPresentationParameters->BackBufferHeight;
6077 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6078 mode.Format = swapchain->presentParms.BackBufferFormat;
6081 /* Should Width == 800 && Height == 0 set 800x600? */
6082 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6083 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6084 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6091 vp.Width = pPresentationParameters->BackBufferWidth;
6092 vp.Height = pPresentationParameters->BackBufferHeight;
6096 if(!pPresentationParameters->Windowed) {
6097 DisplayModeChanged = TRUE;
6099 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6100 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6102 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6103 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6104 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6107 /* Now set the new viewport */
6108 IWineD3DDevice_SetViewport(iface, &vp);
6111 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6112 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6113 DisplayModeChanged) {
6115 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6116 if(!pPresentationParameters->Windowed) {
6117 IWineD3DDevice_SetFullscreen(iface, TRUE);
6120 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6122 /* Switching out of fullscreen mode? First set the original res, then change the window */
6123 if(pPresentationParameters->Windowed) {
6124 IWineD3DDevice_SetFullscreen(iface, FALSE);
6126 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6129 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6133 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6135 /** FIXME: always true at the moment **/
6136 if(!bEnableDialogs) {
6137 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6143 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6145 TRACE("(%p) : pParameters %p\n", This, pParameters);
6147 *pParameters = This->createParms;
6151 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6152 IWineD3DSwapChain *swapchain;
6153 HRESULT hrc = WINED3D_OK;
6155 TRACE("Relaying to swapchain\n");
6157 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6158 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6159 IWineD3DSwapChain_Release(swapchain);
6164 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6165 IWineD3DSwapChain *swapchain;
6166 HRESULT hrc = WINED3D_OK;
6168 TRACE("Relaying to swapchain\n");
6170 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6171 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6172 IWineD3DSwapChain_Release(swapchain);
6178 /** ********************************************************
6179 * Notification functions
6180 ** ********************************************************/
6181 /** This function must be called in the release of a resource when ref == 0,
6182 * the contents of resource must still be correct,
6183 * any handels to other resource held by the caller must be closed
6184 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6185 *****************************************************/
6186 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6188 ResourceList* resourceList;
6190 TRACE("(%p) : resource %p\n", This, resource);
6191 /* add a new texture to the frot of the linked list */
6192 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6193 resourceList->resource = resource;
6195 /* Get the old head */
6196 resourceList->next = This->resources;
6198 This->resources = resourceList;
6199 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6204 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6206 ResourceList* resourceList = NULL;
6207 ResourceList* previousResourceList = NULL;
6209 TRACE("(%p) : resource %p\n", This, resource);
6211 resourceList = This->resources;
6213 while (resourceList != NULL) {
6214 if(resourceList->resource == resource) break;
6215 previousResourceList = resourceList;
6216 resourceList = resourceList->next;
6219 if (resourceList == NULL) {
6220 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6223 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6225 /* make sure we don't leave a hole in the list */
6226 if (previousResourceList != NULL) {
6227 previousResourceList->next = resourceList->next;
6229 This->resources = resourceList->next;
6236 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6240 TRACE("(%p) : resource %p\n", This, resource);
6241 switch(IWineD3DResource_GetType(resource)){
6242 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6243 case WINED3DRTYPE_SURFACE: {
6246 /* Cleanup any FBO attachments */
6247 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6248 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6249 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6250 set_render_target_fbo(iface, i, NULL);
6251 This->fbo_color_attachments[i] = NULL;
6254 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6255 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6256 set_depth_stencil_fbo(iface, NULL);
6257 This->fbo_depth_attachment = NULL;
6263 case WINED3DRTYPE_TEXTURE:
6264 case WINED3DRTYPE_CUBETEXTURE:
6265 case WINED3DRTYPE_VOLUMETEXTURE:
6266 for (counter = 0; counter < MAX_SAMPLERS; counter++) {
6267 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6268 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6269 This->stateBlock->textures[counter] = NULL;
6271 if (This->updateStateBlock != This->stateBlock ){
6272 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6273 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6274 This->updateStateBlock->textures[counter] = NULL;
6279 case WINED3DRTYPE_VOLUME:
6280 /* TODO: nothing really? */
6282 case WINED3DRTYPE_VERTEXBUFFER:
6283 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6286 TRACE("Cleaning up stream pointers\n");
6288 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6289 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6290 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6292 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6293 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6294 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6295 This->updateStateBlock->streamSource[streamNumber] = 0;
6296 /* Set changed flag? */
6299 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) */
6300 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6301 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6302 This->stateBlock->streamSource[streamNumber] = 0;
6305 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6306 else { /* This shouldn't happen */
6307 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6314 case WINED3DRTYPE_INDEXBUFFER:
6315 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6316 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6317 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6318 This->updateStateBlock->pIndexData = NULL;
6321 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6322 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6323 This->stateBlock->pIndexData = NULL;
6329 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6334 /* Remove the resoruce from the resourceStore */
6335 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6337 TRACE("Resource released\n");
6341 /**********************************************************
6342 * IWineD3DDevice VTbl follows
6343 **********************************************************/
6345 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6347 /*** IUnknown methods ***/
6348 IWineD3DDeviceImpl_QueryInterface,
6349 IWineD3DDeviceImpl_AddRef,
6350 IWineD3DDeviceImpl_Release,
6351 /*** IWineD3DDevice methods ***/
6352 IWineD3DDeviceImpl_GetParent,
6353 /*** Creation methods**/
6354 IWineD3DDeviceImpl_CreateVertexBuffer,
6355 IWineD3DDeviceImpl_CreateIndexBuffer,
6356 IWineD3DDeviceImpl_CreateStateBlock,
6357 IWineD3DDeviceImpl_CreateSurface,
6358 IWineD3DDeviceImpl_CreateTexture,
6359 IWineD3DDeviceImpl_CreateVolumeTexture,
6360 IWineD3DDeviceImpl_CreateVolume,
6361 IWineD3DDeviceImpl_CreateCubeTexture,
6362 IWineD3DDeviceImpl_CreateQuery,
6363 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6364 IWineD3DDeviceImpl_CreateVertexDeclaration,
6365 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6366 IWineD3DDeviceImpl_CreateVertexShader,
6367 IWineD3DDeviceImpl_CreatePixelShader,
6368 IWineD3DDeviceImpl_CreatePalette,
6369 /*** Odd functions **/
6370 IWineD3DDeviceImpl_Init3D,
6371 IWineD3DDeviceImpl_Uninit3D,
6372 IWineD3DDeviceImpl_SetFullscreen,
6373 IWineD3DDeviceImpl_SetMultithreaded,
6374 IWineD3DDeviceImpl_EvictManagedResources,
6375 IWineD3DDeviceImpl_GetAvailableTextureMem,
6376 IWineD3DDeviceImpl_GetBackBuffer,
6377 IWineD3DDeviceImpl_GetCreationParameters,
6378 IWineD3DDeviceImpl_GetDeviceCaps,
6379 IWineD3DDeviceImpl_GetDirect3D,
6380 IWineD3DDeviceImpl_GetDisplayMode,
6381 IWineD3DDeviceImpl_SetDisplayMode,
6382 IWineD3DDeviceImpl_GetHWND,
6383 IWineD3DDeviceImpl_SetHWND,
6384 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6385 IWineD3DDeviceImpl_GetRasterStatus,
6386 IWineD3DDeviceImpl_GetSwapChain,
6387 IWineD3DDeviceImpl_Reset,
6388 IWineD3DDeviceImpl_SetDialogBoxMode,
6389 IWineD3DDeviceImpl_SetCursorProperties,
6390 IWineD3DDeviceImpl_SetCursorPosition,
6391 IWineD3DDeviceImpl_ShowCursor,
6392 IWineD3DDeviceImpl_TestCooperativeLevel,
6393 /*** Getters and setters **/
6394 IWineD3DDeviceImpl_SetClipPlane,
6395 IWineD3DDeviceImpl_GetClipPlane,
6396 IWineD3DDeviceImpl_SetClipStatus,
6397 IWineD3DDeviceImpl_GetClipStatus,
6398 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6399 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6400 IWineD3DDeviceImpl_SetDepthStencilSurface,
6401 IWineD3DDeviceImpl_GetDepthStencilSurface,
6402 IWineD3DDeviceImpl_SetFVF,
6403 IWineD3DDeviceImpl_GetFVF,
6404 IWineD3DDeviceImpl_SetGammaRamp,
6405 IWineD3DDeviceImpl_GetGammaRamp,
6406 IWineD3DDeviceImpl_SetIndices,
6407 IWineD3DDeviceImpl_GetIndices,
6408 IWineD3DDeviceImpl_SetBaseVertexIndex,
6409 IWineD3DDeviceImpl_GetBaseVertexIndex,
6410 IWineD3DDeviceImpl_SetLight,
6411 IWineD3DDeviceImpl_GetLight,
6412 IWineD3DDeviceImpl_SetLightEnable,
6413 IWineD3DDeviceImpl_GetLightEnable,
6414 IWineD3DDeviceImpl_SetMaterial,
6415 IWineD3DDeviceImpl_GetMaterial,
6416 IWineD3DDeviceImpl_SetNPatchMode,
6417 IWineD3DDeviceImpl_GetNPatchMode,
6418 IWineD3DDeviceImpl_SetPaletteEntries,
6419 IWineD3DDeviceImpl_GetPaletteEntries,
6420 IWineD3DDeviceImpl_SetPixelShader,
6421 IWineD3DDeviceImpl_GetPixelShader,
6422 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6423 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6424 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6425 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6426 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6427 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6428 IWineD3DDeviceImpl_SetRenderState,
6429 IWineD3DDeviceImpl_GetRenderState,
6430 IWineD3DDeviceImpl_SetRenderTarget,
6431 IWineD3DDeviceImpl_GetRenderTarget,
6432 IWineD3DDeviceImpl_SetFrontBackBuffers,
6433 IWineD3DDeviceImpl_SetSamplerState,
6434 IWineD3DDeviceImpl_GetSamplerState,
6435 IWineD3DDeviceImpl_SetScissorRect,
6436 IWineD3DDeviceImpl_GetScissorRect,
6437 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6438 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6439 IWineD3DDeviceImpl_SetStreamSource,
6440 IWineD3DDeviceImpl_GetStreamSource,
6441 IWineD3DDeviceImpl_SetStreamSourceFreq,
6442 IWineD3DDeviceImpl_GetStreamSourceFreq,
6443 IWineD3DDeviceImpl_SetTexture,
6444 IWineD3DDeviceImpl_GetTexture,
6445 IWineD3DDeviceImpl_SetTextureStageState,
6446 IWineD3DDeviceImpl_GetTextureStageState,
6447 IWineD3DDeviceImpl_SetTransform,
6448 IWineD3DDeviceImpl_GetTransform,
6449 IWineD3DDeviceImpl_SetVertexDeclaration,
6450 IWineD3DDeviceImpl_GetVertexDeclaration,
6451 IWineD3DDeviceImpl_SetVertexShader,
6452 IWineD3DDeviceImpl_GetVertexShader,
6453 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6454 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6455 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6456 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6457 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6458 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6459 IWineD3DDeviceImpl_SetViewport,
6460 IWineD3DDeviceImpl_GetViewport,
6461 IWineD3DDeviceImpl_MultiplyTransform,
6462 IWineD3DDeviceImpl_ValidateDevice,
6463 IWineD3DDeviceImpl_ProcessVertices,
6464 /*** State block ***/
6465 IWineD3DDeviceImpl_BeginStateBlock,
6466 IWineD3DDeviceImpl_EndStateBlock,
6467 /*** Scene management ***/
6468 IWineD3DDeviceImpl_BeginScene,
6469 IWineD3DDeviceImpl_EndScene,
6470 IWineD3DDeviceImpl_Present,
6471 IWineD3DDeviceImpl_Clear,
6473 IWineD3DDeviceImpl_DrawPrimitive,
6474 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6475 IWineD3DDeviceImpl_DrawPrimitiveUP,
6476 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6477 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6478 IWineD3DDeviceImpl_DrawRectPatch,
6479 IWineD3DDeviceImpl_DrawTriPatch,
6480 IWineD3DDeviceImpl_DeletePatch,
6481 IWineD3DDeviceImpl_ColorFill,
6482 IWineD3DDeviceImpl_UpdateTexture,
6483 IWineD3DDeviceImpl_UpdateSurface,
6484 IWineD3DDeviceImpl_GetFrontBufferData,
6485 /*** object tracking ***/
6486 IWineD3DDeviceImpl_ResourceReleased
6490 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6491 WINED3DRS_ALPHABLENDENABLE ,
6492 WINED3DRS_ALPHAFUNC ,
6493 WINED3DRS_ALPHAREF ,
6494 WINED3DRS_ALPHATESTENABLE ,
6496 WINED3DRS_COLORWRITEENABLE ,
6497 WINED3DRS_DESTBLEND ,
6498 WINED3DRS_DITHERENABLE ,
6499 WINED3DRS_FILLMODE ,
6500 WINED3DRS_FOGDENSITY ,
6502 WINED3DRS_FOGSTART ,
6503 WINED3DRS_LASTPIXEL ,
6504 WINED3DRS_SHADEMODE ,
6505 WINED3DRS_SRCBLEND ,
6506 WINED3DRS_STENCILENABLE ,
6507 WINED3DRS_STENCILFAIL ,
6508 WINED3DRS_STENCILFUNC ,
6509 WINED3DRS_STENCILMASK ,
6510 WINED3DRS_STENCILPASS ,
6511 WINED3DRS_STENCILREF ,
6512 WINED3DRS_STENCILWRITEMASK ,
6513 WINED3DRS_STENCILZFAIL ,
6514 WINED3DRS_TEXTUREFACTOR ,
6525 WINED3DRS_ZWRITEENABLE
6528 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6529 WINED3DTSS_ADDRESSW ,
6530 WINED3DTSS_ALPHAARG0 ,
6531 WINED3DTSS_ALPHAARG1 ,
6532 WINED3DTSS_ALPHAARG2 ,
6533 WINED3DTSS_ALPHAOP ,
6534 WINED3DTSS_BUMPENVLOFFSET ,
6535 WINED3DTSS_BUMPENVLSCALE ,
6536 WINED3DTSS_BUMPENVMAT00 ,
6537 WINED3DTSS_BUMPENVMAT01 ,
6538 WINED3DTSS_BUMPENVMAT10 ,
6539 WINED3DTSS_BUMPENVMAT11 ,
6540 WINED3DTSS_COLORARG0 ,
6541 WINED3DTSS_COLORARG1 ,
6542 WINED3DTSS_COLORARG2 ,
6543 WINED3DTSS_COLOROP ,
6544 WINED3DTSS_RESULTARG ,
6545 WINED3DTSS_TEXCOORDINDEX ,
6546 WINED3DTSS_TEXTURETRANSFORMFLAGS
6549 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6550 WINED3DSAMP_ADDRESSU ,
6551 WINED3DSAMP_ADDRESSV ,
6552 WINED3DSAMP_ADDRESSW ,
6553 WINED3DSAMP_BORDERCOLOR ,
6554 WINED3DSAMP_MAGFILTER ,
6555 WINED3DSAMP_MINFILTER ,
6556 WINED3DSAMP_MIPFILTER ,
6557 WINED3DSAMP_MIPMAPLODBIAS ,
6558 WINED3DSAMP_MAXMIPLEVEL ,
6559 WINED3DSAMP_MAXANISOTROPY ,
6560 WINED3DSAMP_SRGBTEXTURE ,
6561 WINED3DSAMP_ELEMENTINDEX
6564 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6566 WINED3DRS_AMBIENTMATERIALSOURCE ,
6567 WINED3DRS_CLIPPING ,
6568 WINED3DRS_CLIPPLANEENABLE ,
6569 WINED3DRS_COLORVERTEX ,
6570 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6571 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6572 WINED3DRS_FOGDENSITY ,
6574 WINED3DRS_FOGSTART ,
6575 WINED3DRS_FOGTABLEMODE ,
6576 WINED3DRS_FOGVERTEXMODE ,
6577 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6578 WINED3DRS_LIGHTING ,
6579 WINED3DRS_LOCALVIEWER ,
6580 WINED3DRS_MULTISAMPLEANTIALIAS ,
6581 WINED3DRS_MULTISAMPLEMASK ,
6582 WINED3DRS_NORMALIZENORMALS ,
6583 WINED3DRS_PATCHEDGESTYLE ,
6584 WINED3DRS_POINTSCALE_A ,
6585 WINED3DRS_POINTSCALE_B ,
6586 WINED3DRS_POINTSCALE_C ,
6587 WINED3DRS_POINTSCALEENABLE ,
6588 WINED3DRS_POINTSIZE ,
6589 WINED3DRS_POINTSIZE_MAX ,
6590 WINED3DRS_POINTSIZE_MIN ,
6591 WINED3DRS_POINTSPRITEENABLE ,
6592 WINED3DRS_RANGEFOGENABLE ,
6593 WINED3DRS_SPECULARMATERIALSOURCE ,
6594 WINED3DRS_TWEENFACTOR ,
6595 WINED3DRS_VERTEXBLEND
6598 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6599 WINED3DTSS_TEXCOORDINDEX ,
6600 WINED3DTSS_TEXTURETRANSFORMFLAGS
6603 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6604 WINED3DSAMP_DMAPOFFSET
6607 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6608 DWORD rep = StateTable[state].representative;
6612 WineD3DContext *context;
6615 for(i = 0; i < This->numContexts; i++) {
6616 context = This->contexts[i];
6617 if(isStateDirty(context, rep)) continue;
6619 context->dirtyArray[context->numDirtyEntries++] = rep;
6622 context->isStateDirty[idx] |= (1 << shift);