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-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 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 /* static function declarations */
55 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; ERR("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
67 *pp##type = (IWineD3D##type *) object; \
70 /**********************************************************
71 * Global variable / Constants follow
72 **********************************************************/
73 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
75 /**********************************************************
76 * IUnknown parts follows
77 **********************************************************/
79 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
81 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
83 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
84 if (IsEqualGUID(riid, &IID_IUnknown)
85 || IsEqualGUID(riid, &IID_IWineD3DBase)
86 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
87 IUnknown_AddRef(iface);
95 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
96 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
97 ULONG refCount = InterlockedIncrement(&This->ref);
99 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
103 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
105 ULONG refCount = InterlockedDecrement(&This->ref);
107 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
112 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
113 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
114 This->multistate_funcs[i] = NULL;
117 /* TODO: Clean up all the surfaces and textures! */
118 /* NOTE: You must release the parent if the object was created via a callback
119 ** ***************************/
121 if (!list_empty(&This->resources)) {
122 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
123 dumpResources(&This->resources);
126 if(This->contexts) ERR("Context array not freed!\n");
127 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
128 This->haveHardwareCursor = FALSE;
130 IWineD3D_Release(This->wineD3D);
131 This->wineD3D = NULL;
132 HeapFree(GetProcessHeap(), 0, This);
133 TRACE("Freed device %p\n", This);
139 /**********************************************************
140 * IWineD3DDevice implementation follows
141 **********************************************************/
142 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
144 *pParent = This->parent;
145 IUnknown_AddRef(This->parent);
149 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
150 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 IWineD3DVertexBufferImpl *object;
154 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
155 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
160 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
161 *ppVertexBuffer = NULL;
162 return WINED3DERR_INVALIDCALL;
163 } else if(Pool == WINED3DPOOL_SCRATCH) {
164 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
165 * anyway, SCRATCH vertex buffers aren't usable anywhere
167 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
168 *ppVertexBuffer = NULL;
169 return WINED3DERR_INVALIDCALL;
172 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
175 ERR("Out of memory\n");
176 *ppVertexBuffer = NULL;
177 return WINED3DERR_OUTOFVIDEOMEMORY;
180 object->lpVtbl = &IWineD3DVertexBuffer_Vtbl;
181 hr = resource_init(&object->resource, WINED3DRTYPE_VERTEXBUFFER, This, Size, Usage, Format, Pool, parent);
184 WARN("Failed to initialize resource, returning %#x\n", hr);
185 HeapFree(GetProcessHeap(), 0, object);
186 *ppVertexBuffer = NULL;
190 TRACE("(%p) : Created resource %p\n", This, object);
192 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
194 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
195 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
199 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
200 * drawStridedFast (half-life 2).
202 * Basically converting the vertices in the buffer is quite expensive, and observations
203 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
204 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
206 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
207 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
208 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
209 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
211 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
212 * more. In this call we can convert dx7 buffers too.
214 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
215 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
216 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
217 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
218 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
219 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
220 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
221 } else if(dxVersion <= 7 && conv) {
222 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
224 object->Flags |= VBFLAG_CREATEVBO;
229 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
230 GLenum error, glUsage;
231 TRACE("Creating VBO for Index Buffer %p\n", object);
233 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
234 * restored on the next draw
236 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
238 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
239 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
244 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
245 error = glGetError();
246 if(error != GL_NO_ERROR || object->vbo == 0) {
247 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
251 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
252 error = glGetError();
253 if(error != GL_NO_ERROR) {
254 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
258 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
259 * copy no readback will be needed
261 glUsage = GL_STATIC_DRAW_ARB;
262 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
263 error = glGetError();
264 if(error != GL_NO_ERROR) {
265 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
269 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
273 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
274 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
279 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
280 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
281 HANDLE *sharedHandle, IUnknown *parent) {
282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
283 IWineD3DIndexBufferImpl *object;
286 TRACE("(%p) Creating index buffer\n", This);
288 /* Allocate the storage for the device */
289 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
292 ERR("Out of memory\n");
293 *ppIndexBuffer = NULL;
294 return WINED3DERR_OUTOFVIDEOMEMORY;
297 object->lpVtbl = &IWineD3DIndexBuffer_Vtbl;
298 hr = resource_init(&object->resource, WINED3DRTYPE_INDEXBUFFER, This, Length, Usage, Format, Pool, parent);
301 WARN("Failed to initialize resource, returning %#x\n", hr);
302 HeapFree(GetProcessHeap(), 0, object);
303 *ppIndexBuffer = NULL;
307 TRACE("(%p) : Created resource %p\n", This, object);
309 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
311 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
312 CreateIndexBufferVBO(This, object);
315 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
316 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
317 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
322 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
325 IWineD3DStateBlockImpl *object;
329 D3DCREATEOBJECTINSTANCE(object, StateBlock)
330 object->blockType = Type;
332 for(i = 0; i < LIGHTMAP_SIZE; i++) {
333 list_init(&object->lightMap[i]);
336 temp_result = allocate_shader_constants(object);
337 if (FAILED(temp_result))
339 HeapFree(GetProcessHeap(), 0, object);
343 /* Special case - Used during initialization to produce a placeholder stateblock
344 so other functions called can update a state block */
345 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
347 /* Don't bother increasing the reference count otherwise a device will never
348 be freed due to circular dependencies */
352 /* Otherwise, might as well set the whole state block to the appropriate values */
353 if (This->stateBlock != NULL)
354 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
356 memset(object->streamFreq, 1, sizeof(object->streamFreq));
358 /* Reset the ref and type after kludging it */
359 object->wineD3DDevice = This;
361 object->blockType = Type;
363 TRACE("Updating changed flags appropriate for type %d\n", Type);
365 if (Type == WINED3DSBT_ALL) {
367 TRACE("ALL => Pretend everything has changed\n");
368 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
370 /* Lights are not part of the changed / set structure */
371 for(j = 0; j < LIGHTMAP_SIZE; j++) {
373 LIST_FOR_EACH(e, &object->lightMap[j]) {
374 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
375 light->changed = TRUE;
376 light->enabledChanged = TRUE;
379 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
380 object->contained_render_states[j - 1] = j;
382 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
383 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
384 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
385 object->contained_transform_states[j - 1] = j;
387 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
388 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
389 object->contained_vs_consts_f[j] = j;
391 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
392 for(j = 0; j < MAX_CONST_I; j++) {
393 object->contained_vs_consts_i[j] = j;
395 object->num_contained_vs_consts_i = MAX_CONST_I;
396 for(j = 0; j < MAX_CONST_B; j++) {
397 object->contained_vs_consts_b[j] = j;
399 object->num_contained_vs_consts_b = MAX_CONST_B;
400 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
401 object->contained_ps_consts_f[j] = j;
403 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
404 for(j = 0; j < MAX_CONST_I; j++) {
405 object->contained_ps_consts_i[j] = j;
407 object->num_contained_ps_consts_i = MAX_CONST_I;
408 for(j = 0; j < MAX_CONST_B; j++) {
409 object->contained_ps_consts_b[j] = j;
411 object->num_contained_ps_consts_b = MAX_CONST_B;
412 for(i = 0; i < MAX_TEXTURES; i++) {
413 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
415 object->contained_tss_states[object->num_contained_tss_states].stage = i;
416 object->contained_tss_states[object->num_contained_tss_states].state = j;
417 object->num_contained_tss_states++;
420 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
421 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
422 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
423 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
424 object->num_contained_sampler_states++;
428 for(i = 0; i < MAX_STREAMS; i++) {
429 if(object->streamSource[i]) {
430 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
433 if(object->pIndexData) {
434 IWineD3DIndexBuffer_AddRef(object->pIndexData);
436 if(object->vertexShader) {
437 IWineD3DVertexShader_AddRef(object->vertexShader);
439 if(object->pixelShader) {
440 IWineD3DPixelShader_AddRef(object->pixelShader);
443 } else if (Type == WINED3DSBT_PIXELSTATE) {
445 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
446 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
448 object->changed.pixelShader = TRUE;
450 /* Pixel Shader Constants */
451 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
452 object->contained_ps_consts_f[i] = i;
453 object->changed.pixelShaderConstantsF[i] = TRUE;
455 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
456 for (i = 0; i < MAX_CONST_B; ++i) {
457 object->contained_ps_consts_b[i] = i;
458 object->changed.pixelShaderConstantsB |= (1 << i);
460 object->num_contained_ps_consts_b = MAX_CONST_B;
461 for (i = 0; i < MAX_CONST_I; ++i) {
462 object->contained_ps_consts_i[i] = i;
463 object->changed.pixelShaderConstantsI |= (1 << i);
465 object->num_contained_ps_consts_i = MAX_CONST_I;
467 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
468 DWORD rs = SavedPixelStates_R[i];
469 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
470 object->contained_render_states[i] = rs;
472 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
473 for (j = 0; j < MAX_TEXTURES; j++) {
474 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
475 DWORD state = SavedPixelStates_T[i];
476 object->changed.textureState[j] |= 1 << state;
477 object->contained_tss_states[object->num_contained_tss_states].stage = j;
478 object->contained_tss_states[object->num_contained_tss_states].state = state;
479 object->num_contained_tss_states++;
482 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
483 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
484 DWORD state = SavedPixelStates_S[i];
485 object->changed.samplerState[j] |= 1 << state;
486 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
487 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
488 object->num_contained_sampler_states++;
491 if(object->pixelShader) {
492 IWineD3DPixelShader_AddRef(object->pixelShader);
495 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
496 * on them. This makes releasing the buffer easier
498 for(i = 0; i < MAX_STREAMS; i++) {
499 object->streamSource[i] = NULL;
501 object->pIndexData = NULL;
502 object->vertexShader = NULL;
504 } else if (Type == WINED3DSBT_VERTEXSTATE) {
506 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
507 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
509 object->changed.vertexShader = TRUE;
511 /* Vertex Shader Constants */
512 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
513 object->changed.vertexShaderConstantsF[i] = TRUE;
514 object->contained_vs_consts_f[i] = i;
516 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
517 for (i = 0; i < MAX_CONST_B; ++i) {
518 object->contained_vs_consts_b[i] = i;
519 object->changed.vertexShaderConstantsB |= (1 << i);
521 object->num_contained_vs_consts_b = MAX_CONST_B;
522 for (i = 0; i < MAX_CONST_I; ++i) {
523 object->contained_vs_consts_i[i] = i;
524 object->changed.vertexShaderConstantsI |= (1 << i);
526 object->num_contained_vs_consts_i = MAX_CONST_I;
527 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
528 DWORD rs = SavedVertexStates_R[i];
529 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
530 object->contained_render_states[i] = rs;
532 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
533 for (j = 0; j < MAX_TEXTURES; j++) {
534 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
535 DWORD state = SavedVertexStates_T[i];
536 object->changed.textureState[j] |= 1 << state;
537 object->contained_tss_states[object->num_contained_tss_states].stage = j;
538 object->contained_tss_states[object->num_contained_tss_states].state = state;
539 object->num_contained_tss_states++;
542 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
543 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
544 DWORD state = SavedVertexStates_S[i];
545 object->changed.samplerState[j] |= 1 << state;
546 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
547 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
548 object->num_contained_sampler_states++;
552 for(j = 0; j < LIGHTMAP_SIZE; j++) {
554 LIST_FOR_EACH(e, &object->lightMap[j]) {
555 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
556 light->changed = TRUE;
557 light->enabledChanged = TRUE;
561 for(i = 0; i < MAX_STREAMS; i++) {
562 if(object->streamSource[i]) {
563 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
566 if(object->vertexShader) {
567 IWineD3DVertexShader_AddRef(object->vertexShader);
569 object->pIndexData = NULL;
570 object->pixelShader = NULL;
572 FIXME("Unrecognized state block type %d\n", Type);
575 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
579 /* ************************************
581 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
584 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
586 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.
588 ******************************** */
590 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) {
591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
592 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
593 unsigned int Size = 1;
594 const struct GlPixelFormatDesc *glDesc;
595 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
599 TRACE("(%p) Create surface\n",This);
601 /** FIXME: Check ranges on the inputs are valid
604 * [in] Quality level. The valid range is between zero and one less than the level
605 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
606 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
607 * values of paired render targets, depth stencil surfaces, and the MultiSample type
609 *******************************/
614 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
616 * If this flag is set, the contents of the depth stencil buffer will be
617 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
618 * with a different depth surface.
620 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
621 ***************************/
623 if(MultisampleQuality > 0) {
624 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
625 MultisampleQuality=0;
628 /** FIXME: Check that the format is supported
630 *******************************/
632 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
633 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
635 *********************************/
636 mul_4w = (Width + 3) & ~3;
637 mul_4h = (Height + 3) & ~3;
638 if (WINED3DFMT_UNKNOWN == Format) {
640 } else if (Format == WINED3DFMT_DXT1) {
641 /* DXT1 is half byte per pixel */
642 Size = (mul_4w * tableEntry->bpp * mul_4h) >> 1;
644 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
645 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
646 Format == WINED3DFMT_ATI2N) {
647 Size = (mul_4w * tableEntry->bpp * mul_4h);
649 /* The pitch is a multiple of 4 bytes */
650 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
654 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
656 /** Create and initialise the surface resource **/
657 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
660 ERR("Out of memory\n");
662 return WINED3DERR_OUTOFVIDEOMEMORY;
665 /* Look at the implementation and set the correct Vtable */
669 /* Check if a 3D adapter is available when creating gl surfaces */
672 ERR("OpenGL surfaces are not available without opengl\n");
673 HeapFree(GetProcessHeap(), 0, object);
674 return WINED3DERR_NOTAVAILABLE;
676 object->lpVtbl = &IWineD3DSurface_Vtbl;
680 object->lpVtbl = &IWineGDISurface_Vtbl;
684 /* To be sure to catch this */
685 ERR("Unknown requested surface implementation %d!\n", Impl);
686 HeapFree(GetProcessHeap(), 0, object);
687 return WINED3DERR_INVALIDCALL;
690 hr = resource_init(&object->resource, WINED3DRTYPE_SURFACE, This, Size, Usage, Format, Pool, parent);
693 WARN("Failed to initialize resource, returning %#x\n", hr);
694 HeapFree(GetProcessHeap(), 0, object);
699 TRACE("(%p) : Created resource %p\n", This, object);
701 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
703 *ppSurface = (IWineD3DSurface *)object;
705 /* "Standalone" surface */
706 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
708 object->currentDesc.Width = Width;
709 object->currentDesc.Height = Height;
710 object->currentDesc.MultiSampleType = MultiSample;
711 object->currentDesc.MultiSampleQuality = MultisampleQuality;
712 object->glDescription.level = Level;
713 object->heightscale = glDesc->heightscale != 0.0 ? glDesc->heightscale : 1.0;
714 list_init(&object->overlays);
717 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
718 object->Flags |= Discard ? SFLAG_DISCARD : 0;
719 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
720 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
723 if (WINED3DFMT_UNKNOWN != Format) {
724 object->bytesPerPixel = tableEntry->bpp;
726 object->bytesPerPixel = 0;
729 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
731 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
733 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
734 * this function is too deep to need to care about things like this.
735 * Levels need to be checked too, and possibly Type since they all affect what can be done.
736 * ****************************************/
738 case WINED3DPOOL_SCRATCH:
740 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
741 "which are mutually exclusive, setting lockable to TRUE\n");
744 case WINED3DPOOL_SYSTEMMEM:
745 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
746 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
747 case WINED3DPOOL_MANAGED:
748 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
749 "Usage of DYNAMIC which are mutually exclusive, not doing "
750 "anything just telling you.\n");
752 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
753 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
754 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
755 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
758 FIXME("(%p) Unknown pool %d\n", This, Pool);
762 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
763 FIXME("Trying to create a render target that isn't in the default pool\n");
766 /* mark the texture as dirty so that it gets loaded first time around*/
767 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
768 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
769 This, Width, Height, Format, debug_d3dformat(Format),
770 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
772 list_init(&object->renderbuffers);
774 /* Call the private setup routine */
775 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)object);
778 ERR("Private setup failed, returning %#x\n", hr);
779 IWineD3DSurface_Release(*ppSurface);
787 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
788 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
789 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
790 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
793 IWineD3DTextureImpl *object;
798 unsigned int pow2Width;
799 unsigned int pow2Height;
800 const struct GlPixelFormatDesc *glDesc;
801 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
803 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
804 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
805 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
807 /* TODO: It should only be possible to create textures for formats
808 that are reported as supported */
809 if (WINED3DFMT_UNKNOWN >= Format) {
810 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
811 return WINED3DERR_INVALIDCALL;
814 /* Non-power2 support */
815 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO))
822 /* Find the nearest pow2 match */
823 pow2Width = pow2Height = 1;
824 while (pow2Width < Width) pow2Width <<= 1;
825 while (pow2Height < Height) pow2Height <<= 1;
827 if (pow2Width != Width || pow2Height != Height)
831 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
832 return WINED3DERR_INVALIDCALL;
838 /* Calculate levels for mip mapping */
839 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
841 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
843 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
844 return WINED3DERR_INVALIDCALL;
849 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
850 return WINED3DERR_INVALIDCALL;
857 Levels = wined3d_log2i(max(Width, Height)) + 1;
858 TRACE("Calculated levels = %d\n", Levels);
861 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
864 ERR("Out of memory\n");
866 return WINED3DERR_OUTOFVIDEOMEMORY;
869 object->lpVtbl = &IWineD3DTexture_Vtbl;
870 hr = resource_init(&object->resource, WINED3DRTYPE_TEXTURE, This, 0, Usage, Format, Pool, parent);
873 WARN("Failed to initialize resource, returning %#x\n", hr);
874 HeapFree(GetProcessHeap(), 0, object);
879 TRACE("(%p) : Created resource %p\n", This, object);
881 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
883 *ppTexture = (IWineD3DTexture *)object;
885 basetexture_init(&object->baseTexture, Levels, Usage);
886 object->width = Width;
887 object->height = Height;
889 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
890 object->baseTexture.minMipLookup = minMipLookup;
891 object->baseTexture.magLookup = magLookup;
893 object->baseTexture.minMipLookup = minMipLookup_noFilter;
894 object->baseTexture.magLookup = magLookup_noFilter;
897 /** FIXME: add support for real non-power-two if it's provided by the video card **/
898 /* Precalculated scaling for 'faked' non power of two texture coords.
899 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
900 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
901 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
903 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
904 object->baseTexture.pow2Matrix[0] = 1.0;
905 object->baseTexture.pow2Matrix[5] = 1.0;
906 object->baseTexture.pow2Matrix[10] = 1.0;
907 object->baseTexture.pow2Matrix[15] = 1.0;
908 object->target = GL_TEXTURE_2D;
909 object->cond_np2 = TRUE;
910 object->baseTexture.minMipLookup = minMipLookup_noFilter;
911 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
912 (Width != pow2Width || Height != pow2Height) &&
913 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
915 object->baseTexture.pow2Matrix[0] = (float)Width;
916 object->baseTexture.pow2Matrix[5] = (float)Height;
917 object->baseTexture.pow2Matrix[10] = 1.0;
918 object->baseTexture.pow2Matrix[15] = 1.0;
919 object->target = GL_TEXTURE_RECTANGLE_ARB;
920 object->cond_np2 = TRUE;
921 object->baseTexture.minMipLookup = minMipLookup_noFilter;
923 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
924 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
925 object->baseTexture.pow2Matrix[10] = 1.0;
926 object->baseTexture.pow2Matrix[15] = 1.0;
927 object->target = GL_TEXTURE_2D;
928 object->cond_np2 = FALSE;
930 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
932 /* Generate all the surfaces */
935 for (i = 0; i < object->baseTexture.levels; i++)
937 /* use the callback to create the texture surface */
938 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
939 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
940 FIXME("Failed to create surface %p\n", object);
942 object->surfaces[i] = NULL;
943 IWineD3DTexture_Release((IWineD3DTexture *)object);
949 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
950 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
951 surface_set_texture_target(object->surfaces[i], object->target);
952 /* calculate the next mipmap level */
953 tmpW = max(1, tmpW >> 1);
954 tmpH = max(1, tmpH >> 1);
956 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
958 TRACE("(%p) : Created texture %p\n", This, object);
962 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
963 UINT Width, UINT Height, UINT Depth,
964 UINT Levels, DWORD Usage,
965 WINED3DFORMAT Format, WINED3DPOOL Pool,
966 IWineD3DVolumeTexture **ppVolumeTexture,
967 HANDLE *pSharedHandle, IUnknown *parent,
968 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
971 IWineD3DVolumeTextureImpl *object;
976 const struct GlPixelFormatDesc *glDesc;
979 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
981 /* TODO: It should only be possible to create textures for formats
982 that are reported as supported */
983 if (WINED3DFMT_UNKNOWN >= Format) {
984 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
985 return WINED3DERR_INVALIDCALL;
987 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
988 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
989 return WINED3DERR_INVALIDCALL;
992 /* Calculate levels for mip mapping */
993 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
995 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
997 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
998 return WINED3DERR_INVALIDCALL;
1003 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1004 return WINED3DERR_INVALIDCALL;
1011 Levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
1012 TRACE("Calculated levels = %d\n", Levels);
1015 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1018 ERR("Out of memory\n");
1019 *ppVolumeTexture = NULL;
1020 return WINED3DERR_OUTOFVIDEOMEMORY;
1023 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1024 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUMETEXTURE, This, 0, Usage, Format, Pool, parent);
1027 WARN("Failed to initialize resource, returning %#x\n", hr);
1028 HeapFree(GetProcessHeap(), 0, object);
1029 *ppVolumeTexture = NULL;
1033 TRACE("(%p) : Created resource %p\n", This, object);
1035 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1037 basetexture_init(&object->baseTexture, Levels, Usage);
1039 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1040 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1042 /* Is NP2 support for volumes needed? */
1043 object->baseTexture.pow2Matrix[ 0] = 1.0;
1044 object->baseTexture.pow2Matrix[ 5] = 1.0;
1045 object->baseTexture.pow2Matrix[10] = 1.0;
1046 object->baseTexture.pow2Matrix[15] = 1.0;
1048 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1049 object->baseTexture.minMipLookup = minMipLookup;
1050 object->baseTexture.magLookup = magLookup;
1052 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1053 object->baseTexture.magLookup = magLookup_noFilter;
1056 /* Generate all the surfaces */
1061 for (i = 0; i < object->baseTexture.levels; i++)
1064 /* Create the volume */
1065 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
1066 &object->volumes[i], pSharedHandle);
1069 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1070 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1071 *ppVolumeTexture = NULL;
1075 /* Set its container to this object */
1076 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1078 /* calculate the next mipmap level */
1079 tmpW = max(1, tmpW >> 1);
1080 tmpH = max(1, tmpH >> 1);
1081 tmpD = max(1, tmpD >> 1);
1083 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
1085 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1086 TRACE("(%p) : Created volume texture %p\n", This, object);
1090 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1091 UINT Width, UINT Height, UINT Depth,
1093 WINED3DFORMAT Format, WINED3DPOOL Pool,
1094 IWineD3DVolume** ppVolume,
1095 HANDLE* pSharedHandle, IUnknown *parent) {
1097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1098 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1099 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1102 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1103 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1104 return WINED3DERR_INVALIDCALL;
1107 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1110 ERR("Out of memory\n");
1112 return WINED3DERR_OUTOFVIDEOMEMORY;
1115 object->lpVtbl = &IWineD3DVolume_Vtbl;
1116 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUME, This,
1117 Width * Height * Depth * formatDesc->bpp, Usage, Format, Pool, parent);
1120 WARN("Failed to initialize resource, returning %#x\n", hr);
1121 HeapFree(GetProcessHeap(), 0, object);
1126 TRACE("(%p) : Created resource %p\n", This, object);
1128 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1130 *ppVolume = (IWineD3DVolume *)object;
1132 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1133 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1135 object->currentDesc.Width = Width;
1136 object->currentDesc.Height = Height;
1137 object->currentDesc.Depth = Depth;
1138 object->bytesPerPixel = formatDesc->bpp;
1140 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1141 object->lockable = TRUE;
1142 object->locked = FALSE;
1143 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1144 object->dirty = TRUE;
1146 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1151 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1152 UINT Levels, DWORD Usage,
1153 WINED3DFORMAT Format, WINED3DPOOL Pool,
1154 IWineD3DCubeTexture **ppCubeTexture,
1155 HANDLE *pSharedHandle, IUnknown *parent,
1156 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1159 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1163 unsigned int pow2EdgeLength;
1164 const struct GlPixelFormatDesc *glDesc;
1165 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1167 /* TODO: It should only be possible to create textures for formats
1168 that are reported as supported */
1169 if (WINED3DFMT_UNKNOWN >= Format) {
1170 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1171 return WINED3DERR_INVALIDCALL;
1174 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1175 WARN("(%p) : Tried to create not supported cube texture\n", This);
1176 return WINED3DERR_INVALIDCALL;
1179 /* Calculate levels for mip mapping */
1180 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1182 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1184 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1185 return WINED3DERR_INVALIDCALL;
1190 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1191 return WINED3DERR_INVALIDCALL;
1198 Levels = wined3d_log2i(EdgeLength) + 1;
1199 TRACE("Calculated levels = %d\n", Levels);
1202 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1205 ERR("Out of memory\n");
1206 *ppCubeTexture = NULL;
1207 return WINED3DERR_OUTOFVIDEOMEMORY;
1210 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1211 hr = resource_init(&object->resource, WINED3DRTYPE_CUBETEXTURE, This, 0, Usage, Format, Pool, parent);
1214 WARN("Failed to initialize resource, returning %#x\n", hr);
1215 HeapFree(GetProcessHeap(), 0, object);
1216 *ppCubeTexture = NULL;
1220 TRACE("(%p) : Created resource %p\n", This, object);
1222 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1224 basetexture_init(&object->baseTexture, Levels, Usage);
1226 TRACE("(%p) Create Cube Texture\n", This);
1228 /* Find the nearest pow2 match */
1230 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1232 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
1233 /* Precalculated scaling for 'faked' non power of two texture coords */
1234 object->baseTexture.pow2Matrix[ 0] = 1.0;
1235 object->baseTexture.pow2Matrix[ 5] = 1.0;
1236 object->baseTexture.pow2Matrix[10] = 1.0;
1237 object->baseTexture.pow2Matrix[15] = 1.0;
1239 /* Precalculated scaling for 'faked' non power of two texture coords */
1240 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1241 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1242 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1243 object->baseTexture.pow2Matrix[15] = 1.0;
1246 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1247 object->baseTexture.minMipLookup = minMipLookup;
1248 object->baseTexture.magLookup = magLookup;
1250 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1251 object->baseTexture.magLookup = magLookup_noFilter;
1254 /* Generate all the surfaces */
1256 for (i = 0; i < object->baseTexture.levels; i++) {
1258 /* Create the 6 faces */
1259 for (j = 0; j < 6; j++) {
1260 static const GLenum cube_targets[6] = {
1261 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1262 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1263 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1264 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1265 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1266 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1269 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1270 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1274 FIXME("(%p) Failed to create surface\n",object);
1275 IWineD3DCubeTexture_Release((IWineD3DCubeTexture *)object);
1276 *ppCubeTexture = NULL;
1279 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1280 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1281 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1283 tmpW = max(1, tmpW >> 1);
1285 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
1287 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1288 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1292 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1294 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1295 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1296 const IWineD3DQueryVtbl *vtable;
1298 /* Just a check to see if we support this type of query */
1300 case WINED3DQUERYTYPE_OCCLUSION:
1301 TRACE("(%p) occlusion query\n", This);
1302 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1305 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1307 vtable = &IWineD3DOcclusionQuery_Vtbl;
1310 case WINED3DQUERYTYPE_EVENT:
1311 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1312 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1313 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1315 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1317 vtable = &IWineD3DEventQuery_Vtbl;
1321 case WINED3DQUERYTYPE_VCACHE:
1322 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1323 case WINED3DQUERYTYPE_VERTEXSTATS:
1324 case WINED3DQUERYTYPE_TIMESTAMP:
1325 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1326 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1327 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1328 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1329 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1330 case WINED3DQUERYTYPE_PIXELTIMINGS:
1331 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1332 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1334 /* Use the base Query vtable until we have a special one for each query */
1335 vtable = &IWineD3DQuery_Vtbl;
1336 FIXME("(%p) Unhandled query type %d\n", This, Type);
1338 if(NULL == ppQuery || hr != WINED3D_OK) {
1342 D3DCREATEOBJECTINSTANCE(object, Query)
1343 object->lpVtbl = vtable;
1344 object->type = Type;
1345 object->state = QUERY_CREATED;
1346 /* allocated the 'extended' data based on the type of query requested */
1348 case WINED3DQUERYTYPE_OCCLUSION:
1349 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1350 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1352 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1353 TRACE("(%p) Allocating data for an occlusion query\n", This);
1355 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1357 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1361 case WINED3DQUERYTYPE_EVENT:
1362 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1363 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1365 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1367 if(GL_SUPPORT(APPLE_FENCE)) {
1368 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1369 checkGLcall("glGenFencesAPPLE");
1370 } else if(GL_SUPPORT(NV_FENCE)) {
1371 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1372 checkGLcall("glGenFencesNV");
1377 case WINED3DQUERYTYPE_VCACHE:
1378 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1379 case WINED3DQUERYTYPE_VERTEXSTATS:
1380 case WINED3DQUERYTYPE_TIMESTAMP:
1381 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1382 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1383 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1384 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1385 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1386 case WINED3DQUERYTYPE_PIXELTIMINGS:
1387 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1388 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1390 object->extendedData = 0;
1391 FIXME("(%p) Unhandled query type %d\n",This , Type);
1393 TRACE("(%p) : Created Query %p\n", This, object);
1397 /*****************************************************************************
1398 * IWineD3DDeviceImpl_SetupFullscreenWindow
1400 * Helper function that modifies a HWND's Style and ExStyle for proper
1404 * iface: Pointer to the IWineD3DDevice interface
1405 * window: Window to setup
1407 *****************************************************************************/
1408 static LONG fullscreen_style(LONG orig_style) {
1409 LONG style = orig_style;
1410 style &= ~WS_CAPTION;
1411 style &= ~WS_THICKFRAME;
1413 /* Make sure the window is managed, otherwise we won't get keyboard input */
1414 style |= WS_POPUP | WS_SYSMENU;
1419 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1420 LONG exStyle = orig_exStyle;
1422 /* Filter out window decorations */
1423 exStyle &= ~WS_EX_WINDOWEDGE;
1424 exStyle &= ~WS_EX_CLIENTEDGE;
1429 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1432 LONG style, exStyle;
1433 /* Don't do anything if an original style is stored.
1434 * That shouldn't happen
1436 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1437 if (This->style || This->exStyle) {
1438 ERR("(%p): Want to change the window parameters of HWND %p, but "
1439 "another style is stored for restoration afterwards\n", This, window);
1442 /* Get the parameters and save them */
1443 style = GetWindowLongW(window, GWL_STYLE);
1444 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1445 This->style = style;
1446 This->exStyle = exStyle;
1448 style = fullscreen_style(style);
1449 exStyle = fullscreen_exStyle(exStyle);
1451 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1452 This->style, This->exStyle, style, exStyle);
1454 SetWindowLongW(window, GWL_STYLE, style);
1455 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1457 /* Inform the window about the update. */
1458 SetWindowPos(window, HWND_TOP, 0, 0,
1459 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1462 /*****************************************************************************
1463 * IWineD3DDeviceImpl_RestoreWindow
1465 * Helper function that restores a windows' properties when taking it out
1466 * of fullscreen mode
1469 * iface: Pointer to the IWineD3DDevice interface
1470 * window: Window to setup
1472 *****************************************************************************/
1473 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1475 LONG style, exStyle;
1477 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1478 * switch, do nothing
1480 if (!This->style && !This->exStyle) return;
1482 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1483 This, window, This->style, This->exStyle);
1485 style = GetWindowLongW(window, GWL_STYLE);
1486 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1488 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1489 * Some applications change it before calling Reset() when switching between windowed and
1490 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1492 if(style == fullscreen_style(This->style) &&
1493 exStyle == fullscreen_style(This->exStyle)) {
1494 SetWindowLongW(window, GWL_STYLE, This->style);
1495 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1498 /* Delete the old values */
1502 /* Inform the window about the update */
1503 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1504 0, 0, 0, 0, /* Pos, Size, ignored */
1505 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1508 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1509 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice* iface,
1510 WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1511 IUnknown* parent, D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1512 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil, WINED3DSURFTYPE surface_type)
1514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1517 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1519 IUnknown *bufferParent;
1520 BOOL displaymode_set = FALSE;
1521 WINED3DDISPLAYMODE Mode;
1522 const StaticPixelFormatDesc *formatDesc;
1524 TRACE("(%p) : Created Additional Swap Chain\n", This);
1526 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1527 * does a device hold a reference to a swap chain giving them a lifetime of the device
1528 * or does the swap chain notify the device of its destruction.
1529 *******************************/
1531 /* Check the params */
1532 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1533 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1534 return WINED3DERR_INVALIDCALL;
1535 } else if (pPresentationParameters->BackBufferCount > 1) {
1536 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");
1539 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1540 switch(surface_type) {
1542 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1544 case SURFACE_OPENGL:
1545 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1547 case SURFACE_UNKNOWN:
1548 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1549 return WINED3DERR_INVALIDCALL;
1552 /*********************
1553 * Lookup the window Handle and the relating X window handle
1554 ********************/
1556 /* Setup hwnd we are using, plus which display this equates to */
1557 object->win_handle = pPresentationParameters->hDeviceWindow;
1558 if (!object->win_handle) {
1559 object->win_handle = This->createParms.hFocusWindow;
1561 if(!pPresentationParameters->Windowed && object->win_handle) {
1562 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1563 pPresentationParameters->BackBufferWidth,
1564 pPresentationParameters->BackBufferHeight);
1567 hDc = GetDC(object->win_handle);
1568 TRACE("Using hDc %p\n", hDc);
1571 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1572 return WINED3DERR_NOTAVAILABLE;
1575 /* Get info on the current display setup */
1576 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1577 object->orig_width = Mode.Width;
1578 object->orig_height = Mode.Height;
1579 object->orig_fmt = Mode.Format;
1580 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1582 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1583 * then the corresponding dimension of the client area of the hDeviceWindow
1584 * (or the focus window, if hDeviceWindow is NULL) is taken.
1585 **********************/
1587 if (pPresentationParameters->Windowed &&
1588 ((pPresentationParameters->BackBufferWidth == 0) ||
1589 (pPresentationParameters->BackBufferHeight == 0) ||
1590 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1593 GetClientRect(object->win_handle, &Rect);
1595 if (pPresentationParameters->BackBufferWidth == 0) {
1596 pPresentationParameters->BackBufferWidth = Rect.right;
1597 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1599 if (pPresentationParameters->BackBufferHeight == 0) {
1600 pPresentationParameters->BackBufferHeight = Rect.bottom;
1601 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1603 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1604 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1605 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1609 /* Put the correct figures in the presentation parameters */
1610 TRACE("Copying across presentation parameters\n");
1611 object->presentParms = *pPresentationParameters;
1613 TRACE("calling rendertarget CB\n");
1614 hr = D3DCB_CreateRenderTarget(This->parent,
1616 object->presentParms.BackBufferWidth,
1617 object->presentParms.BackBufferHeight,
1618 object->presentParms.BackBufferFormat,
1619 object->presentParms.MultiSampleType,
1620 object->presentParms.MultiSampleQuality,
1621 TRUE /* Lockable */,
1622 &object->frontBuffer,
1623 NULL /* pShared (always null)*/);
1624 if (SUCCEEDED(hr)) {
1625 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1626 if(surface_type == SURFACE_OPENGL) {
1627 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1630 ERR("Failed to create the front buffer\n");
1634 /*********************
1635 * Windowed / Fullscreen
1636 *******************/
1639 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1640 * so we should really check to see if there is a fullscreen swapchain already
1641 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1642 **************************************/
1644 if (!pPresentationParameters->Windowed) {
1645 WINED3DDISPLAYMODE mode;
1648 /* Change the display settings */
1649 mode.Width = pPresentationParameters->BackBufferWidth;
1650 mode.Height = pPresentationParameters->BackBufferHeight;
1651 mode.Format = pPresentationParameters->BackBufferFormat;
1652 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1654 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1655 displaymode_set = TRUE;
1659 * Create an opengl context for the display visual
1660 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1661 * use different properties after that point in time. FIXME: How to handle when requested format
1662 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1663 * it chooses is identical to the one already being used!
1664 **********************************/
1665 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1667 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1668 if(!object->context) {
1669 ERR("Failed to create the context array\n");
1673 object->num_contexts = 1;
1675 if(surface_type == SURFACE_OPENGL) {
1676 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1677 if (!object->context[0]) {
1678 ERR("Failed to create a new context\n");
1679 hr = WINED3DERR_NOTAVAILABLE;
1682 TRACE("Context created (HWND=%p, glContext=%p)\n",
1683 object->win_handle, object->context[0]->glCtx);
1687 /*********************
1688 * Create the back, front and stencil buffers
1689 *******************/
1690 if(object->presentParms.BackBufferCount > 0) {
1693 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1694 if(!object->backBuffer) {
1695 ERR("Out of memory\n");
1700 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1701 TRACE("calling rendertarget CB\n");
1702 hr = D3DCB_CreateRenderTarget(This->parent,
1704 object->presentParms.BackBufferWidth,
1705 object->presentParms.BackBufferHeight,
1706 object->presentParms.BackBufferFormat,
1707 object->presentParms.MultiSampleType,
1708 object->presentParms.MultiSampleQuality,
1709 TRUE /* Lockable */,
1710 &object->backBuffer[i],
1711 NULL /* pShared (always null)*/);
1713 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1715 ERR("Cannot create new back buffer\n");
1718 if(surface_type == SURFACE_OPENGL) {
1720 glDrawBuffer(GL_BACK);
1721 checkGLcall("glDrawBuffer(GL_BACK)");
1726 object->backBuffer = NULL;
1728 /* Single buffering - draw to front buffer */
1729 if(surface_type == SURFACE_OPENGL) {
1731 glDrawBuffer(GL_FRONT);
1732 checkGLcall("glDrawBuffer(GL_FRONT)");
1737 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1738 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1739 TRACE("Creating depth stencil buffer\n");
1740 if (This->auto_depth_stencil_buffer == NULL ) {
1741 hr = D3DCB_CreateDepthStencil(This->parent,
1743 object->presentParms.BackBufferWidth,
1744 object->presentParms.BackBufferHeight,
1745 object->presentParms.AutoDepthStencilFormat,
1746 object->presentParms.MultiSampleType,
1747 object->presentParms.MultiSampleQuality,
1748 FALSE /* FIXME: Discard */,
1749 &This->auto_depth_stencil_buffer,
1750 NULL /* pShared (always null)*/ );
1751 if (SUCCEEDED(hr)) {
1752 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1754 ERR("Failed to create the auto depth stencil\n");
1760 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1762 TRACE("Created swapchain %p\n", object);
1763 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1767 if (displaymode_set) {
1771 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1774 /* Change the display settings */
1775 memset(&devmode, 0, sizeof(devmode));
1776 devmode.dmSize = sizeof(devmode);
1777 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1778 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1779 devmode.dmPelsWidth = object->orig_width;
1780 devmode.dmPelsHeight = object->orig_height;
1781 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1784 if (object->backBuffer) {
1786 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1787 if(object->backBuffer[i]) {
1788 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1789 IUnknown_Release(bufferParent); /* once for the get parent */
1790 if (IUnknown_Release(bufferParent) > 0) {
1791 FIXME("(%p) Something's still holding the back buffer\n",This);
1795 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1796 object->backBuffer = NULL;
1798 if(object->context && object->context[0])
1799 DestroyContext(This, object->context[0]);
1800 if(object->frontBuffer) {
1801 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1802 IUnknown_Release(bufferParent); /* once for the get parent */
1803 if (IUnknown_Release(bufferParent) > 0) {
1804 FIXME("(%p) Something's still holding the front buffer\n",This);
1807 HeapFree(GetProcessHeap(), 0, object);
1811 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1812 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1814 TRACE("(%p)\n", This);
1816 return This->NumberOfSwapChains;
1819 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1821 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1823 if(iSwapChain < This->NumberOfSwapChains) {
1824 *pSwapChain = This->swapchains[iSwapChain];
1825 IWineD3DSwapChain_AddRef(*pSwapChain);
1826 TRACE("(%p) returning %p\n", This, *pSwapChain);
1829 TRACE("Swapchain out of range\n");
1831 return WINED3DERR_INVALIDCALL;
1836 * Vertex Declaration
1838 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1839 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1841 IWineD3DVertexDeclarationImpl *object = NULL;
1842 HRESULT hr = WINED3D_OK;
1844 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1845 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1847 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1849 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1851 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1852 *ppVertexDeclaration = NULL;
1858 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1859 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1861 unsigned int idx, idx2;
1862 unsigned int offset;
1863 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1864 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1865 BOOL has_blend_idx = has_blend &&
1866 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1867 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1868 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1869 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1870 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1871 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1872 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1874 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1875 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1877 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1878 WINED3DVERTEXELEMENT *elements = NULL;
1881 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1882 if (has_blend_idx) num_blends--;
1884 /* Compute declaration size */
1885 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1886 has_psize + has_diffuse + has_specular + num_textures + 1;
1888 /* convert the declaration */
1889 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1893 elements[size-1] = end_element;
1896 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1897 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1898 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1900 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1901 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1902 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1905 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1906 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1908 elements[idx].UsageIndex = 0;
1911 if (has_blend && (num_blends > 0)) {
1912 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1913 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1915 switch(num_blends) {
1916 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
1917 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
1918 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
1919 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
1921 ERR("Unexpected amount of blend values: %u\n", num_blends);
1924 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1925 elements[idx].UsageIndex = 0;
1928 if (has_blend_idx) {
1929 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1930 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1931 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1932 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1933 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1935 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1936 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1937 elements[idx].UsageIndex = 0;
1941 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1942 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1943 elements[idx].UsageIndex = 0;
1947 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1948 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1949 elements[idx].UsageIndex = 0;
1953 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1954 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1955 elements[idx].UsageIndex = 0;
1959 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1960 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1961 elements[idx].UsageIndex = 1;
1964 for (idx2 = 0; idx2 < num_textures; idx2++) {
1965 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1966 switch (numcoords) {
1967 case WINED3DFVF_TEXTUREFORMAT1:
1968 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1970 case WINED3DFVF_TEXTUREFORMAT2:
1971 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1973 case WINED3DFVF_TEXTUREFORMAT3:
1974 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1976 case WINED3DFVF_TEXTUREFORMAT4:
1977 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1980 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1981 elements[idx].UsageIndex = idx2;
1985 /* Now compute offsets, and initialize the rest of the fields */
1986 for (idx = 0, offset = 0; idx < size-1; idx++) {
1987 elements[idx].Stream = 0;
1988 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1989 elements[idx].Offset = offset;
1990 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1993 *ppVertexElements = elements;
1997 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1998 WINED3DVERTEXELEMENT* elements = NULL;
1999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2003 size = ConvertFvfToDeclaration(This, Fvf, &elements);
2004 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
2006 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
2007 HeapFree(GetProcessHeap(), 0, elements);
2008 if (hr != S_OK) return hr;
2013 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
2014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2015 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
2016 HRESULT hr = WINED3D_OK;
2018 if (!pFunction) return WINED3DERR_INVALIDCALL;
2020 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2023 ERR("Out of memory\n");
2024 *ppVertexShader = NULL;
2025 return WINED3DERR_OUTOFVIDEOMEMORY;
2028 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
2029 object->parent = parent;
2030 shader_init(&object->baseShader, iface, IWineD3DVertexShaderImpl_shader_ins);
2031 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2032 *ppVertexShader = (IWineD3DVertexShader *)object;
2034 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
2036 if (vertex_declaration) {
2037 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
2040 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
2043 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2044 IWineD3DVertexShader_Release(*ppVertexShader);
2045 *ppVertexShader = NULL;
2052 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
2053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2054 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2055 HRESULT hr = WINED3D_OK;
2057 if (!pFunction) return WINED3DERR_INVALIDCALL;
2059 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2062 ERR("Out of memory\n");
2063 *ppPixelShader = NULL;
2064 return WINED3DERR_OUTOFVIDEOMEMORY;
2067 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2068 object->parent = parent;
2069 shader_init(&object->baseShader, iface, IWineD3DPixelShaderImpl_shader_ins);
2070 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2071 *ppPixelShader = (IWineD3DPixelShader *)object;
2073 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2075 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
2078 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2079 IWineD3DPixelShader_Release(*ppPixelShader);
2080 *ppPixelShader = NULL;
2087 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2088 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2091 IWineD3DPaletteImpl *object;
2093 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2095 /* Create the new object */
2096 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2098 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2099 return E_OUTOFMEMORY;
2102 object->lpVtbl = &IWineD3DPalette_Vtbl;
2104 object->Flags = Flags;
2105 object->parent = Parent;
2106 object->wineD3DDevice = This;
2107 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2108 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2111 HeapFree( GetProcessHeap(), 0, object);
2112 return E_OUTOFMEMORY;
2115 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2117 IWineD3DPalette_Release((IWineD3DPalette *) object);
2121 *Palette = (IWineD3DPalette *) object;
2126 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2130 HDC dcb = NULL, dcs = NULL;
2131 WINEDDCOLORKEY colorkey;
2133 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2136 GetObjectA(hbm, sizeof(BITMAP), &bm);
2137 dcb = CreateCompatibleDC(NULL);
2139 SelectObject(dcb, hbm);
2143 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2144 * couldn't be loaded
2146 memset(&bm, 0, sizeof(bm));
2151 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2152 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2153 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
2155 ERR("Wine logo requested, but failed to create surface\n");
2160 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2161 if(FAILED(hr)) goto out;
2162 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2163 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2165 colorkey.dwColorSpaceLowValue = 0;
2166 colorkey.dwColorSpaceHighValue = 0;
2167 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2169 /* Fill the surface with a white color to show that wined3d is there */
2170 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2183 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2185 /* Under DirectX you can have texture stage operations even if no texture is
2186 bound, whereas opengl will only do texture operations when a valid texture is
2187 bound. We emulate this by creating dummy textures and binding them to each
2188 texture stage, but disable all stages by default. Hence if a stage is enabled
2189 then the default texture will kick in until replaced by a SetTexture call */
2192 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2193 /* The dummy texture does not have client storage backing */
2194 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2195 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2197 for (i = 0; i < GL_LIMITS(textures); i++) {
2198 GLubyte white = 255;
2200 /* Make appropriate texture active */
2201 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2202 checkGLcall("glActiveTextureARB");
2204 /* Generate an opengl texture name */
2205 glGenTextures(1, &This->dummyTextureName[i]);
2206 checkGLcall("glGenTextures");
2207 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2209 /* Generate a dummy 2d texture (not using 1d because they cause many
2210 * DRI drivers fall back to sw) */
2211 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2212 checkGLcall("glBindTexture");
2214 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2215 checkGLcall("glTexImage2D");
2217 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2218 /* Reenable because if supported it is enabled by default */
2219 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2220 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2226 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2228 IWineD3DSwapChainImpl *swapchain = NULL;
2233 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateSwapChain);
2234 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2235 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2237 /* TODO: Test if OpenGL is compiled in and loaded */
2239 TRACE("(%p) : Creating stateblock\n", This);
2240 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2241 hr = IWineD3DDevice_CreateStateBlock(iface,
2243 (IWineD3DStateBlock **)&This->stateBlock,
2245 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2246 WARN("Failed to create stateblock\n");
2249 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2250 This->updateStateBlock = This->stateBlock;
2251 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2253 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2254 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2256 This->NumberOfPalettes = 1;
2257 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2258 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2259 ERR("Out of memory!\n");
2262 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2263 if(!This->palettes[0]) {
2264 ERR("Out of memory!\n");
2267 for (i = 0; i < 256; ++i) {
2268 This->palettes[0][i].peRed = 0xFF;
2269 This->palettes[0][i].peGreen = 0xFF;
2270 This->palettes[0][i].peBlue = 0xFF;
2271 This->palettes[0][i].peFlags = 0xFF;
2273 This->currentPalette = 0;
2275 /* Initialize the texture unit mapping to a 1:1 mapping */
2276 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2277 if (state < GL_LIMITS(fragment_samplers)) {
2278 This->texUnitMap[state] = state;
2279 This->rev_tex_unit_map[state] = state;
2281 This->texUnitMap[state] = -1;
2282 This->rev_tex_unit_map[state] = -1;
2286 /* Setup the implicit swapchain */
2287 TRACE("Creating implicit swapchain\n");
2288 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2289 if (FAILED(hr) || !swapchain) {
2290 WARN("Failed to create implicit swapchain\n");
2294 This->NumberOfSwapChains = 1;
2295 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2296 if(!This->swapchains) {
2297 ERR("Out of memory!\n");
2300 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2302 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2303 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2304 This->render_targets[0] = swapchain->backBuffer[0];
2305 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2308 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2309 This->render_targets[0] = swapchain->frontBuffer;
2310 This->lastActiveRenderTarget = swapchain->frontBuffer;
2312 IWineD3DSurface_AddRef(This->render_targets[0]);
2313 This->activeContext = swapchain->context[0];
2314 This->lastThread = GetCurrentThreadId();
2316 /* Depth Stencil support */
2317 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2318 if (NULL != This->stencilBufferTarget) {
2319 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2322 hr = This->shader_backend->shader_alloc_private(iface);
2324 TRACE("Shader private data couldn't be allocated\n");
2327 hr = This->frag_pipe->alloc_private(iface);
2329 TRACE("Fragment pipeline private data couldn't be allocated\n");
2332 hr = This->blitter->alloc_private(iface);
2334 TRACE("Blitter private data couldn't be allocated\n");
2338 /* Set up some starting GL setup */
2340 /* Setup all the devices defaults */
2341 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2342 create_dummy_textures(This);
2346 /* Initialize the current view state */
2347 This->view_ident = 1;
2348 This->contexts[0]->last_was_rhw = 0;
2349 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2350 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2352 switch(wined3d_settings.offscreen_rendering_mode) {
2355 This->offscreenBuffer = GL_BACK;
2358 case ORM_BACKBUFFER:
2360 if(This->activeContext->aux_buffers > 0) {
2361 TRACE("Using auxilliary buffer for offscreen rendering\n");
2362 This->offscreenBuffer = GL_AUX0;
2364 TRACE("Using back buffer for offscreen rendering\n");
2365 This->offscreenBuffer = GL_BACK;
2370 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2373 /* Clear the screen */
2374 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2375 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2378 This->d3d_initialized = TRUE;
2380 if(wined3d_settings.logo) {
2381 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2383 This->highest_dirty_ps_const = 0;
2384 This->highest_dirty_vs_const = 0;
2388 HeapFree(GetProcessHeap(), 0, This->render_targets);
2389 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2390 HeapFree(GetProcessHeap(), 0, This->swapchains);
2391 This->NumberOfSwapChains = 0;
2392 if(This->palettes) {
2393 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2394 HeapFree(GetProcessHeap(), 0, This->palettes);
2396 This->NumberOfPalettes = 0;
2398 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2400 if(This->stateBlock) {
2401 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2402 This->stateBlock = NULL;
2404 if (This->blit_priv) {
2405 This->blitter->free_private(iface);
2407 if (This->fragment_priv) {
2408 This->frag_pipe->free_private(iface);
2410 if (This->shader_priv) {
2411 This->shader_backend->shader_free_private(iface);
2416 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2418 IWineD3DSwapChainImpl *swapchain = NULL;
2421 /* Setup the implicit swapchain */
2422 TRACE("Creating implicit swapchain\n");
2423 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2424 if (FAILED(hr) || !swapchain) {
2425 WARN("Failed to create implicit swapchain\n");
2429 This->NumberOfSwapChains = 1;
2430 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2431 if(!This->swapchains) {
2432 ERR("Out of memory!\n");
2435 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2439 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2443 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2447 TRACE("(%p)\n", This);
2449 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2451 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2452 * it was created. Thus make sure a context is active for the glDelete* calls
2454 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2456 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2458 TRACE("Deleting high order patches\n");
2459 for(i = 0; i < PATCHMAP_SIZE; i++) {
2460 struct list *e1, *e2;
2461 struct WineD3DRectPatch *patch;
2462 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2463 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2464 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2468 /* Delete the palette conversion shader if it is around */
2469 if(This->paletteConversionShader) {
2471 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2473 This->paletteConversionShader = 0;
2476 /* Delete the pbuffer context if there is any */
2477 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2479 /* Delete the mouse cursor texture */
2480 if(This->cursorTexture) {
2482 glDeleteTextures(1, &This->cursorTexture);
2484 This->cursorTexture = 0;
2487 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2488 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2490 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2491 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2494 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2495 * private data, it might contain opengl pointers
2497 if(This->depth_blt_texture) {
2498 glDeleteTextures(1, &This->depth_blt_texture);
2499 This->depth_blt_texture = 0;
2501 if (This->depth_blt_rb) {
2502 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2503 This->depth_blt_rb = 0;
2504 This->depth_blt_rb_w = 0;
2505 This->depth_blt_rb_h = 0;
2508 /* Release the update stateblock */
2509 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2510 if(This->updateStateBlock != This->stateBlock)
2511 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2513 This->updateStateBlock = NULL;
2515 { /* because were not doing proper internal refcounts releasing the primary state block
2516 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2517 to set this->stateBlock = NULL; first */
2518 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2519 This->stateBlock = NULL;
2521 /* Release the stateblock */
2522 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2523 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2527 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2528 This->blitter->free_private(iface);
2529 This->frag_pipe->free_private(iface);
2530 This->shader_backend->shader_free_private(iface);
2532 /* Release the buffers (with sanity checks)*/
2533 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2534 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2535 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2536 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2538 This->stencilBufferTarget = NULL;
2540 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2541 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2542 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2544 TRACE("Setting rendertarget to NULL\n");
2545 This->render_targets[0] = NULL;
2547 if (This->auto_depth_stencil_buffer) {
2548 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2549 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2551 This->auto_depth_stencil_buffer = NULL;
2554 for(i=0; i < This->NumberOfSwapChains; i++) {
2555 TRACE("Releasing the implicit swapchain %d\n", i);
2556 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2557 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2561 HeapFree(GetProcessHeap(), 0, This->swapchains);
2562 This->swapchains = NULL;
2563 This->NumberOfSwapChains = 0;
2565 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2566 HeapFree(GetProcessHeap(), 0, This->palettes);
2567 This->palettes = NULL;
2568 This->NumberOfPalettes = 0;
2570 HeapFree(GetProcessHeap(), 0, This->render_targets);
2571 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2572 This->render_targets = NULL;
2573 This->draw_buffers = NULL;
2575 This->d3d_initialized = FALSE;
2579 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2583 for(i=0; i < This->NumberOfSwapChains; i++) {
2584 TRACE("Releasing the implicit swapchain %d\n", i);
2585 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2586 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2590 HeapFree(GetProcessHeap(), 0, This->swapchains);
2591 This->swapchains = NULL;
2592 This->NumberOfSwapChains = 0;
2596 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2597 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2598 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2600 * There is no way to deactivate thread safety once it is enabled.
2602 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2605 /*For now just store the flag(needed in case of ddraw) */
2606 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2611 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2612 const WINED3DDISPLAYMODE* pMode) {
2614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2616 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2619 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2621 /* Resize the screen even without a window:
2622 * The app could have unset it with SetCooperativeLevel, but not called
2623 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2624 * but we don't have any hwnd
2627 memset(&devmode, 0, sizeof(devmode));
2628 devmode.dmSize = sizeof(devmode);
2629 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2630 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2631 devmode.dmPelsWidth = pMode->Width;
2632 devmode.dmPelsHeight = pMode->Height;
2634 devmode.dmDisplayFrequency = pMode->RefreshRate;
2635 if (pMode->RefreshRate != 0) {
2636 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2639 /* Only change the mode if necessary */
2640 if( (This->ddraw_width == pMode->Width) &&
2641 (This->ddraw_height == pMode->Height) &&
2642 (This->ddraw_format == pMode->Format) &&
2643 (pMode->RefreshRate == 0) ) {
2647 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2648 if (ret != DISP_CHANGE_SUCCESSFUL) {
2649 if(devmode.dmDisplayFrequency != 0) {
2650 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2651 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2652 devmode.dmDisplayFrequency = 0;
2653 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2655 if(ret != DISP_CHANGE_SUCCESSFUL) {
2656 return WINED3DERR_NOTAVAILABLE;
2660 /* Store the new values */
2661 This->ddraw_width = pMode->Width;
2662 This->ddraw_height = pMode->Height;
2663 This->ddraw_format = pMode->Format;
2665 /* And finally clip mouse to our screen */
2666 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2667 ClipCursor(&clip_rc);
2672 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2674 *ppD3D= This->wineD3D;
2675 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2676 IWineD3D_AddRef(*ppD3D);
2680 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2683 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2684 (This->adapter->TextureRam/(1024*1024)),
2685 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2686 /* return simulated texture memory left */
2687 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2691 * Get / Set Stream Source
2693 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2695 IWineD3DVertexBuffer *oldSrc;
2697 if (StreamNumber >= MAX_STREAMS) {
2698 WARN("Stream out of range %d\n", StreamNumber);
2699 return WINED3DERR_INVALIDCALL;
2700 } else if(OffsetInBytes & 0x3) {
2701 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2702 return WINED3DERR_INVALIDCALL;
2705 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2706 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2708 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2710 if(oldSrc == pStreamData &&
2711 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2712 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2713 TRACE("Application is setting the old values over, nothing to do\n");
2717 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2719 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2720 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2723 /* Handle recording of state blocks */
2724 if (This->isRecordingState) {
2725 TRACE("Recording... not performing anything\n");
2726 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2727 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2731 /* Need to do a getParent and pass the references up */
2732 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2733 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2734 so for now, just count internally */
2735 if (pStreamData != NULL) {
2736 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2737 InterlockedIncrement(&vbImpl->bindCount);
2738 IWineD3DVertexBuffer_AddRef(pStreamData);
2740 if (oldSrc != NULL) {
2741 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2742 IWineD3DVertexBuffer_Release(oldSrc);
2745 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2750 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2753 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2754 This->stateBlock->streamSource[StreamNumber],
2755 This->stateBlock->streamOffset[StreamNumber],
2756 This->stateBlock->streamStride[StreamNumber]);
2758 if (StreamNumber >= MAX_STREAMS) {
2759 WARN("Stream out of range %d\n", StreamNumber);
2760 return WINED3DERR_INVALIDCALL;
2762 *pStream = This->stateBlock->streamSource[StreamNumber];
2763 *pStride = This->stateBlock->streamStride[StreamNumber];
2765 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2768 if (*pStream != NULL) {
2769 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2774 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2776 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2777 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2779 /* Verify input at least in d3d9 this is invalid*/
2780 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2781 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2782 return WINED3DERR_INVALIDCALL;
2784 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2785 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2786 return WINED3DERR_INVALIDCALL;
2789 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2790 return WINED3DERR_INVALIDCALL;
2793 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2794 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2796 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2797 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2799 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2800 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2801 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2807 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2810 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2811 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2813 TRACE("(%p) : returning %d\n", This, *Divider);
2819 * Get / Set & Multiply Transform
2821 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2824 /* Most of this routine, comments included copied from ddraw tree initially: */
2825 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2827 /* Handle recording of state blocks */
2828 if (This->isRecordingState) {
2829 TRACE("Recording... not performing anything\n");
2830 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2831 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2836 * If the new matrix is the same as the current one,
2837 * we cut off any further processing. this seems to be a reasonable
2838 * optimization because as was noticed, some apps (warcraft3 for example)
2839 * tend towards setting the same matrix repeatedly for some reason.
2841 * From here on we assume that the new matrix is different, wherever it matters.
2843 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2844 TRACE("The app is setting the same matrix over again\n");
2847 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2851 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2852 where ViewMat = Camera space, WorldMat = world space.
2854 In OpenGL, camera and world space is combined into GL_MODELVIEW
2855 matrix. The Projection matrix stay projection matrix.
2858 /* Capture the times we can just ignore the change for now */
2859 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2860 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2861 /* Handled by the state manager */
2864 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2868 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2870 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2871 *pMatrix = This->stateBlock->transforms[State];
2875 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2876 const WINED3DMATRIX *mat = NULL;
2879 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2880 * below means it will be recorded in a state block change, but it
2881 * works regardless where it is recorded.
2882 * If this is found to be wrong, change to StateBlock.
2884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2885 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2887 if (State <= HIGHEST_TRANSFORMSTATE)
2889 mat = &This->updateStateBlock->transforms[State];
2891 FIXME("Unhandled transform state!!\n");
2894 multiply_matrix(&temp, mat, pMatrix);
2896 /* Apply change via set transform - will reapply to eg. lights this way */
2897 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2903 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2904 you can reference any indexes you want as long as that number max are enabled at any
2905 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2906 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2907 but when recording, just build a chain pretty much of commands to be replayed. */
2909 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2911 PLIGHTINFOEL *object = NULL;
2912 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2916 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2918 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2922 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2923 return WINED3DERR_INVALIDCALL;
2926 switch(pLight->Type) {
2927 case WINED3DLIGHT_POINT:
2928 case WINED3DLIGHT_SPOT:
2929 case WINED3DLIGHT_PARALLELPOINT:
2930 case WINED3DLIGHT_GLSPOT:
2931 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2934 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2935 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2936 return WINED3DERR_INVALIDCALL;
2940 case WINED3DLIGHT_DIRECTIONAL:
2941 /* Ignores attenuation */
2945 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2946 return WINED3DERR_INVALIDCALL;
2949 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2950 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2951 if(object->OriginalIndex == Index) break;
2956 TRACE("Adding new light\n");
2957 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2959 ERR("Out of memory error when allocating a light\n");
2960 return E_OUTOFMEMORY;
2962 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2963 object->glIndex = -1;
2964 object->OriginalIndex = Index;
2965 object->changed = TRUE;
2968 /* Initialize the object */
2969 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,
2970 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2971 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2972 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2973 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2974 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2975 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2977 /* Save away the information */
2978 object->OriginalParms = *pLight;
2980 switch (pLight->Type) {
2981 case WINED3DLIGHT_POINT:
2983 object->lightPosn[0] = pLight->Position.x;
2984 object->lightPosn[1] = pLight->Position.y;
2985 object->lightPosn[2] = pLight->Position.z;
2986 object->lightPosn[3] = 1.0f;
2987 object->cutoff = 180.0f;
2991 case WINED3DLIGHT_DIRECTIONAL:
2993 object->lightPosn[0] = -pLight->Direction.x;
2994 object->lightPosn[1] = -pLight->Direction.y;
2995 object->lightPosn[2] = -pLight->Direction.z;
2996 object->lightPosn[3] = 0.0;
2997 object->exponent = 0.0f;
2998 object->cutoff = 180.0f;
3001 case WINED3DLIGHT_SPOT:
3003 object->lightPosn[0] = pLight->Position.x;
3004 object->lightPosn[1] = pLight->Position.y;
3005 object->lightPosn[2] = pLight->Position.z;
3006 object->lightPosn[3] = 1.0;
3009 object->lightDirn[0] = pLight->Direction.x;
3010 object->lightDirn[1] = pLight->Direction.y;
3011 object->lightDirn[2] = pLight->Direction.z;
3012 object->lightDirn[3] = 1.0;
3015 * opengl-ish and d3d-ish spot lights use too different models for the
3016 * light "intensity" as a function of the angle towards the main light direction,
3017 * so we only can approximate very roughly.
3018 * however spot lights are rather rarely used in games (if ever used at all).
3019 * furthermore if still used, probably nobody pays attention to such details.
3021 if (pLight->Falloff == 0) {
3022 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3023 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3024 * will always be 1.0 for both of them, and we don't have to care for the
3025 * rest of the rather complex calculation
3027 object->exponent = 0;
3029 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3030 if (rho < 0.0001) rho = 0.0001f;
3031 object->exponent = -0.3/log(cos(rho/2));
3033 if (object->exponent > 128.0) {
3034 object->exponent = 128.0;
3036 object->cutoff = pLight->Phi*90/M_PI;
3042 FIXME("Unrecognized light type %d\n", pLight->Type);
3045 /* Update the live definitions if the light is currently assigned a glIndex */
3046 if (object->glIndex != -1 && !This->isRecordingState) {
3047 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3052 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3053 PLIGHTINFOEL *lightInfo = NULL;
3054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3055 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3057 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3059 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3060 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3061 if(lightInfo->OriginalIndex == Index) break;
3065 if (lightInfo == NULL) {
3066 TRACE("Light information requested but light not defined\n");
3067 return WINED3DERR_INVALIDCALL;
3070 *pLight = lightInfo->OriginalParms;
3075 * Get / Set Light Enable
3076 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3078 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3079 PLIGHTINFOEL *lightInfo = NULL;
3080 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3081 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3083 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3085 /* Tests show true = 128...not clear why */
3086 Enable = Enable? 128: 0;
3088 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3089 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3090 if(lightInfo->OriginalIndex == Index) break;
3093 TRACE("Found light: %p\n", lightInfo);
3095 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3096 if (lightInfo == NULL) {
3098 TRACE("Light enabled requested but light not defined, so defining one!\n");
3099 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3101 /* Search for it again! Should be fairly quick as near head of list */
3102 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3103 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3104 if(lightInfo->OriginalIndex == Index) break;
3107 if (lightInfo == NULL) {
3108 FIXME("Adding default lights has failed dismally\n");
3109 return WINED3DERR_INVALIDCALL;
3113 lightInfo->enabledChanged = TRUE;
3115 if(lightInfo->glIndex != -1) {
3116 if(!This->isRecordingState) {
3117 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3120 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3121 lightInfo->glIndex = -1;
3123 TRACE("Light already disabled, nothing to do\n");
3125 lightInfo->enabled = FALSE;
3127 lightInfo->enabled = TRUE;
3128 if (lightInfo->glIndex != -1) {
3130 TRACE("Nothing to do as light was enabled\n");
3133 /* Find a free gl light */
3134 for(i = 0; i < This->maxConcurrentLights; i++) {
3135 if(This->updateStateBlock->activeLights[i] == NULL) {
3136 This->updateStateBlock->activeLights[i] = lightInfo;
3137 lightInfo->glIndex = i;
3141 if(lightInfo->glIndex == -1) {
3142 /* Our tests show that Windows returns D3D_OK in this situation, even with
3143 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3144 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3145 * as well for those lights.
3147 * TODO: Test how this affects rendering
3149 WARN("Too many concurrently active lights\n");
3153 /* i == lightInfo->glIndex */
3154 if(!This->isRecordingState) {
3155 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3163 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3165 PLIGHTINFOEL *lightInfo = NULL;
3166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3168 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3169 TRACE("(%p) : for idx(%d)\n", This, Index);
3171 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3172 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3173 if(lightInfo->OriginalIndex == Index) break;
3177 if (lightInfo == NULL) {
3178 TRACE("Light enabled state requested but light not defined\n");
3179 return WINED3DERR_INVALIDCALL;
3181 /* true is 128 according to SetLightEnable */
3182 *pEnable = lightInfo->enabled ? 128 : 0;
3187 * Get / Set Clip Planes
3189 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3191 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3193 /* Validate Index */
3194 if (Index >= GL_LIMITS(clipplanes)) {
3195 TRACE("Application has requested clipplane this device doesn't support\n");
3196 return WINED3DERR_INVALIDCALL;
3199 This->updateStateBlock->changed.clipplane |= 1 << Index;
3201 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3202 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3203 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3204 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3205 TRACE("Application is setting old values over, nothing to do\n");
3209 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3210 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3211 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3212 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3214 /* Handle recording of state blocks */
3215 if (This->isRecordingState) {
3216 TRACE("Recording... not performing anything\n");
3220 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3225 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3227 TRACE("(%p) : for idx %d\n", This, Index);
3229 /* Validate Index */
3230 if (Index >= GL_LIMITS(clipplanes)) {
3231 TRACE("Application has requested clipplane this device doesn't support\n");
3232 return WINED3DERR_INVALIDCALL;
3235 pPlane[0] = This->stateBlock->clipplane[Index][0];
3236 pPlane[1] = This->stateBlock->clipplane[Index][1];
3237 pPlane[2] = This->stateBlock->clipplane[Index][2];
3238 pPlane[3] = This->stateBlock->clipplane[Index][3];
3243 * Get / Set Clip Plane Status
3244 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3246 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3248 FIXME("(%p) : stub\n", This);
3249 if (NULL == pClipStatus) {
3250 return WINED3DERR_INVALIDCALL;
3252 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3253 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3257 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3259 FIXME("(%p) : stub\n", This);
3260 if (NULL == pClipStatus) {
3261 return WINED3DERR_INVALIDCALL;
3263 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3264 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3269 * Get / Set Material
3271 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3274 This->updateStateBlock->changed.material = TRUE;
3275 This->updateStateBlock->material = *pMaterial;
3277 /* Handle recording of state blocks */
3278 if (This->isRecordingState) {
3279 TRACE("Recording... not performing anything\n");
3283 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3287 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3289 *pMaterial = This->updateStateBlock->material;
3290 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3291 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3292 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3293 pMaterial->Ambient.b, pMaterial->Ambient.a);
3294 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3295 pMaterial->Specular.b, pMaterial->Specular.a);
3296 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3297 pMaterial->Emissive.b, pMaterial->Emissive.a);
3298 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3306 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3308 IWineD3DIndexBuffer *oldIdxs;
3310 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3311 oldIdxs = This->updateStateBlock->pIndexData;
3313 This->updateStateBlock->changed.indices = TRUE;
3314 This->updateStateBlock->pIndexData = pIndexData;
3316 /* Handle recording of state blocks */
3317 if (This->isRecordingState) {
3318 TRACE("Recording... not performing anything\n");
3319 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3320 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3324 if(oldIdxs != pIndexData) {
3325 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3326 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3327 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3332 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3335 *ppIndexData = This->stateBlock->pIndexData;
3337 /* up ref count on ppindexdata */
3339 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3340 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3342 TRACE("(%p) No index data set\n", This);
3344 TRACE("Returning %p\n", *ppIndexData);
3349 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3350 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3352 TRACE("(%p)->(%d)\n", This, BaseIndex);
3354 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3355 TRACE("Application is setting the old value over, nothing to do\n");
3359 This->updateStateBlock->baseVertexIndex = BaseIndex;
3361 if (This->isRecordingState) {
3362 TRACE("Recording... not performing anything\n");
3365 /* The base vertex index affects the stream sources */
3366 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3370 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3371 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3372 TRACE("(%p) : base_index %p\n", This, base_index);
3374 *base_index = This->stateBlock->baseVertexIndex;
3376 TRACE("Returning %u\n", *base_index);
3382 * Get / Set Viewports
3384 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3387 TRACE("(%p)\n", This);
3388 This->updateStateBlock->changed.viewport = TRUE;
3389 This->updateStateBlock->viewport = *pViewport;
3391 /* Handle recording of state blocks */
3392 if (This->isRecordingState) {
3393 TRACE("Recording... not performing anything\n");
3397 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3398 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3400 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3405 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3407 TRACE("(%p)\n", This);
3408 *pViewport = This->stateBlock->viewport;
3413 * Get / Set Render States
3414 * TODO: Verify against dx9 definitions
3416 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3419 DWORD oldValue = This->stateBlock->renderState[State];
3421 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3423 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3424 This->updateStateBlock->renderState[State] = Value;
3426 /* Handle recording of state blocks */
3427 if (This->isRecordingState) {
3428 TRACE("Recording... not performing anything\n");
3432 /* Compared here and not before the assignment to allow proper stateblock recording */
3433 if(Value == oldValue) {
3434 TRACE("Application is setting the old value over, nothing to do\n");
3436 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3442 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3444 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3445 *pValue = This->stateBlock->renderState[State];
3450 * Get / Set Sampler States
3451 * TODO: Verify against dx9 definitions
3454 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3458 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3459 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3461 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3462 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3465 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3466 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3467 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3470 * SetSampler is designed to allow for more than the standard up to 8 textures
3471 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3472 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3474 * http://developer.nvidia.com/object/General_FAQ.html#t6
3476 * There are two new settings for GForce
3478 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3479 * and the texture one:
3480 * GL_MAX_TEXTURE_COORDS_ARB.
3481 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3484 oldValue = This->stateBlock->samplerState[Sampler][Type];
3485 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3486 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3488 /* Handle recording of state blocks */
3489 if (This->isRecordingState) {
3490 TRACE("Recording... not performing anything\n");
3494 if(oldValue == Value) {
3495 TRACE("Application is setting the old value over, nothing to do\n");
3499 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3504 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3507 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3508 This, Sampler, debug_d3dsamplerstate(Type), Type);
3510 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3511 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3514 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3515 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3516 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3518 *Value = This->stateBlock->samplerState[Sampler][Type];
3519 TRACE("(%p) : Returning %#x\n", This, *Value);
3524 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3525 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3527 This->updateStateBlock->changed.scissorRect = TRUE;
3528 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3529 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3532 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3534 if(This->isRecordingState) {
3535 TRACE("Recording... not performing anything\n");
3539 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3544 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3547 *pRect = This->updateStateBlock->scissorRect;
3548 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3552 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3554 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3556 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3558 This->updateStateBlock->vertexDecl = pDecl;
3559 This->updateStateBlock->changed.vertexDecl = TRUE;
3561 if (This->isRecordingState) {
3562 TRACE("Recording... not performing anything\n");
3564 } else if(pDecl == oldDecl) {
3565 /* Checked after the assignment to allow proper stateblock recording */
3566 TRACE("Application is setting the old declaration over, nothing to do\n");
3570 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3574 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3577 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3579 *ppDecl = This->stateBlock->vertexDecl;
3580 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3584 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3586 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3588 This->updateStateBlock->vertexShader = pShader;
3589 This->updateStateBlock->changed.vertexShader = TRUE;
3591 if (This->isRecordingState) {
3592 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3593 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3594 TRACE("Recording... not performing anything\n");
3596 } else if(oldShader == pShader) {
3597 /* Checked here to allow proper stateblock recording */
3598 TRACE("App is setting the old shader over, nothing to do\n");
3602 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3603 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3604 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3606 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3611 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3614 if (NULL == ppShader) {
3615 return WINED3DERR_INVALIDCALL;
3617 *ppShader = This->stateBlock->vertexShader;
3618 if( NULL != *ppShader)
3619 IWineD3DVertexShader_AddRef(*ppShader);
3621 TRACE("(%p) : returning %p\n", This, *ppShader);
3625 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3626 IWineD3DDevice *iface,
3628 CONST BOOL *srcData,
3631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3632 int i, cnt = min(count, MAX_CONST_B - start);
3634 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3635 iface, srcData, start, count);
3637 if (srcData == NULL || cnt < 0)
3638 return WINED3DERR_INVALIDCALL;
3640 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3641 for (i = 0; i < cnt; i++)
3642 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3644 for (i = start; i < cnt + start; ++i) {
3645 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3648 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3653 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3654 IWineD3DDevice *iface,
3659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3660 int cnt = min(count, MAX_CONST_B - start);
3662 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3663 iface, dstData, start, count);
3665 if (dstData == NULL || cnt < 0)
3666 return WINED3DERR_INVALIDCALL;
3668 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3672 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3673 IWineD3DDevice *iface,
3678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3679 int i, cnt = min(count, MAX_CONST_I - start);
3681 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3682 iface, srcData, start, count);
3684 if (srcData == NULL || cnt < 0)
3685 return WINED3DERR_INVALIDCALL;
3687 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3688 for (i = 0; i < cnt; i++)
3689 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3690 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3692 for (i = start; i < cnt + start; ++i) {
3693 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3696 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3701 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3702 IWineD3DDevice *iface,
3707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3708 int cnt = min(count, MAX_CONST_I - start);
3710 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3711 iface, dstData, start, count);
3713 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3714 return WINED3DERR_INVALIDCALL;
3716 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3720 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3721 IWineD3DDevice *iface,
3723 CONST float *srcData,
3726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3729 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3730 iface, srcData, start, count);
3732 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3733 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3734 return WINED3DERR_INVALIDCALL;
3736 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3738 for (i = 0; i < count; i++)
3739 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3740 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3743 if (!This->isRecordingState)
3745 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3746 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3749 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3750 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3755 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3756 IWineD3DDevice *iface,
3761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3762 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3764 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3765 iface, dstData, start, count);
3767 if (dstData == NULL || cnt < 0)
3768 return WINED3DERR_INVALIDCALL;
3770 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3774 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3776 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3778 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3782 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3783 int i = This->rev_tex_unit_map[unit];
3784 int j = This->texUnitMap[stage];
3786 This->texUnitMap[stage] = unit;
3787 if (i != -1 && i != stage) {
3788 This->texUnitMap[i] = -1;
3791 This->rev_tex_unit_map[unit] = stage;
3792 if (j != -1 && j != unit) {
3793 This->rev_tex_unit_map[j] = -1;
3797 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3800 This->fixed_function_usage_map = 0;
3801 for (i = 0; i < MAX_TEXTURES; ++i) {
3802 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3803 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3804 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3805 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3806 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3807 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3808 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3809 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3811 if (color_op == WINED3DTOP_DISABLE) {
3812 /* Not used, and disable higher stages */
3816 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3817 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3818 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3819 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3820 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3821 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3822 This->fixed_function_usage_map |= (1 << i);
3825 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3826 This->fixed_function_usage_map |= (1 << (i + 1));
3831 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3835 device_update_fixed_function_usage_map(This);
3836 ffu_map = This->fixed_function_usage_map;
3838 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3839 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3840 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3842 if (!(ffu_map & 1)) continue;
3844 if (This->texUnitMap[i] != i) {
3845 device_map_stage(This, i, i);
3846 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3847 markTextureStagesDirty(This, i);
3853 /* Now work out the mapping */
3855 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3857 if (!(ffu_map & 1)) continue;
3859 if (This->texUnitMap[i] != tex) {
3860 device_map_stage(This, i, tex);
3861 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3862 markTextureStagesDirty(This, i);
3869 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3870 const DWORD *sampler_tokens =
3871 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3874 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3875 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3876 device_map_stage(This, i, i);
3877 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3878 if (i < MAX_TEXTURES) {
3879 markTextureStagesDirty(This, i);
3885 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3886 const DWORD *vshader_sampler_tokens, int unit)
3888 int current_mapping = This->rev_tex_unit_map[unit];
3890 if (current_mapping == -1) {
3891 /* Not currently used */
3895 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3896 /* Used by a fragment sampler */
3898 if (!pshader_sampler_tokens) {
3899 /* No pixel shader, check fixed function */
3900 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3903 /* Pixel shader, check the shader's sampler map */
3904 return !pshader_sampler_tokens[current_mapping];
3907 /* Used by a vertex sampler */
3908 return !vshader_sampler_tokens[current_mapping];
3911 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3912 const DWORD *vshader_sampler_tokens =
3913 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3914 const DWORD *pshader_sampler_tokens = NULL;
3915 int start = GL_LIMITS(combined_samplers) - 1;
3919 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3921 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3922 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3923 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3926 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3927 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3928 if (vshader_sampler_tokens[i]) {
3929 if (This->texUnitMap[vsampler_idx] != -1) {
3930 /* Already mapped somewhere */
3934 while (start >= 0) {
3935 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3936 device_map_stage(This, vsampler_idx, start);
3937 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3949 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3950 BOOL vs = use_vs(This->stateBlock);
3951 BOOL ps = use_ps(This->stateBlock);
3954 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3955 * that would be really messy and require shader recompilation
3956 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3957 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3960 device_map_psamplers(This);
3962 device_map_fixed_function_samplers(This);
3966 device_map_vsamplers(This, ps);
3970 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3972 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3973 This->updateStateBlock->pixelShader = pShader;
3974 This->updateStateBlock->changed.pixelShader = TRUE;
3976 /* Handle recording of state blocks */
3977 if (This->isRecordingState) {
3978 TRACE("Recording... not performing anything\n");
3981 if (This->isRecordingState) {
3982 TRACE("Recording... not performing anything\n");
3983 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3984 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3988 if(pShader == oldShader) {
3989 TRACE("App is setting the old pixel shader over, nothing to do\n");
3993 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3994 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3996 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3997 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4002 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4005 if (NULL == ppShader) {
4006 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4007 return WINED3DERR_INVALIDCALL;
4010 *ppShader = This->stateBlock->pixelShader;
4011 if (NULL != *ppShader) {
4012 IWineD3DPixelShader_AddRef(*ppShader);
4014 TRACE("(%p) : returning %p\n", This, *ppShader);
4018 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4019 IWineD3DDevice *iface,
4021 CONST BOOL *srcData,
4024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4025 int i, cnt = min(count, MAX_CONST_B - start);
4027 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4028 iface, srcData, start, count);
4030 if (srcData == NULL || cnt < 0)
4031 return WINED3DERR_INVALIDCALL;
4033 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4034 for (i = 0; i < cnt; i++)
4035 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4037 for (i = start; i < cnt + start; ++i) {
4038 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4041 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4046 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4047 IWineD3DDevice *iface,
4052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4053 int cnt = min(count, MAX_CONST_B - start);
4055 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4056 iface, dstData, start, count);
4058 if (dstData == NULL || cnt < 0)
4059 return WINED3DERR_INVALIDCALL;
4061 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4065 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4066 IWineD3DDevice *iface,
4071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4072 int i, cnt = min(count, MAX_CONST_I - start);
4074 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4075 iface, srcData, start, count);
4077 if (srcData == NULL || cnt < 0)
4078 return WINED3DERR_INVALIDCALL;
4080 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4081 for (i = 0; i < cnt; i++)
4082 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4083 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4085 for (i = start; i < cnt + start; ++i) {
4086 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4089 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4094 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4095 IWineD3DDevice *iface,
4100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4101 int cnt = min(count, MAX_CONST_I - start);
4103 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4104 iface, dstData, start, count);
4106 if (dstData == NULL || cnt < 0)
4107 return WINED3DERR_INVALIDCALL;
4109 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4113 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4114 IWineD3DDevice *iface,
4116 CONST float *srcData,
4119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4122 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4123 iface, srcData, start, count);
4125 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4126 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4127 return WINED3DERR_INVALIDCALL;
4129 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4131 for (i = 0; i < count; i++)
4132 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4133 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4136 if (!This->isRecordingState)
4138 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4139 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4142 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4143 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4148 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4149 IWineD3DDevice *iface,
4154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4155 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4157 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4158 iface, dstData, start, count);
4160 if (dstData == NULL || cnt < 0)
4161 return WINED3DERR_INVALIDCALL;
4163 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4167 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4168 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4169 const WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags)
4171 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4173 DWORD DestFVF = dest->fvf;
4175 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4179 if (lpStrideData->u.s.normal.lpData) {
4180 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4183 if (lpStrideData->u.s.position.lpData == NULL) {
4184 ERR("Source has no position mask\n");
4185 return WINED3DERR_INVALIDCALL;
4188 /* We might access VBOs from this code, so hold the lock */
4191 if (dest->resource.allocatedMemory == NULL) {
4192 /* This may happen if we do direct locking into a vbo. Unlikely,
4193 * but theoretically possible(ddraw processvertices test)
4195 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4196 if(!dest->resource.allocatedMemory) {
4198 ERR("Out of memory\n");
4199 return E_OUTOFMEMORY;
4203 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4204 checkGLcall("glBindBufferARB");
4205 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4207 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4209 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4210 checkGLcall("glUnmapBufferARB");
4214 /* Get a pointer into the destination vbo(create one if none exists) and
4215 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4217 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4218 dest->Flags |= VBFLAG_CREATEVBO;
4219 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4223 unsigned char extrabytes = 0;
4224 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4225 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4226 * this may write 4 extra bytes beyond the area that should be written
4228 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4229 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4230 if(!dest_conv_addr) {
4231 ERR("Out of memory\n");
4232 /* Continue without storing converted vertices */
4234 dest_conv = dest_conv_addr;
4238 * a) WINED3DRS_CLIPPING is enabled
4239 * b) WINED3DVOP_CLIP is passed
4241 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4242 static BOOL warned = FALSE;
4244 * The clipping code is not quite correct. Some things need
4245 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4246 * so disable clipping for now.
4247 * (The graphics in Half-Life are broken, and my processvertices
4248 * test crashes with IDirect3DDevice3)
4254 FIXME("Clipping is broken and disabled for now\n");
4256 } else doClip = FALSE;
4257 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4259 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4262 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4263 WINED3DTS_PROJECTION,
4265 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4266 WINED3DTS_WORLDMATRIX(0),
4269 TRACE("View mat:\n");
4270 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);
4271 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);
4272 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);
4273 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);
4275 TRACE("Proj mat:\n");
4276 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);
4277 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);
4278 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);
4279 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);
4281 TRACE("World mat:\n");
4282 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);
4283 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);
4284 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);
4285 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);
4287 /* Get the viewport */
4288 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4289 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4290 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4292 multiply_matrix(&mat,&view_mat,&world_mat);
4293 multiply_matrix(&mat,&proj_mat,&mat);
4295 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4297 for (i = 0; i < dwCount; i+= 1) {
4298 unsigned int tex_index;
4300 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4301 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4302 /* The position first */
4304 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4306 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4308 /* Multiplication with world, view and projection matrix */
4309 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);
4310 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);
4311 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);
4312 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);
4314 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4316 /* WARNING: The following things are taken from d3d7 and were not yet checked
4317 * against d3d8 or d3d9!
4320 /* Clipping conditions: From msdn
4322 * A vertex is clipped if it does not match the following requirements
4326 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4328 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4329 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4334 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4335 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4338 /* "Normal" viewport transformation (not clipped)
4339 * 1) The values are divided by rhw
4340 * 2) The y axis is negative, so multiply it with -1
4341 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4342 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4343 * 4) Multiply x with Width/2 and add Width/2
4344 * 5) The same for the height
4345 * 6) Add the viewpoint X and Y to the 2D coordinates and
4346 * The minimum Z value to z
4347 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4349 * Well, basically it's simply a linear transformation into viewport
4361 z *= vp.MaxZ - vp.MinZ;
4363 x += vp.Width / 2 + vp.X;
4364 y += vp.Height / 2 + vp.Y;
4369 /* That vertex got clipped
4370 * Contrary to OpenGL it is not dropped completely, it just
4371 * undergoes a different calculation.
4373 TRACE("Vertex got clipped\n");
4380 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4381 * outside of the main vertex buffer memory. That needs some more
4386 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4389 ( (float *) dest_ptr)[0] = x;
4390 ( (float *) dest_ptr)[1] = y;
4391 ( (float *) dest_ptr)[2] = z;
4392 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4394 dest_ptr += 3 * sizeof(float);
4396 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4397 dest_ptr += sizeof(float);
4402 ( (float *) dest_conv)[0] = x * w;
4403 ( (float *) dest_conv)[1] = y * w;
4404 ( (float *) dest_conv)[2] = z * w;
4405 ( (float *) dest_conv)[3] = w;
4407 dest_conv += 3 * sizeof(float);
4409 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4410 dest_conv += sizeof(float);
4414 if (DestFVF & WINED3DFVF_PSIZE) {
4415 dest_ptr += sizeof(DWORD);
4416 if(dest_conv) dest_conv += sizeof(DWORD);
4418 if (DestFVF & WINED3DFVF_NORMAL) {
4419 const float *normal =
4420 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4421 /* AFAIK this should go into the lighting information */
4422 FIXME("Didn't expect the destination to have a normal\n");
4423 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4425 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4429 if (DestFVF & WINED3DFVF_DIFFUSE) {
4430 const DWORD *color_d =
4431 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4433 static BOOL warned = FALSE;
4436 ERR("No diffuse color in source, but destination has one\n");
4440 *( (DWORD *) dest_ptr) = 0xffffffff;
4441 dest_ptr += sizeof(DWORD);
4444 *( (DWORD *) dest_conv) = 0xffffffff;
4445 dest_conv += sizeof(DWORD);
4449 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4451 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4452 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4453 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4454 dest_conv += sizeof(DWORD);
4459 if (DestFVF & WINED3DFVF_SPECULAR) {
4460 /* What's the color value in the feedback buffer? */
4461 const DWORD *color_s =
4462 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4464 static BOOL warned = FALSE;
4467 ERR("No specular color in source, but destination has one\n");
4471 *( (DWORD *) dest_ptr) = 0xFF000000;
4472 dest_ptr += sizeof(DWORD);
4475 *( (DWORD *) dest_conv) = 0xFF000000;
4476 dest_conv += sizeof(DWORD);
4480 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4482 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4483 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4484 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4485 dest_conv += sizeof(DWORD);
4490 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4491 const float *tex_coord =
4492 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4493 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4495 ERR("No source texture, but destination requests one\n");
4496 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4497 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4500 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4502 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4509 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4510 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4511 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4512 dwCount * get_flexible_vertex_size(DestFVF),
4514 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4515 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4522 #undef copy_and_next
4524 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4525 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4526 WineDirect3DVertexStridedData strided;
4527 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4528 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4531 ERR("Output vertex declaration not implemented yet\n");
4534 /* Need any context to write to the vbo. */
4535 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4537 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4538 * control the streamIsUP flag, thus restore it afterwards.
4540 This->stateBlock->streamIsUP = FALSE;
4541 memset(&strided, 0, sizeof(strided));
4542 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4543 This->stateBlock->streamIsUP = streamWasUP;
4545 if(vbo || SrcStartIndex) {
4547 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4548 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4550 * Also get the start index in, but only loop over all elements if there's something to add at all.
4552 #define FIXSRC(type) \
4553 if(strided.u.s.type.VBO) { \
4554 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4555 strided.u.s.type.VBO = 0; \
4556 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4558 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4562 if(strided.u.s.type.lpData) { \
4563 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4566 FIXSRC(blendWeights);
4567 FIXSRC(blendMatrixIndices);
4572 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4573 FIXSRC(texCoords[i]);
4586 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4590 * Get / Set Texture Stage States
4591 * TODO: Verify against dx9 definitions
4593 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4595 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4597 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4599 if (Stage >= MAX_TEXTURES) {
4600 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4604 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4605 This->updateStateBlock->textureState[Stage][Type] = Value;
4607 if (This->isRecordingState) {
4608 TRACE("Recording... not performing anything\n");
4612 /* Checked after the assignments to allow proper stateblock recording */
4613 if(oldValue == Value) {
4614 TRACE("App is setting the old value over, nothing to do\n");
4618 if(Stage > This->stateBlock->lowest_disabled_stage &&
4619 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4620 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4621 * Changes in other states are important on disabled stages too
4626 if(Type == WINED3DTSS_COLOROP) {
4629 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4630 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4631 * they have to be disabled
4633 * The current stage is dirtified below.
4635 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4636 TRACE("Additionally dirtifying stage %d\n", i);
4637 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4639 This->stateBlock->lowest_disabled_stage = Stage;
4640 TRACE("New lowest disabled: %d\n", Stage);
4641 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4642 /* Previously disabled stage enabled. Stages above it may need enabling
4643 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4644 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4646 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4649 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4650 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4653 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4654 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4656 This->stateBlock->lowest_disabled_stage = i;
4657 TRACE("New lowest disabled: %d\n", i);
4661 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4666 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4668 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4669 *pValue = This->updateStateBlock->textureState[Stage][Type];
4676 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4678 IWineD3DBaseTexture *oldTexture;
4680 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4682 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4683 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4686 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4687 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4688 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4691 oldTexture = This->updateStateBlock->textures[Stage];
4693 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4694 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4696 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4697 return WINED3DERR_INVALIDCALL;
4700 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4701 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4703 This->updateStateBlock->changed.textures |= 1 << Stage;
4704 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4705 This->updateStateBlock->textures[Stage] = pTexture;
4707 /* Handle recording of state blocks */
4708 if (This->isRecordingState) {
4709 TRACE("Recording... not performing anything\n");
4713 if(oldTexture == pTexture) {
4714 TRACE("App is setting the same texture again, nothing to do\n");
4718 /** NOTE: MSDN says that setTexture increases the reference count,
4719 * and that the application must set the texture back to null (or have a leaky application),
4720 * This means we should pass the refcount up to the parent
4721 *******************************/
4722 if (NULL != This->updateStateBlock->textures[Stage]) {
4723 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4724 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4725 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4727 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4729 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4731 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4734 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4735 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4736 * so the COLOROP and ALPHAOP have to be dirtified.
4738 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4739 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4741 if(bindCount == 1) {
4742 new->baseTexture.sampler = Stage;
4744 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4748 if (NULL != oldTexture) {
4749 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4750 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4752 IWineD3DBaseTexture_Release(oldTexture);
4753 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4754 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4755 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4758 if(bindCount && old->baseTexture.sampler == Stage) {
4760 /* Have to do a search for the other sampler(s) where the texture is bound to
4761 * Shouldn't happen as long as apps bind a texture only to one stage
4763 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4764 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4765 if(This->updateStateBlock->textures[i] == oldTexture) {
4766 old->baseTexture.sampler = i;
4773 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4778 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4781 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4783 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4784 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4787 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4788 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4789 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4792 *ppTexture=This->stateBlock->textures[Stage];
4794 IWineD3DBaseTexture_AddRef(*ppTexture);
4796 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4804 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4805 IWineD3DSurface **ppBackBuffer) {
4806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4807 IWineD3DSwapChain *swapChain;
4810 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4812 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4813 if (hr == WINED3D_OK) {
4814 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4815 IWineD3DSwapChain_Release(swapChain);
4817 *ppBackBuffer = NULL;
4822 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4824 WARN("(%p) : stub, calling idirect3d for now\n", This);
4825 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4828 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4830 IWineD3DSwapChain *swapChain;
4833 if(iSwapChain > 0) {
4834 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4835 if (hr == WINED3D_OK) {
4836 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4837 IWineD3DSwapChain_Release(swapChain);
4839 FIXME("(%p) Error getting display mode\n", This);
4842 /* Don't read the real display mode,
4843 but return the stored mode instead. X11 can't change the color
4844 depth, and some apps are pretty angry if they SetDisplayMode from
4845 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4847 Also don't relay to the swapchain because with ddraw it's possible
4848 that there isn't a swapchain at all */
4849 pMode->Width = This->ddraw_width;
4850 pMode->Height = This->ddraw_height;
4851 pMode->Format = This->ddraw_format;
4852 pMode->RefreshRate = 0;
4860 * Stateblock related functions
4863 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4865 IWineD3DStateBlock *stateblock;
4868 TRACE("(%p)\n", This);
4870 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4872 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4873 if (FAILED(hr)) return hr;
4875 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4876 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4877 This->isRecordingState = TRUE;
4879 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4884 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4887 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4889 if (!This->isRecordingState) {
4890 WARN("(%p) not recording! returning error\n", This);
4891 *ppStateBlock = NULL;
4892 return WINED3DERR_INVALIDCALL;
4895 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
4897 DWORD map = object->changed.renderState[i];
4898 for (j = 0; map; map >>= 1, ++j)
4900 if (!(map & 1)) continue;
4902 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
4906 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
4908 DWORD map = object->changed.transform[i];
4909 for (j = 0; map; map >>= 1, ++j)
4911 if (!(map & 1)) continue;
4913 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
4916 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4917 if(object->changed.vertexShaderConstantsF[i]) {
4918 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4919 object->num_contained_vs_consts_f++;
4922 for(i = 0; i < MAX_CONST_I; i++) {
4923 if (object->changed.vertexShaderConstantsI & (1 << i))
4925 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4926 object->num_contained_vs_consts_i++;
4929 for(i = 0; i < MAX_CONST_B; i++) {
4930 if (object->changed.vertexShaderConstantsB & (1 << i))
4932 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4933 object->num_contained_vs_consts_b++;
4936 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4938 if (object->changed.pixelShaderConstantsF[i])
4940 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4941 ++object->num_contained_ps_consts_f;
4944 for(i = 0; i < MAX_CONST_I; i++) {
4945 if (object->changed.pixelShaderConstantsI & (1 << i))
4947 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4948 object->num_contained_ps_consts_i++;
4951 for(i = 0; i < MAX_CONST_B; i++) {
4952 if (object->changed.pixelShaderConstantsB & (1 << i))
4954 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4955 object->num_contained_ps_consts_b++;
4958 for(i = 0; i < MAX_TEXTURES; i++) {
4959 DWORD map = object->changed.textureState[i];
4961 for(j = 0; map; map >>= 1, ++j)
4963 if (!(map & 1)) continue;
4965 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4966 object->contained_tss_states[object->num_contained_tss_states].state = j;
4967 ++object->num_contained_tss_states;
4970 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4971 DWORD map = object->changed.samplerState[i];
4973 for (j = 0; map; map >>= 1, ++j)
4975 if (!(map & 1)) continue;
4977 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4978 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4979 ++object->num_contained_sampler_states;
4983 *ppStateBlock = (IWineD3DStateBlock*) object;
4984 This->isRecordingState = FALSE;
4985 This->updateStateBlock = This->stateBlock;
4986 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4987 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4988 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4993 * Scene related functions
4995 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4996 /* At the moment we have no need for any functionality at the beginning
4998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4999 TRACE("(%p)\n", This);
5002 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
5003 return WINED3DERR_INVALIDCALL;
5005 This->inScene = TRUE;
5009 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5011 TRACE("(%p)\n", This);
5013 if(!This->inScene) {
5014 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
5015 return WINED3DERR_INVALIDCALL;
5018 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5019 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5021 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5025 This->inScene = FALSE;
5029 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5030 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5031 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5033 IWineD3DSwapChain *swapChain = NULL;
5035 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5037 TRACE("(%p) Presenting the frame\n", This);
5039 for(i = 0 ; i < swapchains ; i ++) {
5041 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5042 TRACE("presentinng chain %d, %p\n", i, swapChain);
5043 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5044 IWineD3DSwapChain_Release(swapChain);
5050 /* Not called from the VTable (internal subroutine) */
5051 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5052 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5053 float Z, DWORD Stencil) {
5054 GLbitfield glMask = 0;
5056 WINED3DRECT curRect;
5058 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5059 UINT drawable_width, drawable_height;
5060 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5061 IWineD3DSwapChainImpl *swapchain = NULL;
5063 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5064 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5065 * for the cleared parts, and the untouched parts.
5067 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5068 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5069 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5070 * checking all this if the dest surface is in the drawable anyway.
5072 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5074 if(vp->X != 0 || vp->Y != 0 ||
5075 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5076 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5079 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5080 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5081 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5082 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5083 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5086 if(Count > 0 && pRects && (
5087 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5088 pRects[0].x2 < target->currentDesc.Width ||
5089 pRects[0].y2 < target->currentDesc.Height)) {
5090 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5097 target->get_drawable_size(target, &drawable_width, &drawable_height);
5099 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5102 /* Only set the values up once, as they are not changing */
5103 if (Flags & WINED3DCLEAR_STENCIL) {
5104 glClearStencil(Stencil);
5105 checkGLcall("glClearStencil");
5106 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5107 glStencilMask(0xFFFFFFFF);
5110 if (Flags & WINED3DCLEAR_ZBUFFER) {
5111 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5112 glDepthMask(GL_TRUE);
5114 checkGLcall("glClearDepth");
5115 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5116 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5118 if (vp->X != 0 || vp->Y != 0 ||
5119 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5120 surface_load_ds_location(This->stencilBufferTarget, location);
5122 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5123 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5124 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5125 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5126 surface_load_ds_location(This->stencilBufferTarget, location);
5128 else if (Count > 0 && pRects && (
5129 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5130 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5131 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5132 surface_load_ds_location(This->stencilBufferTarget, location);
5136 if (Flags & WINED3DCLEAR_TARGET) {
5137 TRACE("Clearing screen with glClear to color %x\n", Color);
5138 glClearColor(D3DCOLOR_R(Color),
5142 checkGLcall("glClearColor");
5144 /* Clear ALL colors! */
5145 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5146 glMask = glMask | GL_COLOR_BUFFER_BIT;
5149 vp_rect.left = vp->X;
5150 vp_rect.top = vp->Y;
5151 vp_rect.right = vp->X + vp->Width;
5152 vp_rect.bottom = vp->Y + vp->Height;
5153 if (!(Count > 0 && pRects)) {
5154 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5155 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5157 if(This->render_offscreen) {
5158 glScissor(vp_rect.left, vp_rect.top,
5159 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5161 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5162 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5164 checkGLcall("glScissor");
5166 checkGLcall("glClear");
5168 /* Now process each rect in turn */
5169 for (i = 0; i < Count; i++) {
5170 /* Note gl uses lower left, width/height */
5171 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5172 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5173 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5175 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5176 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5177 curRect.x1, (target->currentDesc.Height - curRect.y2),
5178 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5180 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5181 * The rectangle is not cleared, no error is returned, but further rectanlges are
5182 * still cleared if they are valid
5184 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5185 TRACE("Rectangle with negative dimensions, ignoring\n");
5189 if(This->render_offscreen) {
5190 glScissor(curRect.x1, curRect.y1,
5191 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5193 glScissor(curRect.x1, drawable_height - curRect.y2,
5194 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5196 checkGLcall("glScissor");
5199 checkGLcall("glClear");
5203 /* Restore the old values (why..?) */
5204 if (Flags & WINED3DCLEAR_STENCIL) {
5205 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5207 if (Flags & WINED3DCLEAR_TARGET) {
5208 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5209 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5210 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5211 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5212 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5214 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5215 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5217 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5219 if (Flags & WINED3DCLEAR_ZBUFFER) {
5220 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5221 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5222 surface_modify_ds_location(This->stencilBufferTarget, location);
5227 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5228 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5231 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5237 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5238 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5240 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5242 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5243 Count, pRects, Flags, Color, Z, Stencil);
5245 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5246 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5247 /* TODO: What about depth stencil buffers without stencil bits? */
5248 return WINED3DERR_INVALIDCALL;
5251 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5257 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5258 UINT PrimitiveCount) {
5260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5262 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5263 debug_d3dprimitivetype(PrimitiveType),
5264 StartVertex, PrimitiveCount);
5266 if(!This->stateBlock->vertexDecl) {
5267 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5268 return WINED3DERR_INVALIDCALL;
5271 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5272 if(This->stateBlock->streamIsUP) {
5273 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5274 This->stateBlock->streamIsUP = FALSE;
5277 if(This->stateBlock->loadBaseVertexIndex != 0) {
5278 This->stateBlock->loadBaseVertexIndex = 0;
5279 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5281 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5282 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0/* NumVertices */, StartVertex /* start_idx */,
5283 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5287 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5288 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5289 WINED3DPRIMITIVETYPE PrimitiveType,
5290 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5294 IWineD3DIndexBuffer *pIB;
5295 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5298 pIB = This->stateBlock->pIndexData;
5300 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5301 * without an index buffer set. (The first time at least...)
5302 * D3D8 simply dies, but I doubt it can do much harm to return
5303 * D3DERR_INVALIDCALL there as well. */
5304 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5305 return WINED3DERR_INVALIDCALL;
5308 if(!This->stateBlock->vertexDecl) {
5309 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5310 return WINED3DERR_INVALIDCALL;
5313 if(This->stateBlock->streamIsUP) {
5314 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5315 This->stateBlock->streamIsUP = FALSE;
5317 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5319 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5320 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5321 minIndex, NumVertices, startIndex, primCount);
5323 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5324 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5330 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5331 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5332 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5335 drawPrimitive(iface, PrimitiveType, primCount, NumVertices, startIndex,
5336 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5341 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5342 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5343 UINT VertexStreamZeroStride) {
5344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5345 IWineD3DVertexBuffer *vb;
5347 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5348 debug_d3dprimitivetype(PrimitiveType),
5349 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5351 if(!This->stateBlock->vertexDecl) {
5352 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5353 return WINED3DERR_INVALIDCALL;
5356 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5357 vb = This->stateBlock->streamSource[0];
5358 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5359 if(vb) IWineD3DVertexBuffer_Release(vb);
5360 This->stateBlock->streamOffset[0] = 0;
5361 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5362 This->stateBlock->streamIsUP = TRUE;
5363 This->stateBlock->loadBaseVertexIndex = 0;
5365 /* TODO: Only mark dirty if drawing from a different UP address */
5366 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5368 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* NumVertices */,
5369 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5371 /* MSDN specifies stream zero settings must be set to NULL */
5372 This->stateBlock->streamStride[0] = 0;
5373 This->stateBlock->streamSource[0] = NULL;
5375 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5376 * the new stream sources or use UP drawing again
5381 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5382 UINT MinVertexIndex, UINT NumVertices,
5383 UINT PrimitiveCount, CONST void* pIndexData,
5384 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5385 UINT VertexStreamZeroStride) {
5387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5388 IWineD3DVertexBuffer *vb;
5389 IWineD3DIndexBuffer *ib;
5391 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5392 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5393 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5394 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5396 if(!This->stateBlock->vertexDecl) {
5397 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5398 return WINED3DERR_INVALIDCALL;
5401 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5407 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5408 vb = This->stateBlock->streamSource[0];
5409 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5410 if(vb) IWineD3DVertexBuffer_Release(vb);
5411 This->stateBlock->streamIsUP = TRUE;
5412 This->stateBlock->streamOffset[0] = 0;
5413 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5415 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5416 This->stateBlock->baseVertexIndex = 0;
5417 This->stateBlock->loadBaseVertexIndex = 0;
5418 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5419 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5420 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5422 drawPrimitive(iface, PrimitiveType, PrimitiveCount, NumVertices, 0 /* start_idx */, idxStride, pIndexData, MinVertexIndex);
5424 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5425 This->stateBlock->streamSource[0] = NULL;
5426 This->stateBlock->streamStride[0] = 0;
5427 ib = This->stateBlock->pIndexData;
5429 IWineD3DIndexBuffer_Release(ib);
5430 This->stateBlock->pIndexData = NULL;
5432 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5433 * SetStreamSource to specify a vertex buffer
5439 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5440 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5441 const WineDirect3DVertexStridedData *DrawPrimStrideData)
5443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5445 /* Mark the state dirty until we have nicer tracking
5446 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5449 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5450 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5451 This->stateBlock->baseVertexIndex = 0;
5452 This->up_strided = DrawPrimStrideData;
5453 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, NULL, 0);
5454 This->up_strided = NULL;
5458 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5459 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5460 const WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, const void *pIndexData,
5461 WINED3DFORMAT IndexDataFormat)
5463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5464 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5466 /* Mark the state dirty until we have nicer tracking
5467 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5470 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5471 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5472 This->stateBlock->streamIsUP = TRUE;
5473 This->stateBlock->baseVertexIndex = 0;
5474 This->up_strided = DrawPrimStrideData;
5475 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5476 This->up_strided = NULL;
5480 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5481 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5482 * not callable by the app directly no parameter validation checks are needed here.
5484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5485 WINED3DLOCKED_BOX src;
5486 WINED3DLOCKED_BOX dst;
5488 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5490 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5491 * dirtification to improve loading performance.
5493 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5494 if(FAILED(hr)) return hr;
5495 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5497 IWineD3DVolume_UnlockBox(pSourceVolume);
5501 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5503 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5505 IWineD3DVolume_UnlockBox(pSourceVolume);
5507 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5512 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5513 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5515 HRESULT hr = WINED3D_OK;
5516 WINED3DRESOURCETYPE sourceType;
5517 WINED3DRESOURCETYPE destinationType;
5520 /* TODO: think about moving the code into IWineD3DBaseTexture */
5522 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5524 /* verify that the source and destination textures aren't NULL */
5525 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5526 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5527 This, pSourceTexture, pDestinationTexture);
5528 hr = WINED3DERR_INVALIDCALL;
5531 if (pSourceTexture == pDestinationTexture) {
5532 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5533 This, pSourceTexture, pDestinationTexture);
5534 hr = WINED3DERR_INVALIDCALL;
5536 /* Verify that the source and destination textures are the same type */
5537 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5538 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5540 if (sourceType != destinationType) {
5541 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5543 hr = WINED3DERR_INVALIDCALL;
5546 /* check that both textures have the identical numbers of levels */
5547 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5548 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5549 hr = WINED3DERR_INVALIDCALL;
5552 if (WINED3D_OK == hr) {
5554 /* Make sure that the destination texture is loaded */
5555 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5557 /* Update every surface level of the texture */
5558 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5560 switch (sourceType) {
5561 case WINED3DRTYPE_TEXTURE:
5563 IWineD3DSurface *srcSurface;
5564 IWineD3DSurface *destSurface;
5566 for (i = 0 ; i < levels ; ++i) {
5567 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5568 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5569 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5570 IWineD3DSurface_Release(srcSurface);
5571 IWineD3DSurface_Release(destSurface);
5572 if (WINED3D_OK != hr) {
5573 WARN("(%p) : Call to update surface failed\n", This);
5579 case WINED3DRTYPE_CUBETEXTURE:
5581 IWineD3DSurface *srcSurface;
5582 IWineD3DSurface *destSurface;
5583 WINED3DCUBEMAP_FACES faceType;
5585 for (i = 0 ; i < levels ; ++i) {
5586 /* Update each cube face */
5587 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5588 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5589 if (WINED3D_OK != hr) {
5590 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5592 TRACE("Got srcSurface %p\n", srcSurface);
5594 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5595 if (WINED3D_OK != hr) {
5596 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5598 TRACE("Got desrSurface %p\n", destSurface);
5600 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5601 IWineD3DSurface_Release(srcSurface);
5602 IWineD3DSurface_Release(destSurface);
5603 if (WINED3D_OK != hr) {
5604 WARN("(%p) : Call to update surface failed\n", This);
5612 case WINED3DRTYPE_VOLUMETEXTURE:
5614 IWineD3DVolume *srcVolume = NULL;
5615 IWineD3DVolume *destVolume = NULL;
5617 for (i = 0 ; i < levels ; ++i) {
5618 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5619 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5620 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5621 IWineD3DVolume_Release(srcVolume);
5622 IWineD3DVolume_Release(destVolume);
5623 if (WINED3D_OK != hr) {
5624 WARN("(%p) : Call to update volume failed\n", This);
5632 FIXME("(%p) : Unsupported source and destination type\n", This);
5633 hr = WINED3DERR_INVALIDCALL;
5640 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5641 IWineD3DSwapChain *swapChain;
5643 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5644 if(hr == WINED3D_OK) {
5645 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5646 IWineD3DSwapChain_Release(swapChain);
5651 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5653 IWineD3DBaseTextureImpl *texture;
5654 const struct GlPixelFormatDesc *gl_info;
5657 TRACE("(%p) : %p\n", This, pNumPasses);
5659 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5660 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5661 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5662 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5664 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5665 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5666 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5669 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5670 if(!texture) continue;
5671 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5672 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5674 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5675 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5678 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5679 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5682 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5683 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5684 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5689 /* return a sensible default */
5692 TRACE("returning D3D_OK\n");
5696 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5700 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5701 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5702 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5703 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5708 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5712 PALETTEENTRY **palettes;
5714 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5716 if (PaletteNumber >= MAX_PALETTES) {
5717 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5718 return WINED3DERR_INVALIDCALL;
5721 if (PaletteNumber >= This->NumberOfPalettes) {
5722 NewSize = This->NumberOfPalettes;
5725 } while(PaletteNumber >= NewSize);
5726 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5728 ERR("Out of memory!\n");
5729 return E_OUTOFMEMORY;
5731 This->palettes = palettes;
5732 This->NumberOfPalettes = NewSize;
5735 if (!This->palettes[PaletteNumber]) {
5736 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5737 if (!This->palettes[PaletteNumber]) {
5738 ERR("Out of memory!\n");
5739 return E_OUTOFMEMORY;
5743 for (j = 0; j < 256; ++j) {
5744 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5745 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5746 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5747 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5749 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5750 TRACE("(%p) : returning\n", This);
5754 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5757 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5758 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5759 /* What happens in such situation isn't documented; Native seems to silently abort
5760 on such conditions. Return Invalid Call. */
5761 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5762 return WINED3DERR_INVALIDCALL;
5764 for (j = 0; j < 256; ++j) {
5765 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5766 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5767 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5768 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5770 TRACE("(%p) : returning\n", This);
5774 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5776 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5777 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5778 (tested with reference rasterizer). Return Invalid Call. */
5779 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5780 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5781 return WINED3DERR_INVALIDCALL;
5783 /*TODO: stateblocks */
5784 if (This->currentPalette != PaletteNumber) {
5785 This->currentPalette = PaletteNumber;
5786 dirtify_p8_texture_samplers(This);
5788 TRACE("(%p) : returning\n", This);
5792 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5794 if (PaletteNumber == NULL) {
5795 WARN("(%p) : returning Invalid Call\n", This);
5796 return WINED3DERR_INVALIDCALL;
5798 /*TODO: stateblocks */
5799 *PaletteNumber = This->currentPalette;
5800 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5804 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5809 FIXME("(%p) : stub\n", This);
5813 This->softwareVertexProcessing = bSoftware;
5818 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5823 FIXME("(%p) : stub\n", This);
5826 return This->softwareVertexProcessing;
5830 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5832 IWineD3DSwapChain *swapChain;
5835 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5837 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5838 if(hr == WINED3D_OK){
5839 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5840 IWineD3DSwapChain_Release(swapChain);
5842 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5848 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5851 if(nSegments != 0.0f) {
5854 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5861 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5866 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5872 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5874 /** TODO: remove casts to IWineD3DSurfaceImpl
5875 * NOTE: move code to surface to accomplish this
5876 ****************************************/
5877 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5878 int srcWidth, srcHeight;
5879 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5880 WINED3DFORMAT destFormat, srcFormat;
5882 int srcLeft, destLeft, destTop;
5883 WINED3DPOOL srcPool, destPool;
5885 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5886 glDescriptor *glDescription = NULL;
5890 CONVERT_TYPES convert = NO_CONVERSION;
5892 WINED3DSURFACE_DESC winedesc;
5894 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5895 memset(&winedesc, 0, sizeof(winedesc));
5896 winedesc.Width = &srcSurfaceWidth;
5897 winedesc.Height = &srcSurfaceHeight;
5898 winedesc.Pool = &srcPool;
5899 winedesc.Format = &srcFormat;
5901 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5903 winedesc.Width = &destSurfaceWidth;
5904 winedesc.Height = &destSurfaceHeight;
5905 winedesc.Pool = &destPool;
5906 winedesc.Format = &destFormat;
5907 winedesc.Size = &destSize;
5909 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5911 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5912 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5913 return WINED3DERR_INVALIDCALL;
5916 /* This call loads the opengl surface directly, instead of copying the surface to the
5917 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5918 * copy in sysmem and use regular surface loading.
5920 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5921 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5922 if(convert != NO_CONVERSION) {
5923 return IWineD3DSurface_BltFast(pDestinationSurface,
5924 pDestPoint ? pDestPoint->x : 0,
5925 pDestPoint ? pDestPoint->y : 0,
5926 pSourceSurface, pSourceRect, 0);
5929 if (destFormat == WINED3DFMT_UNKNOWN) {
5930 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5931 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5933 /* Get the update surface description */
5934 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5937 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5940 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5941 checkGLcall("glActiveTextureARB");
5944 /* Make sure the surface is loaded and up to date */
5945 IWineD3DSurface_PreLoad(pDestinationSurface);
5946 IWineD3DSurface_BindTexture(pDestinationSurface);
5948 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5950 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5951 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5952 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5953 srcLeft = pSourceRect ? pSourceRect->left : 0;
5954 destLeft = pDestPoint ? pDestPoint->x : 0;
5955 destTop = pDestPoint ? pDestPoint->y : 0;
5958 /* This function doesn't support compressed textures
5959 the pitch is just bytesPerPixel * width */
5960 if(srcWidth != srcSurfaceWidth || srcLeft ){
5961 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5962 offset += srcLeft * pSrcSurface->bytesPerPixel;
5963 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5965 /* TODO DXT formats */
5967 if(pSourceRect != NULL && pSourceRect->top != 0){
5968 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5970 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5971 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
5972 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5975 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5977 /* need to lock the surface to get the data */
5978 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5983 /* TODO: Cube and volume support */
5985 /* not a whole row so we have to do it a line at a time */
5988 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5989 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5991 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5993 glTexSubImage2D(glDescription->target
5994 ,glDescription->level
5999 ,glDescription->glFormat
6000 ,glDescription->glType
6001 ,data /* could be quicker using */
6006 } else { /* Full width, so just write out the whole texture */
6007 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6009 if (WINED3DFMT_DXT1 == destFormat ||
6010 WINED3DFMT_DXT2 == destFormat ||
6011 WINED3DFMT_DXT3 == destFormat ||
6012 WINED3DFMT_DXT4 == destFormat ||
6013 WINED3DFMT_DXT5 == destFormat) {
6014 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6015 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6016 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6017 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6018 } if (destFormat != srcFormat) {
6019 FIXME("Updating mixed format compressed texture is not curretly support\n");
6021 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6022 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
6025 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6030 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6031 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
6034 checkGLcall("glTexSubImage2D");
6038 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6039 sampler = This->rev_tex_unit_map[0];
6040 if (sampler != -1) {
6041 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6047 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6048 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6049 struct WineD3DRectPatch *patch;
6053 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6055 if(!(Handle || pRectPatchInfo)) {
6056 /* TODO: Write a test for the return value, thus the FIXME */
6057 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6058 return WINED3DERR_INVALIDCALL;
6062 i = PATCHMAP_HASHFUNC(Handle);
6064 LIST_FOR_EACH(e, &This->patches[i]) {
6065 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6066 if(patch->Handle == Handle) {
6073 TRACE("Patch does not exist. Creating a new one\n");
6074 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6075 patch->Handle = Handle;
6076 list_add_head(&This->patches[i], &patch->entry);
6078 TRACE("Found existing patch %p\n", patch);
6081 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6082 * attributes we have to tesselate, read back, and draw. This needs a patch
6083 * management structure instance. Create one.
6085 * A possible improvement is to check if a vertex shader is used, and if not directly
6088 FIXME("Drawing an uncached patch. This is slow\n");
6089 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6092 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6093 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6094 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6096 TRACE("Tesselation density or patch info changed, retesselating\n");
6098 if(pRectPatchInfo) {
6099 patch->RectPatchInfo = *pRectPatchInfo;
6101 patch->numSegs[0] = pNumSegs[0];
6102 patch->numSegs[1] = pNumSegs[1];
6103 patch->numSegs[2] = pNumSegs[2];
6104 patch->numSegs[3] = pNumSegs[3];
6106 hr = tesselate_rectpatch(This, patch);
6108 WARN("Patch tesselation failed\n");
6110 /* Do not release the handle to store the params of the patch */
6112 HeapFree(GetProcessHeap(), 0, patch);
6118 This->currentPatch = patch;
6119 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6120 This->currentPatch = NULL;
6122 /* Destroy uncached patches */
6124 HeapFree(GetProcessHeap(), 0, patch->mem);
6125 HeapFree(GetProcessHeap(), 0, patch);
6130 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6132 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6133 FIXME("(%p) : Stub\n", This);
6137 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6140 struct WineD3DRectPatch *patch;
6142 TRACE("(%p) Handle(%d)\n", This, Handle);
6144 i = PATCHMAP_HASHFUNC(Handle);
6145 LIST_FOR_EACH(e, &This->patches[i]) {
6146 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6147 if(patch->Handle == Handle) {
6148 TRACE("Deleting patch %p\n", patch);
6149 list_remove(&patch->entry);
6150 HeapFree(GetProcessHeap(), 0, patch->mem);
6151 HeapFree(GetProcessHeap(), 0, patch);
6156 /* TODO: Write a test for the return value */
6157 FIXME("Attempt to destroy nonexistent patch\n");
6158 return WINED3DERR_INVALIDCALL;
6161 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6163 IWineD3DSwapChain *swapchain;
6165 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6166 if (SUCCEEDED(hr)) {
6167 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6174 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6176 IWineD3DSwapChain *swapchain;
6178 swapchain = get_swapchain(surface);
6182 TRACE("Surface %p is onscreen\n", surface);
6184 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6186 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6187 buffer = surface_get_gl_buffer(surface, swapchain);
6188 glDrawBuffer(buffer);
6189 checkGLcall("glDrawBuffer()");
6191 TRACE("Surface %p is offscreen\n", surface);
6193 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6195 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6196 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6197 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6198 checkGLcall("glFramebufferRenderbufferEXT");
6202 glEnable(GL_SCISSOR_TEST);
6204 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6206 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6207 rect->x2 - rect->x1, rect->y2 - rect->y1);
6209 checkGLcall("glScissor");
6210 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6212 glDisable(GL_SCISSOR_TEST);
6214 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6216 glDisable(GL_BLEND);
6217 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6219 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6220 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6222 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6223 glClear(GL_COLOR_BUFFER_BIT);
6224 checkGLcall("glClear");
6226 if (This->activeContext->current_fbo) {
6227 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6229 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6230 checkGLcall("glBindFramebuffer()");
6233 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6234 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6235 glDrawBuffer(GL_BACK);
6236 checkGLcall("glDrawBuffer()");
6242 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6243 unsigned int r, g, b, a;
6246 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6247 destfmt == WINED3DFMT_R8G8B8)
6250 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6252 a = (color & 0xff000000) >> 24;
6253 r = (color & 0x00ff0000) >> 16;
6254 g = (color & 0x0000ff00) >> 8;
6255 b = (color & 0x000000ff) >> 0;
6259 case WINED3DFMT_R5G6B5:
6260 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6267 TRACE("Returning %08x\n", ret);
6270 case WINED3DFMT_X1R5G5B5:
6271 case WINED3DFMT_A1R5G5B5:
6280 TRACE("Returning %08x\n", ret);
6284 TRACE("Returning %08x\n", a);
6287 case WINED3DFMT_X4R4G4B4:
6288 case WINED3DFMT_A4R4G4B4:
6297 TRACE("Returning %08x\n", ret);
6300 case WINED3DFMT_R3G3B2:
6307 TRACE("Returning %08x\n", ret);
6310 case WINED3DFMT_X8B8G8R8:
6311 case WINED3DFMT_A8B8G8R8:
6316 TRACE("Returning %08x\n", ret);
6319 case WINED3DFMT_A2R10G10B10:
6321 r = (r * 1024) / 256;
6322 g = (g * 1024) / 256;
6323 b = (b * 1024) / 256;
6328 TRACE("Returning %08x\n", ret);
6331 case WINED3DFMT_A2B10G10R10:
6333 r = (r * 1024) / 256;
6334 g = (g * 1024) / 256;
6335 b = (b * 1024) / 256;
6340 TRACE("Returning %08x\n", ret);
6344 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6349 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6351 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6353 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6355 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6356 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6357 return WINED3DERR_INVALIDCALL;
6360 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6361 color_fill_fbo(iface, pSurface, pRect, color);
6364 /* Just forward this to the DirectDraw blitting engine */
6365 memset(&BltFx, 0, sizeof(BltFx));
6366 BltFx.dwSize = sizeof(BltFx);
6367 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6368 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6369 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6373 /* rendertarget and depth stencil functions */
6374 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6377 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6378 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6379 return WINED3DERR_INVALIDCALL;
6382 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6383 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6384 /* Note inc ref on returned surface */
6385 if(*ppRenderTarget != NULL)
6386 IWineD3DSurface_AddRef(*ppRenderTarget);
6390 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6392 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6393 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6394 IWineD3DSwapChainImpl *Swapchain;
6397 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6399 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6400 if(hr != WINED3D_OK) {
6401 ERR("Can't get the swapchain\n");
6405 /* Make sure to release the swapchain */
6406 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6408 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6409 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6410 return WINED3DERR_INVALIDCALL;
6412 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6413 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6414 return WINED3DERR_INVALIDCALL;
6417 if(Swapchain->frontBuffer != Front) {
6418 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6420 if(Swapchain->frontBuffer)
6421 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6422 Swapchain->frontBuffer = Front;
6424 if(Swapchain->frontBuffer) {
6425 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6429 if(Back && !Swapchain->backBuffer) {
6430 /* We need memory for the back buffer array - only one back buffer this way */
6431 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6432 if(!Swapchain->backBuffer) {
6433 ERR("Out of memory\n");
6434 return E_OUTOFMEMORY;
6438 if(Swapchain->backBuffer[0] != Back) {
6439 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6441 /* What to do about the context here in the case of multithreading? Not sure.
6442 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6445 if(!Swapchain->backBuffer[0]) {
6446 /* GL was told to draw to the front buffer at creation,
6449 glDrawBuffer(GL_BACK);
6450 checkGLcall("glDrawBuffer(GL_BACK)");
6451 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6452 Swapchain->presentParms.BackBufferCount = 1;
6454 /* That makes problems - disable for now */
6455 /* glDrawBuffer(GL_FRONT); */
6456 checkGLcall("glDrawBuffer(GL_FRONT)");
6457 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6458 Swapchain->presentParms.BackBufferCount = 0;
6462 if(Swapchain->backBuffer[0])
6463 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6464 Swapchain->backBuffer[0] = Back;
6466 if(Swapchain->backBuffer[0]) {
6467 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6469 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6470 Swapchain->backBuffer = NULL;
6478 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6480 *ppZStencilSurface = This->stencilBufferTarget;
6481 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6483 if(*ppZStencilSurface != NULL) {
6484 /* Note inc ref on returned surface */
6485 IWineD3DSurface_AddRef(*ppZStencilSurface);
6488 return WINED3DERR_NOTFOUND;
6492 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6493 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6496 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6497 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6499 POINT offset = {0, 0};
6501 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6502 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6503 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6504 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6507 case WINED3DTEXF_LINEAR:
6508 gl_filter = GL_LINEAR;
6512 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6513 case WINED3DTEXF_NONE:
6514 case WINED3DTEXF_POINT:
6515 gl_filter = GL_NEAREST;
6519 /* Attach src surface to src fbo */
6520 src_swapchain = get_swapchain(src_surface);
6521 if (src_swapchain) {
6522 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6524 TRACE("Source surface %p is onscreen\n", src_surface);
6525 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6526 /* Make sure the drawable is up to date. In the offscreen case
6527 * attach_surface_fbo() implicitly takes care of this. */
6528 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6530 if(buffer == GL_FRONT) {
6533 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6534 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6535 h = windowsize.bottom - windowsize.top;
6536 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6537 src_rect->y1 = offset.y + h - src_rect->y1;
6538 src_rect->y2 = offset.y + h - src_rect->y2;
6540 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6541 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6545 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6546 glReadBuffer(buffer);
6547 checkGLcall("glReadBuffer()");
6549 TRACE("Source surface %p is offscreen\n", src_surface);
6551 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6552 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6553 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6554 checkGLcall("glReadBuffer()");
6555 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6556 checkGLcall("glFramebufferRenderbufferEXT");
6560 /* Attach dst surface to dst fbo */
6561 dst_swapchain = get_swapchain(dst_surface);
6562 if (dst_swapchain) {
6563 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6565 TRACE("Destination surface %p is onscreen\n", dst_surface);
6566 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6567 /* Make sure the drawable is up to date. In the offscreen case
6568 * attach_surface_fbo() implicitly takes care of this. */
6569 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6571 if(buffer == GL_FRONT) {
6574 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6575 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6576 h = windowsize.bottom - windowsize.top;
6577 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6578 dst_rect->y1 = offset.y + h - dst_rect->y1;
6579 dst_rect->y2 = offset.y + h - dst_rect->y2;
6581 /* Screen coords = window coords, surface height = window height */
6582 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6583 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6587 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6588 glDrawBuffer(buffer);
6589 checkGLcall("glDrawBuffer()");
6591 TRACE("Destination surface %p is offscreen\n", dst_surface);
6593 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6594 if(!src_swapchain) {
6595 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6599 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6600 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6601 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6602 checkGLcall("glDrawBuffer()");
6603 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6604 checkGLcall("glFramebufferRenderbufferEXT");
6606 glDisable(GL_SCISSOR_TEST);
6607 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6610 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6611 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6612 checkGLcall("glBlitFramebuffer()");
6614 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6615 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6616 checkGLcall("glBlitFramebuffer()");
6619 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6621 if (This->activeContext->current_fbo) {
6622 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6624 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6625 checkGLcall("glBindFramebuffer()");
6628 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6629 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6630 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6631 glDrawBuffer(GL_BACK);
6632 checkGLcall("glDrawBuffer()");
6637 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6639 WINED3DVIEWPORT viewport;
6641 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6643 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6644 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6645 This, RenderTargetIndex, GL_LIMITS(buffers));
6646 return WINED3DERR_INVALIDCALL;
6649 /* MSDN says that null disables the render target
6650 but a device must always be associated with a render target
6651 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6653 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6654 FIXME("Trying to set render target 0 to NULL\n");
6655 return WINED3DERR_INVALIDCALL;
6657 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6658 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);
6659 return WINED3DERR_INVALIDCALL;
6662 /* If we are trying to set what we already have, don't bother */
6663 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6664 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6667 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6668 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6669 This->render_targets[RenderTargetIndex] = pRenderTarget;
6671 /* Render target 0 is special */
6672 if(RenderTargetIndex == 0) {
6673 /* Finally, reset the viewport as the MSDN states. */
6674 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6675 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6678 viewport.MaxZ = 1.0f;
6679 viewport.MinZ = 0.0f;
6680 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6681 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6682 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6684 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6689 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6691 HRESULT hr = WINED3D_OK;
6692 IWineD3DSurface *tmp;
6694 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6696 if (pNewZStencil == This->stencilBufferTarget) {
6697 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6699 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6700 * depending on the renter target implementation being used.
6701 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6702 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6703 * stencil buffer and incur an extra memory overhead
6704 ******************************************************/
6706 if (This->stencilBufferTarget) {
6707 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6708 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6709 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6711 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6712 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6713 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6717 tmp = This->stencilBufferTarget;
6718 This->stencilBufferTarget = pNewZStencil;
6719 /* should we be calling the parent or the wined3d surface? */
6720 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6721 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6724 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6725 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6726 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6727 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6728 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6735 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6736 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6737 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6738 /* TODO: the use of Impl is deprecated. */
6739 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6740 WINED3DLOCKED_RECT lockedRect;
6742 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6744 /* some basic validation checks */
6745 if(This->cursorTexture) {
6746 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6748 glDeleteTextures(1, &This->cursorTexture);
6750 This->cursorTexture = 0;
6753 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6754 This->haveHardwareCursor = TRUE;
6756 This->haveHardwareCursor = FALSE;
6759 WINED3DLOCKED_RECT rect;
6761 /* MSDN: Cursor must be A8R8G8B8 */
6762 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6763 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6764 return WINED3DERR_INVALIDCALL;
6767 /* MSDN: Cursor must be smaller than the display mode */
6768 if(pSur->currentDesc.Width > This->ddraw_width ||
6769 pSur->currentDesc.Height > This->ddraw_height) {
6770 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);
6771 return WINED3DERR_INVALIDCALL;
6774 if (!This->haveHardwareCursor) {
6775 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6777 /* Do not store the surface's pointer because the application may
6778 * release it after setting the cursor image. Windows doesn't
6779 * addref the set surface, so we can't do this either without
6780 * creating circular refcount dependencies. Copy out the gl texture
6783 This->cursorWidth = pSur->currentDesc.Width;
6784 This->cursorHeight = pSur->currentDesc.Height;
6785 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6787 const struct GlPixelFormatDesc *glDesc;
6788 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6789 char *mem, *bits = (char *)rect.pBits;
6790 GLint intfmt = glDesc->glInternal;
6791 GLint format = glDesc->glFormat;
6792 GLint type = glDesc->glType;
6793 INT height = This->cursorHeight;
6794 INT width = This->cursorWidth;
6795 INT bpp = tableEntry->bpp;
6798 /* Reformat the texture memory (pitch and width can be
6800 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6801 for(i = 0; i < height; i++)
6802 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6803 IWineD3DSurface_UnlockRect(pCursorBitmap);
6806 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6807 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6808 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6811 /* Make sure that a proper texture unit is selected */
6812 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6813 checkGLcall("glActiveTextureARB");
6814 sampler = This->rev_tex_unit_map[0];
6815 if (sampler != -1) {
6816 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6818 /* Create a new cursor texture */
6819 glGenTextures(1, &This->cursorTexture);
6820 checkGLcall("glGenTextures");
6821 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6822 checkGLcall("glBindTexture");
6823 /* Copy the bitmap memory into the cursor texture */
6824 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6825 HeapFree(GetProcessHeap(), 0, mem);
6826 checkGLcall("glTexImage2D");
6828 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6829 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6830 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6837 FIXME("A cursor texture was not returned.\n");
6838 This->cursorTexture = 0;
6843 /* Draw a hardware cursor */
6844 ICONINFO cursorInfo;
6846 /* Create and clear maskBits because it is not needed for
6847 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6849 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6850 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6851 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6852 WINED3DLOCK_NO_DIRTY_UPDATE |
6853 WINED3DLOCK_READONLY
6855 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6856 pSur->currentDesc.Height);
6858 cursorInfo.fIcon = FALSE;
6859 cursorInfo.xHotspot = XHotSpot;
6860 cursorInfo.yHotspot = YHotSpot;
6861 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6862 pSur->currentDesc.Height, 1,
6864 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6865 pSur->currentDesc.Height, 1,
6866 32, lockedRect.pBits);
6867 IWineD3DSurface_UnlockRect(pCursorBitmap);
6868 /* Create our cursor and clean up. */
6869 cursor = CreateIconIndirect(&cursorInfo);
6871 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6872 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6873 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6874 This->hardwareCursor = cursor;
6875 HeapFree(GetProcessHeap(), 0, maskBits);
6879 This->xHotSpot = XHotSpot;
6880 This->yHotSpot = YHotSpot;
6884 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6886 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6888 This->xScreenSpace = XScreenSpace;
6889 This->yScreenSpace = YScreenSpace;
6895 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6897 BOOL oldVisible = This->bCursorVisible;
6900 TRACE("(%p) : visible(%d)\n", This, bShow);
6903 * When ShowCursor is first called it should make the cursor appear at the OS's last
6904 * known cursor position. Because of this, some applications just repetitively call
6905 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6908 This->xScreenSpace = pt.x;
6909 This->yScreenSpace = pt.y;
6911 if (This->haveHardwareCursor) {
6912 This->bCursorVisible = bShow;
6914 SetCursor(This->hardwareCursor);
6920 if (This->cursorTexture)
6921 This->bCursorVisible = bShow;
6927 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6929 IWineD3DResourceImpl *resource;
6930 TRACE("(%p) : state (%u)\n", This, This->state);
6932 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6933 switch (This->state) {
6936 case WINED3DERR_DEVICELOST:
6938 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6939 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6940 return WINED3DERR_DEVICENOTRESET;
6942 return WINED3DERR_DEVICELOST;
6944 case WINED3DERR_DRIVERINTERNALERROR:
6945 return WINED3DERR_DRIVERINTERNALERROR;
6949 return WINED3DERR_DRIVERINTERNALERROR;
6953 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6954 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6955 /** FIXME: Resource tracking needs to be done,
6956 * The closes we can do to this is set the priorities of all managed textures low
6957 * and then reset them.
6958 ***********************************************************/
6959 FIXME("(%p) : stub\n", This);
6963 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6965 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6967 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6968 if(surface->Flags & SFLAG_DIBSECTION) {
6969 /* Release the DC */
6970 SelectObject(surface->hDC, surface->dib.holdbitmap);
6971 DeleteDC(surface->hDC);
6972 /* Release the DIB section */
6973 DeleteObject(surface->dib.DIBsection);
6974 surface->dib.bitmap_data = NULL;
6975 surface->resource.allocatedMemory = NULL;
6976 surface->Flags &= ~SFLAG_DIBSECTION;
6978 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6979 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6980 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6981 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6982 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6983 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6985 surface->pow2Width = surface->pow2Height = 1;
6986 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6987 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6989 surface->glRect.left = 0;
6990 surface->glRect.top = 0;
6991 surface->glRect.right = surface->pow2Width;
6992 surface->glRect.bottom = surface->pow2Height;
6994 if(surface->glDescription.textureName) {
6995 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6997 glDeleteTextures(1, &surface->glDescription.textureName);
6999 surface->glDescription.textureName = 0;
7000 surface->Flags &= ~SFLAG_CLIENT;
7002 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7003 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7004 surface->Flags |= SFLAG_NONPOW2;
7006 surface->Flags &= ~SFLAG_NONPOW2;
7008 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7009 surface->resource.allocatedMemory = NULL;
7010 surface->resource.heapMemory = NULL;
7011 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7012 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7013 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7014 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7016 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7020 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7021 TRACE("Unloading resource %p\n", resource);
7022 IWineD3DResource_UnLoad(resource);
7023 IWineD3DResource_Release(resource);
7027 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7030 WINED3DDISPLAYMODE m;
7033 /* All Windowed modes are supported, as is leaving the current mode */
7034 if(pp->Windowed) return TRUE;
7035 if(!pp->BackBufferWidth) return TRUE;
7036 if(!pp->BackBufferHeight) return TRUE;
7038 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7039 for(i = 0; i < count; i++) {
7040 memset(&m, 0, sizeof(m));
7041 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7043 ERR("EnumAdapterModes failed\n");
7045 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7046 /* Mode found, it is supported */
7050 /* Mode not found -> not supported */
7054 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7056 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7058 IWineD3DBaseShaderImpl *shader;
7060 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7061 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7062 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7066 if(This->depth_blt_texture) {
7067 glDeleteTextures(1, &This->depth_blt_texture);
7068 This->depth_blt_texture = 0;
7070 if (This->depth_blt_rb) {
7071 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7072 This->depth_blt_rb = 0;
7073 This->depth_blt_rb_w = 0;
7074 This->depth_blt_rb_h = 0;
7078 This->blitter->free_private(iface);
7079 This->frag_pipe->free_private(iface);
7080 This->shader_backend->shader_free_private(iface);
7083 for (i = 0; i < GL_LIMITS(textures); i++) {
7084 /* Textures are recreated below */
7085 glDeleteTextures(1, &This->dummyTextureName[i]);
7086 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7087 This->dummyTextureName[i] = 0;
7091 while(This->numContexts) {
7092 DestroyContext(This, This->contexts[0]);
7094 This->activeContext = NULL;
7095 HeapFree(GetProcessHeap(), 0, swapchain->context);
7096 swapchain->context = NULL;
7097 swapchain->num_contexts = 0;
7100 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7102 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7104 IWineD3DSurfaceImpl *target;
7106 /* Recreate the primary swapchain's context */
7107 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7108 if(swapchain->backBuffer) {
7109 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7111 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7113 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7114 &swapchain->presentParms);
7115 swapchain->num_contexts = 1;
7116 This->activeContext = swapchain->context[0];
7118 create_dummy_textures(This);
7120 hr = This->shader_backend->shader_alloc_private(iface);
7122 ERR("Failed to recreate shader private data\n");
7125 hr = This->frag_pipe->alloc_private(iface);
7127 TRACE("Fragment pipeline private data couldn't be allocated\n");
7130 hr = This->blitter->alloc_private(iface);
7132 TRACE("Blitter private data couldn't be allocated\n");
7139 This->blitter->free_private(iface);
7140 This->frag_pipe->free_private(iface);
7141 This->shader_backend->shader_free_private(iface);
7145 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7147 IWineD3DSwapChainImpl *swapchain;
7149 BOOL DisplayModeChanged = FALSE;
7150 WINED3DDISPLAYMODE mode;
7151 TRACE("(%p)\n", This);
7153 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7155 ERR("Failed to get the first implicit swapchain\n");
7159 if(!is_display_mode_supported(This, pPresentationParameters)) {
7160 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7161 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7162 pPresentationParameters->BackBufferHeight);
7163 return WINED3DERR_INVALIDCALL;
7166 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7167 * on an existing gl context, so there's no real need for recreation.
7169 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7171 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7173 TRACE("New params:\n");
7174 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7175 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7176 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7177 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7178 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7179 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7180 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7181 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7182 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7183 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7184 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7185 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7186 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7188 /* No special treatment of these parameters. Just store them */
7189 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7190 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7191 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7192 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7194 /* What to do about these? */
7195 if(pPresentationParameters->BackBufferCount != 0 &&
7196 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7197 ERR("Cannot change the back buffer count yet\n");
7199 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7200 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7201 ERR("Cannot change the back buffer format yet\n");
7203 if(pPresentationParameters->hDeviceWindow != NULL &&
7204 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7205 ERR("Cannot change the device window yet\n");
7207 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7208 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7209 return WINED3DERR_INVALIDCALL;
7212 /* Reset the depth stencil */
7213 if (pPresentationParameters->EnableAutoDepthStencil)
7214 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7216 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7218 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7220 if(pPresentationParameters->Windowed) {
7221 mode.Width = swapchain->orig_width;
7222 mode.Height = swapchain->orig_height;
7223 mode.RefreshRate = 0;
7224 mode.Format = swapchain->presentParms.BackBufferFormat;
7226 mode.Width = pPresentationParameters->BackBufferWidth;
7227 mode.Height = pPresentationParameters->BackBufferHeight;
7228 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7229 mode.Format = swapchain->presentParms.BackBufferFormat;
7232 /* Should Width == 800 && Height == 0 set 800x600? */
7233 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7234 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7235 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7239 if(!pPresentationParameters->Windowed) {
7240 DisplayModeChanged = TRUE;
7242 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7243 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7245 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7246 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7247 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7249 if(This->auto_depth_stencil_buffer) {
7250 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7254 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7255 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7256 DisplayModeChanged) {
7258 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7260 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7261 if(swapchain->presentParms.Windowed) {
7262 /* switch from windowed to fs */
7263 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7264 pPresentationParameters->BackBufferWidth,
7265 pPresentationParameters->BackBufferHeight);
7267 /* Fullscreen -> fullscreen mode change */
7268 MoveWindow(swapchain->win_handle, 0, 0,
7269 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7272 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7273 /* Fullscreen -> windowed switch */
7274 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7276 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7277 } else if(!pPresentationParameters->Windowed) {
7278 DWORD style = This->style, exStyle = This->exStyle;
7279 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7280 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7281 * Reset to clear up their mess. Guild Wars also loses the device during that.
7285 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7286 pPresentationParameters->BackBufferWidth,
7287 pPresentationParameters->BackBufferHeight);
7288 This->style = style;
7289 This->exStyle = exStyle;
7292 TRACE("Resetting stateblock\n");
7293 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7294 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7296 /* Note: No parent needed for initial internal stateblock */
7297 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7298 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7299 else TRACE("Created stateblock %p\n", This->stateBlock);
7300 This->updateStateBlock = This->stateBlock;
7301 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7303 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7305 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7308 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7309 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7311 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7317 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7319 /** FIXME: always true at the moment **/
7320 if(!bEnableDialogs) {
7321 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7327 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7329 TRACE("(%p) : pParameters %p\n", This, pParameters);
7331 *pParameters = This->createParms;
7335 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7336 IWineD3DSwapChain *swapchain;
7338 TRACE("Relaying to swapchain\n");
7340 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7341 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7342 IWineD3DSwapChain_Release(swapchain);
7347 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7348 IWineD3DSwapChain *swapchain;
7350 TRACE("Relaying to swapchain\n");
7352 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7353 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7354 IWineD3DSwapChain_Release(swapchain);
7360 /** ********************************************************
7361 * Notification functions
7362 ** ********************************************************/
7363 /** This function must be called in the release of a resource when ref == 0,
7364 * the contents of resource must still be correct,
7365 * any handles to other resource held by the caller must be closed
7366 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7367 *****************************************************/
7368 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7371 TRACE("(%p) : Adding Resource %p\n", This, resource);
7372 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7375 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7378 TRACE("(%p) : Removing resource %p\n", This, resource);
7380 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7384 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7386 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7389 TRACE("(%p) : resource %p\n", This, resource);
7391 context_resource_released(iface, resource, type);
7394 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7395 case WINED3DRTYPE_SURFACE: {
7398 /* Cleanup any FBO attachments if d3d is enabled */
7399 if(This->d3d_initialized) {
7400 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7401 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7403 TRACE("Last active render target destroyed\n");
7404 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7405 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7406 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7407 * and the lastActiveRenderTarget member shouldn't matter
7410 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7411 TRACE("Activating primary back buffer\n");
7412 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7413 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7414 /* Single buffering environment */
7415 TRACE("Activating primary front buffer\n");
7416 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7418 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7419 /* Implicit render target destroyed, that means the device is being destroyed
7420 * whatever we set here, it shouldn't matter
7422 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7425 /* May happen during ddraw uninitialization */
7426 TRACE("Render target set, but swapchain does not exist!\n");
7427 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7431 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7432 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7433 This->render_targets[i] = NULL;
7436 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7437 This->stencilBufferTarget = NULL;
7443 case WINED3DRTYPE_TEXTURE:
7444 case WINED3DRTYPE_CUBETEXTURE:
7445 case WINED3DRTYPE_VOLUMETEXTURE:
7446 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7447 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7448 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7449 This->stateBlock->textures[counter] = NULL;
7451 if (This->updateStateBlock != This->stateBlock ){
7452 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7453 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7454 This->updateStateBlock->textures[counter] = NULL;
7459 case WINED3DRTYPE_VOLUME:
7460 /* TODO: nothing really? */
7462 case WINED3DRTYPE_VERTEXBUFFER:
7463 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7466 TRACE("Cleaning up stream pointers\n");
7468 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7469 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7470 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7472 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7473 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7474 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7475 This->updateStateBlock->streamSource[streamNumber] = 0;
7476 /* Set changed flag? */
7479 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) */
7480 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7481 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7482 This->stateBlock->streamSource[streamNumber] = 0;
7488 case WINED3DRTYPE_INDEXBUFFER:
7489 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7490 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7491 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7492 This->updateStateBlock->pIndexData = NULL;
7495 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7496 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7497 This->stateBlock->pIndexData = NULL;
7503 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7508 /* Remove the resource from the resourceStore */
7509 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7511 TRACE("Resource released\n");
7515 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7517 IWineD3DResourceImpl *resource, *cursor;
7519 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7521 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7522 TRACE("enumerating resource %p\n", resource);
7523 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7524 ret = pCallback((IWineD3DResource *) resource, pData);
7525 if(ret == S_FALSE) {
7526 TRACE("Canceling enumeration\n");
7533 /**********************************************************
7534 * IWineD3DDevice VTbl follows
7535 **********************************************************/
7537 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7539 /*** IUnknown methods ***/
7540 IWineD3DDeviceImpl_QueryInterface,
7541 IWineD3DDeviceImpl_AddRef,
7542 IWineD3DDeviceImpl_Release,
7543 /*** IWineD3DDevice methods ***/
7544 IWineD3DDeviceImpl_GetParent,
7545 /*** Creation methods**/
7546 IWineD3DDeviceImpl_CreateVertexBuffer,
7547 IWineD3DDeviceImpl_CreateIndexBuffer,
7548 IWineD3DDeviceImpl_CreateStateBlock,
7549 IWineD3DDeviceImpl_CreateSurface,
7550 IWineD3DDeviceImpl_CreateTexture,
7551 IWineD3DDeviceImpl_CreateVolumeTexture,
7552 IWineD3DDeviceImpl_CreateVolume,
7553 IWineD3DDeviceImpl_CreateCubeTexture,
7554 IWineD3DDeviceImpl_CreateQuery,
7555 IWineD3DDeviceImpl_CreateSwapChain,
7556 IWineD3DDeviceImpl_CreateVertexDeclaration,
7557 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7558 IWineD3DDeviceImpl_CreateVertexShader,
7559 IWineD3DDeviceImpl_CreatePixelShader,
7560 IWineD3DDeviceImpl_CreatePalette,
7561 /*** Odd functions **/
7562 IWineD3DDeviceImpl_Init3D,
7563 IWineD3DDeviceImpl_InitGDI,
7564 IWineD3DDeviceImpl_Uninit3D,
7565 IWineD3DDeviceImpl_UninitGDI,
7566 IWineD3DDeviceImpl_SetMultithreaded,
7567 IWineD3DDeviceImpl_EvictManagedResources,
7568 IWineD3DDeviceImpl_GetAvailableTextureMem,
7569 IWineD3DDeviceImpl_GetBackBuffer,
7570 IWineD3DDeviceImpl_GetCreationParameters,
7571 IWineD3DDeviceImpl_GetDeviceCaps,
7572 IWineD3DDeviceImpl_GetDirect3D,
7573 IWineD3DDeviceImpl_GetDisplayMode,
7574 IWineD3DDeviceImpl_SetDisplayMode,
7575 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7576 IWineD3DDeviceImpl_GetRasterStatus,
7577 IWineD3DDeviceImpl_GetSwapChain,
7578 IWineD3DDeviceImpl_Reset,
7579 IWineD3DDeviceImpl_SetDialogBoxMode,
7580 IWineD3DDeviceImpl_SetCursorProperties,
7581 IWineD3DDeviceImpl_SetCursorPosition,
7582 IWineD3DDeviceImpl_ShowCursor,
7583 IWineD3DDeviceImpl_TestCooperativeLevel,
7584 /*** Getters and setters **/
7585 IWineD3DDeviceImpl_SetClipPlane,
7586 IWineD3DDeviceImpl_GetClipPlane,
7587 IWineD3DDeviceImpl_SetClipStatus,
7588 IWineD3DDeviceImpl_GetClipStatus,
7589 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7590 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7591 IWineD3DDeviceImpl_SetDepthStencilSurface,
7592 IWineD3DDeviceImpl_GetDepthStencilSurface,
7593 IWineD3DDeviceImpl_SetGammaRamp,
7594 IWineD3DDeviceImpl_GetGammaRamp,
7595 IWineD3DDeviceImpl_SetIndices,
7596 IWineD3DDeviceImpl_GetIndices,
7597 IWineD3DDeviceImpl_SetBaseVertexIndex,
7598 IWineD3DDeviceImpl_GetBaseVertexIndex,
7599 IWineD3DDeviceImpl_SetLight,
7600 IWineD3DDeviceImpl_GetLight,
7601 IWineD3DDeviceImpl_SetLightEnable,
7602 IWineD3DDeviceImpl_GetLightEnable,
7603 IWineD3DDeviceImpl_SetMaterial,
7604 IWineD3DDeviceImpl_GetMaterial,
7605 IWineD3DDeviceImpl_SetNPatchMode,
7606 IWineD3DDeviceImpl_GetNPatchMode,
7607 IWineD3DDeviceImpl_SetPaletteEntries,
7608 IWineD3DDeviceImpl_GetPaletteEntries,
7609 IWineD3DDeviceImpl_SetPixelShader,
7610 IWineD3DDeviceImpl_GetPixelShader,
7611 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7612 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7613 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7614 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7615 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7616 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7617 IWineD3DDeviceImpl_SetRenderState,
7618 IWineD3DDeviceImpl_GetRenderState,
7619 IWineD3DDeviceImpl_SetRenderTarget,
7620 IWineD3DDeviceImpl_GetRenderTarget,
7621 IWineD3DDeviceImpl_SetFrontBackBuffers,
7622 IWineD3DDeviceImpl_SetSamplerState,
7623 IWineD3DDeviceImpl_GetSamplerState,
7624 IWineD3DDeviceImpl_SetScissorRect,
7625 IWineD3DDeviceImpl_GetScissorRect,
7626 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7627 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7628 IWineD3DDeviceImpl_SetStreamSource,
7629 IWineD3DDeviceImpl_GetStreamSource,
7630 IWineD3DDeviceImpl_SetStreamSourceFreq,
7631 IWineD3DDeviceImpl_GetStreamSourceFreq,
7632 IWineD3DDeviceImpl_SetTexture,
7633 IWineD3DDeviceImpl_GetTexture,
7634 IWineD3DDeviceImpl_SetTextureStageState,
7635 IWineD3DDeviceImpl_GetTextureStageState,
7636 IWineD3DDeviceImpl_SetTransform,
7637 IWineD3DDeviceImpl_GetTransform,
7638 IWineD3DDeviceImpl_SetVertexDeclaration,
7639 IWineD3DDeviceImpl_GetVertexDeclaration,
7640 IWineD3DDeviceImpl_SetVertexShader,
7641 IWineD3DDeviceImpl_GetVertexShader,
7642 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7643 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7644 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7645 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7646 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7647 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7648 IWineD3DDeviceImpl_SetViewport,
7649 IWineD3DDeviceImpl_GetViewport,
7650 IWineD3DDeviceImpl_MultiplyTransform,
7651 IWineD3DDeviceImpl_ValidateDevice,
7652 IWineD3DDeviceImpl_ProcessVertices,
7653 /*** State block ***/
7654 IWineD3DDeviceImpl_BeginStateBlock,
7655 IWineD3DDeviceImpl_EndStateBlock,
7656 /*** Scene management ***/
7657 IWineD3DDeviceImpl_BeginScene,
7658 IWineD3DDeviceImpl_EndScene,
7659 IWineD3DDeviceImpl_Present,
7660 IWineD3DDeviceImpl_Clear,
7662 IWineD3DDeviceImpl_DrawPrimitive,
7663 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7664 IWineD3DDeviceImpl_DrawPrimitiveUP,
7665 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7666 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7667 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7668 IWineD3DDeviceImpl_DrawRectPatch,
7669 IWineD3DDeviceImpl_DrawTriPatch,
7670 IWineD3DDeviceImpl_DeletePatch,
7671 IWineD3DDeviceImpl_ColorFill,
7672 IWineD3DDeviceImpl_UpdateTexture,
7673 IWineD3DDeviceImpl_UpdateSurface,
7674 IWineD3DDeviceImpl_GetFrontBufferData,
7675 /*** object tracking ***/
7676 IWineD3DDeviceImpl_ResourceReleased,
7677 IWineD3DDeviceImpl_EnumResources
7680 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7681 WINED3DRS_ALPHABLENDENABLE ,
7682 WINED3DRS_ALPHAFUNC ,
7683 WINED3DRS_ALPHAREF ,
7684 WINED3DRS_ALPHATESTENABLE ,
7686 WINED3DRS_COLORWRITEENABLE ,
7687 WINED3DRS_DESTBLEND ,
7688 WINED3DRS_DITHERENABLE ,
7689 WINED3DRS_FILLMODE ,
7690 WINED3DRS_FOGDENSITY ,
7692 WINED3DRS_FOGSTART ,
7693 WINED3DRS_LASTPIXEL ,
7694 WINED3DRS_SHADEMODE ,
7695 WINED3DRS_SRCBLEND ,
7696 WINED3DRS_STENCILENABLE ,
7697 WINED3DRS_STENCILFAIL ,
7698 WINED3DRS_STENCILFUNC ,
7699 WINED3DRS_STENCILMASK ,
7700 WINED3DRS_STENCILPASS ,
7701 WINED3DRS_STENCILREF ,
7702 WINED3DRS_STENCILWRITEMASK ,
7703 WINED3DRS_STENCILZFAIL ,
7704 WINED3DRS_TEXTUREFACTOR ,
7715 WINED3DRS_ZWRITEENABLE
7718 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7719 WINED3DTSS_ALPHAARG0 ,
7720 WINED3DTSS_ALPHAARG1 ,
7721 WINED3DTSS_ALPHAARG2 ,
7722 WINED3DTSS_ALPHAOP ,
7723 WINED3DTSS_BUMPENVLOFFSET ,
7724 WINED3DTSS_BUMPENVLSCALE ,
7725 WINED3DTSS_BUMPENVMAT00 ,
7726 WINED3DTSS_BUMPENVMAT01 ,
7727 WINED3DTSS_BUMPENVMAT10 ,
7728 WINED3DTSS_BUMPENVMAT11 ,
7729 WINED3DTSS_COLORARG0 ,
7730 WINED3DTSS_COLORARG1 ,
7731 WINED3DTSS_COLORARG2 ,
7732 WINED3DTSS_COLOROP ,
7733 WINED3DTSS_RESULTARG ,
7734 WINED3DTSS_TEXCOORDINDEX ,
7735 WINED3DTSS_TEXTURETRANSFORMFLAGS
7738 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7739 WINED3DSAMP_ADDRESSU ,
7740 WINED3DSAMP_ADDRESSV ,
7741 WINED3DSAMP_ADDRESSW ,
7742 WINED3DSAMP_BORDERCOLOR ,
7743 WINED3DSAMP_MAGFILTER ,
7744 WINED3DSAMP_MINFILTER ,
7745 WINED3DSAMP_MIPFILTER ,
7746 WINED3DSAMP_MIPMAPLODBIAS ,
7747 WINED3DSAMP_MAXMIPLEVEL ,
7748 WINED3DSAMP_MAXANISOTROPY ,
7749 WINED3DSAMP_SRGBTEXTURE ,
7750 WINED3DSAMP_ELEMENTINDEX
7753 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7755 WINED3DRS_AMBIENTMATERIALSOURCE ,
7756 WINED3DRS_CLIPPING ,
7757 WINED3DRS_CLIPPLANEENABLE ,
7758 WINED3DRS_COLORVERTEX ,
7759 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7760 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7761 WINED3DRS_FOGDENSITY ,
7763 WINED3DRS_FOGSTART ,
7764 WINED3DRS_FOGTABLEMODE ,
7765 WINED3DRS_FOGVERTEXMODE ,
7766 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7767 WINED3DRS_LIGHTING ,
7768 WINED3DRS_LOCALVIEWER ,
7769 WINED3DRS_MULTISAMPLEANTIALIAS ,
7770 WINED3DRS_MULTISAMPLEMASK ,
7771 WINED3DRS_NORMALIZENORMALS ,
7772 WINED3DRS_PATCHEDGESTYLE ,
7773 WINED3DRS_POINTSCALE_A ,
7774 WINED3DRS_POINTSCALE_B ,
7775 WINED3DRS_POINTSCALE_C ,
7776 WINED3DRS_POINTSCALEENABLE ,
7777 WINED3DRS_POINTSIZE ,
7778 WINED3DRS_POINTSIZE_MAX ,
7779 WINED3DRS_POINTSIZE_MIN ,
7780 WINED3DRS_POINTSPRITEENABLE ,
7781 WINED3DRS_RANGEFOGENABLE ,
7782 WINED3DRS_SPECULARMATERIALSOURCE ,
7783 WINED3DRS_TWEENFACTOR ,
7784 WINED3DRS_VERTEXBLEND ,
7785 WINED3DRS_CULLMODE ,
7789 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7790 WINED3DTSS_TEXCOORDINDEX ,
7791 WINED3DTSS_TEXTURETRANSFORMFLAGS
7794 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7795 WINED3DSAMP_DMAPOFFSET
7798 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7799 DWORD rep = This->StateTable[state].representative;
7803 WineD3DContext *context;
7806 for(i = 0; i < This->numContexts; i++) {
7807 context = This->contexts[i];
7808 if(isStateDirty(context, rep)) continue;
7810 context->dirtyArray[context->numDirtyEntries++] = rep;
7813 context->isStateDirty[idx] |= (1 << shift);
7817 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7818 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7819 /* The drawable size of a pbuffer render target is the current pbuffer size
7821 *width = dev->pbufferWidth;
7822 *height = dev->pbufferHeight;
7825 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7826 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7828 *width = This->pow2Width;
7829 *height = This->pow2Height;
7832 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7833 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7834 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7835 * current context's drawable, which is the size of the back buffer of the swapchain
7836 * the active context belongs to. The back buffer of the swapchain is stored as the
7837 * surface the context belongs to.
7839 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7840 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;