push 8724397e7ede0f147b6e05994a72142d44d4fecc
[wine/hacks.git] / dlls / wined3d / device.c
blob871a59abf203d117d05cb67e292eabf9c77b3a88
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-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
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /**********************************************************
58 * Global variable / Constants follow
59 **********************************************************/
60 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
62 /**********************************************************
63 * IUnknown parts follows
64 **********************************************************/
66 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
68 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
70 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
71 if (IsEqualGUID(riid, &IID_IUnknown)
72 || IsEqualGUID(riid, &IID_IWineD3DBase)
73 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
74 IUnknown_AddRef(iface);
75 *ppobj = This;
76 return S_OK;
78 *ppobj = NULL;
79 return E_NOINTERFACE;
82 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
83 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
84 ULONG refCount = InterlockedIncrement(&This->ref);
86 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
87 return refCount;
90 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
91 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
92 ULONG refCount = InterlockedDecrement(&This->ref);
94 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
96 if (!refCount) {
97 UINT i;
99 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
100 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
101 This->multistate_funcs[i] = NULL;
104 /* TODO: Clean up all the surfaces and textures! */
105 /* NOTE: You must release the parent if the object was created via a callback
106 ** ***************************/
108 if (!list_empty(&This->resources)) {
109 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
110 dumpResources(&This->resources);
113 if(This->contexts) ERR("Context array not freed!\n");
114 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
115 This->haveHardwareCursor = FALSE;
117 IWineD3D_Release(This->wineD3D);
118 This->wineD3D = NULL;
119 HeapFree(GetProcessHeap(), 0, This);
120 TRACE("Freed device %p\n", This);
121 This = NULL;
123 return refCount;
126 /**********************************************************
127 * IWineD3DDevice implementation follows
128 **********************************************************/
129 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
131 *pParent = This->parent;
132 IUnknown_AddRef(This->parent);
133 return WINED3D_OK;
136 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface,
137 struct wined3d_buffer_desc *desc, IUnknown *parent, IWineD3DBuffer **buffer)
139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
140 struct wined3d_buffer *object;
141 HRESULT hr;
143 TRACE("iface %p, desc %p, parent %p, buffer %p\n", iface, desc, parent, buffer);
145 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
146 if (!object)
148 ERR("Failed to allocate memory\n");
149 return E_OUTOFMEMORY;
152 object->vtbl = &wined3d_buffer_vtbl;
153 object->desc = *desc;
155 FIXME("Ignoring access flags (pool)\n");
157 hr = resource_init(&object->resource, WINED3DRTYPE_BUFFER, This, desc->byte_width,
158 desc->usage, WINED3DFMT_UNKNOWN, WINED3DPOOL_MANAGED, parent);
159 if (FAILED(hr))
161 WARN("Failed to initialize resource, returning %#x\n", hr);
162 HeapFree(GetProcessHeap(), 0, object);
163 return hr;
166 TRACE("Created resource %p\n", object);
168 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
170 TRACE("size %#x, usage=%#x, format %s, memory @ %p, iface @ %p\n", object->resource.size, object->resource.usage,
171 debug_d3dformat(object->resource.format), object->resource.allocatedMemory, object);
173 *buffer = (IWineD3DBuffer *)object;
175 return WINED3D_OK;
178 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
179 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
180 IUnknown *parent) {
181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
182 IWineD3DVertexBufferImpl *object;
183 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
184 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
185 HRESULT hr;
186 BOOL conv;
188 if(Size == 0) {
189 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
190 *ppVertexBuffer = NULL;
191 return WINED3DERR_INVALIDCALL;
192 } else if(Pool == WINED3DPOOL_SCRATCH) {
193 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
194 * anyway, SCRATCH vertex buffers aren't usable anywhere
196 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
197 *ppVertexBuffer = NULL;
198 return WINED3DERR_INVALIDCALL;
201 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
202 if (!object)
204 ERR("Out of memory\n");
205 *ppVertexBuffer = NULL;
206 return WINED3DERR_OUTOFVIDEOMEMORY;
209 object->lpVtbl = &IWineD3DVertexBuffer_Vtbl;
210 hr = resource_init(&object->resource, WINED3DRTYPE_VERTEXBUFFER, This, Size, Usage, Format, Pool, parent);
211 if (FAILED(hr))
213 WARN("Failed to initialize resource, returning %#x\n", hr);
214 HeapFree(GetProcessHeap(), 0, object);
215 *ppVertexBuffer = NULL;
216 return hr;
219 TRACE("(%p) : Created resource %p\n", This, object);
221 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
223 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);
224 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
226 object->fvf = FVF;
228 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
229 * drawStridedFast (half-life 2).
231 * Basically converting the vertices in the buffer is quite expensive, and observations
232 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
233 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
235 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
236 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
237 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
238 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
239 * dx7 apps.
240 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
241 * more. In this call we can convert dx7 buffers too.
243 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
244 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
245 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
246 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
247 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
248 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
249 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
250 } else if(dxVersion <= 7 && conv) {
251 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
252 } else {
253 object->Flags |= VBFLAG_CREATEVBO;
255 return WINED3D_OK;
258 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
259 GLenum error, glUsage;
260 TRACE("Creating VBO for Index Buffer %p\n", object);
262 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
263 * restored on the next draw
265 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
267 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
268 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
269 ENTER_GL();
271 while(glGetError());
273 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
274 error = glGetError();
275 if(error != GL_NO_ERROR || object->vbo == 0) {
276 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
277 goto out;
280 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
281 error = glGetError();
282 if(error != GL_NO_ERROR) {
283 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
284 goto out;
287 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
288 * copy no readback will be needed
290 glUsage = GL_STATIC_DRAW_ARB;
291 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
292 error = glGetError();
293 if(error != GL_NO_ERROR) {
294 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
295 goto out;
297 LEAVE_GL();
298 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
299 return;
301 out:
302 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
303 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
304 LEAVE_GL();
305 object->vbo = 0;
308 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
309 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
310 HANDLE *sharedHandle, IUnknown *parent) {
311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
312 IWineD3DIndexBufferImpl *object;
313 HRESULT hr;
315 TRACE("(%p) Creating index buffer\n", This);
317 /* Allocate the storage for the device */
318 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
319 if (!object)
321 ERR("Out of memory\n");
322 *ppIndexBuffer = NULL;
323 return WINED3DERR_OUTOFVIDEOMEMORY;
326 object->lpVtbl = &IWineD3DIndexBuffer_Vtbl;
327 hr = resource_init(&object->resource, WINED3DRTYPE_INDEXBUFFER, This, Length, Usage, Format, Pool, parent);
328 if (FAILED(hr))
330 WARN("Failed to initialize resource, returning %#x\n", hr);
331 HeapFree(GetProcessHeap(), 0, object);
332 *ppIndexBuffer = NULL;
333 return hr;
336 TRACE("(%p) : Created resource %p\n", This, object);
338 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
340 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
341 CreateIndexBufferVBO(This, object);
344 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
345 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
346 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
348 return WINED3D_OK;
351 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
353 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
354 IWineD3DStateBlockImpl *object;
355 int i, j;
356 HRESULT temp_result;
358 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
359 if(!object)
361 ERR("Out of memory\n");
362 *ppStateBlock = NULL;
363 return WINED3DERR_OUTOFVIDEOMEMORY;
366 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
367 object->wineD3DDevice = This;
368 object->parent = parent;
369 object->ref = 1;
370 object->blockType = Type;
372 *ppStateBlock = (IWineD3DStateBlock *)object;
374 for(i = 0; i < LIGHTMAP_SIZE; i++) {
375 list_init(&object->lightMap[i]);
378 temp_result = allocate_shader_constants(object);
379 if (FAILED(temp_result))
381 HeapFree(GetProcessHeap(), 0, object);
382 return temp_result;
385 /* Special case - Used during initialization to produce a placeholder stateblock
386 so other functions called can update a state block */
387 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
389 /* Don't bother increasing the reference count otherwise a device will never
390 be freed due to circular dependencies */
391 return WINED3D_OK;
394 /* Otherwise, might as well set the whole state block to the appropriate values */
395 if (This->stateBlock != NULL)
396 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
397 else
398 memset(object->streamFreq, 1, sizeof(object->streamFreq));
400 /* Reset the ref and type after kludging it */
401 object->wineD3DDevice = This;
402 object->ref = 1;
403 object->blockType = Type;
405 TRACE("Updating changed flags appropriate for type %d\n", Type);
407 if (Type == WINED3DSBT_ALL) {
409 TRACE("ALL => Pretend everything has changed\n");
410 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
412 /* Lights are not part of the changed / set structure */
413 for(j = 0; j < LIGHTMAP_SIZE; j++) {
414 struct list *e;
415 LIST_FOR_EACH(e, &object->lightMap[j]) {
416 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
417 light->changed = TRUE;
418 light->enabledChanged = TRUE;
421 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
422 object->contained_render_states[j - 1] = j;
424 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
425 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
426 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
427 object->contained_transform_states[j - 1] = j;
429 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
430 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
431 object->contained_vs_consts_f[j] = j;
433 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
434 for(j = 0; j < MAX_CONST_I; j++) {
435 object->contained_vs_consts_i[j] = j;
437 object->num_contained_vs_consts_i = MAX_CONST_I;
438 for(j = 0; j < MAX_CONST_B; j++) {
439 object->contained_vs_consts_b[j] = j;
441 object->num_contained_vs_consts_b = MAX_CONST_B;
442 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
443 object->contained_ps_consts_f[j] = j;
445 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
446 for(j = 0; j < MAX_CONST_I; j++) {
447 object->contained_ps_consts_i[j] = j;
449 object->num_contained_ps_consts_i = MAX_CONST_I;
450 for(j = 0; j < MAX_CONST_B; j++) {
451 object->contained_ps_consts_b[j] = j;
453 object->num_contained_ps_consts_b = MAX_CONST_B;
454 for(i = 0; i < MAX_TEXTURES; i++) {
455 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
457 object->contained_tss_states[object->num_contained_tss_states].stage = i;
458 object->contained_tss_states[object->num_contained_tss_states].state = j;
459 object->num_contained_tss_states++;
462 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
463 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
464 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
465 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
466 object->num_contained_sampler_states++;
470 for(i = 0; i < MAX_STREAMS; i++) {
471 if(object->streamSource[i]) {
472 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
475 if(object->pIndexData) {
476 IWineD3DIndexBuffer_AddRef(object->pIndexData);
478 if(object->vertexShader) {
479 IWineD3DVertexShader_AddRef(object->vertexShader);
481 if(object->pixelShader) {
482 IWineD3DPixelShader_AddRef(object->pixelShader);
485 } else if (Type == WINED3DSBT_PIXELSTATE) {
487 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
488 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
490 object->changed.pixelShader = TRUE;
492 /* Pixel Shader Constants */
493 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
494 object->contained_ps_consts_f[i] = i;
495 object->changed.pixelShaderConstantsF[i] = TRUE;
497 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
498 for (i = 0; i < MAX_CONST_B; ++i) {
499 object->contained_ps_consts_b[i] = i;
500 object->changed.pixelShaderConstantsB |= (1 << i);
502 object->num_contained_ps_consts_b = MAX_CONST_B;
503 for (i = 0; i < MAX_CONST_I; ++i) {
504 object->contained_ps_consts_i[i] = i;
505 object->changed.pixelShaderConstantsI |= (1 << i);
507 object->num_contained_ps_consts_i = MAX_CONST_I;
509 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
510 DWORD rs = SavedPixelStates_R[i];
511 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
512 object->contained_render_states[i] = rs;
514 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
515 for (j = 0; j < MAX_TEXTURES; j++) {
516 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
517 DWORD state = SavedPixelStates_T[i];
518 object->changed.textureState[j] |= 1 << state;
519 object->contained_tss_states[object->num_contained_tss_states].stage = j;
520 object->contained_tss_states[object->num_contained_tss_states].state = state;
521 object->num_contained_tss_states++;
524 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
525 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
526 DWORD state = SavedPixelStates_S[i];
527 object->changed.samplerState[j] |= 1 << state;
528 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
529 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
530 object->num_contained_sampler_states++;
533 if(object->pixelShader) {
534 IWineD3DPixelShader_AddRef(object->pixelShader);
537 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
538 * on them. This makes releasing the buffer easier
540 for(i = 0; i < MAX_STREAMS; i++) {
541 object->streamSource[i] = NULL;
543 object->pIndexData = NULL;
544 object->vertexShader = NULL;
546 } else if (Type == WINED3DSBT_VERTEXSTATE) {
548 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
549 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
551 object->changed.vertexShader = TRUE;
553 /* Vertex Shader Constants */
554 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
555 object->changed.vertexShaderConstantsF[i] = TRUE;
556 object->contained_vs_consts_f[i] = i;
558 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
559 for (i = 0; i < MAX_CONST_B; ++i) {
560 object->contained_vs_consts_b[i] = i;
561 object->changed.vertexShaderConstantsB |= (1 << i);
563 object->num_contained_vs_consts_b = MAX_CONST_B;
564 for (i = 0; i < MAX_CONST_I; ++i) {
565 object->contained_vs_consts_i[i] = i;
566 object->changed.vertexShaderConstantsI |= (1 << i);
568 object->num_contained_vs_consts_i = MAX_CONST_I;
569 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
570 DWORD rs = SavedVertexStates_R[i];
571 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
572 object->contained_render_states[i] = rs;
574 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
575 for (j = 0; j < MAX_TEXTURES; j++) {
576 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
577 DWORD state = SavedVertexStates_T[i];
578 object->changed.textureState[j] |= 1 << state;
579 object->contained_tss_states[object->num_contained_tss_states].stage = j;
580 object->contained_tss_states[object->num_contained_tss_states].state = state;
581 object->num_contained_tss_states++;
584 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
585 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
586 DWORD state = SavedVertexStates_S[i];
587 object->changed.samplerState[j] |= 1 << state;
588 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
589 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
590 object->num_contained_sampler_states++;
594 for(j = 0; j < LIGHTMAP_SIZE; j++) {
595 struct list *e;
596 LIST_FOR_EACH(e, &object->lightMap[j]) {
597 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
598 light->changed = TRUE;
599 light->enabledChanged = TRUE;
603 for(i = 0; i < MAX_STREAMS; i++) {
604 if(object->streamSource[i]) {
605 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
608 if(object->vertexShader) {
609 IWineD3DVertexShader_AddRef(object->vertexShader);
611 object->pIndexData = NULL;
612 object->pixelShader = NULL;
613 } else {
614 FIXME("Unrecognized state block type %d\n", Type);
617 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
618 return WINED3D_OK;
621 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) {
622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
623 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
624 unsigned int Size = 1;
625 const struct GlPixelFormatDesc *glDesc;
626 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
627 UINT mul_4w, mul_4h;
628 HRESULT hr;
630 TRACE("(%p) Create surface\n",This);
632 if(MultisampleQuality > 0) {
633 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
634 MultisampleQuality=0;
637 /** FIXME: Check that the format is supported
638 * by the device.
639 *******************************/
641 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
642 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
643 * space!
644 *********************************/
645 mul_4w = (Width + 3) & ~3;
646 mul_4h = (Height + 3) & ~3;
647 if (WINED3DFMT_UNKNOWN == Format) {
648 Size = 0;
649 } else if (Format == WINED3DFMT_DXT1) {
650 /* DXT1 is half byte per pixel */
651 Size = (mul_4w * tableEntry->bpp * mul_4h) >> 1;
653 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
654 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
655 Format == WINED3DFMT_ATI2N) {
656 Size = (mul_4w * tableEntry->bpp * mul_4h);
657 } else {
658 /* The pitch is a multiple of 4 bytes */
659 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
660 Size *= Height;
663 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
665 /** Create and initialise the surface resource **/
666 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
667 if (!object)
669 ERR("Out of memory\n");
670 *ppSurface = NULL;
671 return WINED3DERR_OUTOFVIDEOMEMORY;
674 /* Look at the implementation and set the correct Vtable */
675 switch(Impl)
677 case SURFACE_OPENGL:
678 /* Check if a 3D adapter is available when creating gl surfaces */
679 if (!This->adapter)
681 ERR("OpenGL surfaces are not available without opengl\n");
682 HeapFree(GetProcessHeap(), 0, object);
683 return WINED3DERR_NOTAVAILABLE;
685 object->lpVtbl = &IWineD3DSurface_Vtbl;
686 break;
688 case SURFACE_GDI:
689 object->lpVtbl = &IWineGDISurface_Vtbl;
690 break;
692 default:
693 /* To be sure to catch this */
694 ERR("Unknown requested surface implementation %d!\n", Impl);
695 HeapFree(GetProcessHeap(), 0, object);
696 return WINED3DERR_INVALIDCALL;
699 hr = resource_init(&object->resource, WINED3DRTYPE_SURFACE, This, Size, Usage, Format, Pool, parent);
700 if (FAILED(hr))
702 WARN("Failed to initialize resource, returning %#x\n", hr);
703 HeapFree(GetProcessHeap(), 0, object);
704 *ppSurface = NULL;
705 return hr;
708 TRACE("(%p) : Created resource %p\n", This, object);
710 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
712 *ppSurface = (IWineD3DSurface *)object;
714 /* "Standalone" surface */
715 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
717 object->currentDesc.Width = Width;
718 object->currentDesc.Height = Height;
719 object->currentDesc.MultiSampleType = MultiSample;
720 object->currentDesc.MultiSampleQuality = MultisampleQuality;
721 object->glDescription.level = Level;
722 object->heightscale = glDesc->heightscale != 0.0 ? glDesc->heightscale : 1.0;
723 list_init(&object->overlays);
725 /* Flags */
726 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
727 object->Flags |= Discard ? SFLAG_DISCARD : 0;
728 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
729 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
732 if (WINED3DFMT_UNKNOWN != Format) {
733 object->bytesPerPixel = tableEntry->bpp;
734 } else {
735 object->bytesPerPixel = 0;
738 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
740 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
742 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
743 * this function is too deep to need to care about things like this.
744 * Levels need to be checked too, and possibly Type since they all affect what can be done.
745 * ****************************************/
746 switch(Pool) {
747 case WINED3DPOOL_SCRATCH:
748 if(!Lockable)
749 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
750 "which are mutually exclusive, setting lockable to TRUE\n");
751 Lockable = TRUE;
752 break;
753 case WINED3DPOOL_SYSTEMMEM:
754 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
755 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
756 case WINED3DPOOL_MANAGED:
757 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
758 "Usage of DYNAMIC which are mutually exclusive, not doing "
759 "anything just telling you.\n");
760 break;
761 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
762 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
763 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
764 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
765 break;
766 default:
767 FIXME("(%p) Unknown pool %d\n", This, Pool);
768 break;
771 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
772 FIXME("Trying to create a render target that isn't in the default pool\n");
775 /* mark the texture as dirty so that it gets loaded first time around*/
776 surface_add_dirty_rect(*ppSurface, NULL);
777 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
778 This, Width, Height, Format, debug_d3dformat(Format),
779 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
781 list_init(&object->renderbuffers);
783 /* Call the private setup routine */
784 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)object);
785 if (FAILED(hr))
787 ERR("Private setup failed, returning %#x\n", hr);
788 IWineD3DSurface_Release(*ppSurface);
789 *ppSurface = NULL;
790 return hr;
793 return hr;
796 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
797 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
799 struct wined3d_rendertarget_view *object;
801 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
802 if (!object)
804 ERR("Failed to allocate memory\n");
805 return E_OUTOFMEMORY;
808 object->vtbl = &wined3d_rendertarget_view_vtbl;
809 object->refcount = 1;
810 IWineD3DResource_AddRef(resource);
811 object->resource = resource;
812 object->parent = parent;
814 *rendertarget_view = (IWineD3DRendertargetView *)object;
816 return WINED3D_OK;
819 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
820 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
821 IWineD3DTexture **ppTexture, HANDLE *pSharedHandle, IUnknown *parent)
823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
824 IWineD3DTextureImpl *object;
825 unsigned int i;
826 UINT tmpW;
827 UINT tmpH;
828 HRESULT hr;
829 unsigned int pow2Width;
830 unsigned int pow2Height;
831 const struct GlPixelFormatDesc *glDesc;
832 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
834 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
835 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
836 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
838 /* TODO: It should only be possible to create textures for formats
839 that are reported as supported */
840 if (WINED3DFMT_UNKNOWN >= Format) {
841 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
842 return WINED3DERR_INVALIDCALL;
845 /* Non-power2 support */
846 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO))
848 pow2Width = Width;
849 pow2Height = Height;
851 else
853 /* Find the nearest pow2 match */
854 pow2Width = pow2Height = 1;
855 while (pow2Width < Width) pow2Width <<= 1;
856 while (pow2Height < Height) pow2Height <<= 1;
858 if (pow2Width != Width || pow2Height != Height)
860 if (Levels > 1)
862 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
863 return WINED3DERR_INVALIDCALL;
865 Levels = 1;
869 /* Calculate levels for mip mapping */
870 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
872 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
874 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
875 return WINED3DERR_INVALIDCALL;
878 if (Levels > 1)
880 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
881 return WINED3DERR_INVALIDCALL;
884 Levels = 1;
886 else if (!Levels)
888 Levels = wined3d_log2i(max(Width, Height)) + 1;
889 TRACE("Calculated levels = %d\n", Levels);
892 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
893 if (!object)
895 ERR("Out of memory\n");
896 *ppTexture = NULL;
897 return WINED3DERR_OUTOFVIDEOMEMORY;
900 object->lpVtbl = &IWineD3DTexture_Vtbl;
901 hr = resource_init(&object->resource, WINED3DRTYPE_TEXTURE, This, 0, Usage, Format, Pool, parent);
902 if (FAILED(hr))
904 WARN("Failed to initialize resource, returning %#x\n", hr);
905 HeapFree(GetProcessHeap(), 0, object);
906 *ppTexture = NULL;
907 return hr;
910 TRACE("(%p) : Created resource %p\n", This, object);
912 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
914 *ppTexture = (IWineD3DTexture *)object;
916 basetexture_init(&object->baseTexture, Levels, Usage);
917 object->width = Width;
918 object->height = Height;
920 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
921 object->baseTexture.minMipLookup = minMipLookup;
922 object->baseTexture.magLookup = magLookup;
923 } else {
924 object->baseTexture.minMipLookup = minMipLookup_noFilter;
925 object->baseTexture.magLookup = magLookup_noFilter;
928 /** FIXME: add support for real non-power-two if it's provided by the video card **/
929 /* Precalculated scaling for 'faked' non power of two texture coords.
930 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
931 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
932 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
934 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
935 object->baseTexture.pow2Matrix[0] = 1.0;
936 object->baseTexture.pow2Matrix[5] = 1.0;
937 object->baseTexture.pow2Matrix[10] = 1.0;
938 object->baseTexture.pow2Matrix[15] = 1.0;
939 object->target = GL_TEXTURE_2D;
940 object->cond_np2 = TRUE;
941 object->baseTexture.minMipLookup = minMipLookup_noFilter;
942 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
943 (Width != pow2Width || Height != pow2Height) &&
944 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
946 object->baseTexture.pow2Matrix[0] = (float)Width;
947 object->baseTexture.pow2Matrix[5] = (float)Height;
948 object->baseTexture.pow2Matrix[10] = 1.0;
949 object->baseTexture.pow2Matrix[15] = 1.0;
950 object->target = GL_TEXTURE_RECTANGLE_ARB;
951 object->cond_np2 = TRUE;
952 object->baseTexture.minMipLookup = minMipLookup_noFilter;
953 } else {
954 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
955 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
956 object->baseTexture.pow2Matrix[10] = 1.0;
957 object->baseTexture.pow2Matrix[15] = 1.0;
958 object->target = GL_TEXTURE_2D;
959 object->cond_np2 = FALSE;
961 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
963 /* Generate all the surfaces */
964 tmpW = Width;
965 tmpH = Height;
966 for (i = 0; i < object->baseTexture.levels; i++)
968 /* use the callback to create the texture surface */
969 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpH, Format,
970 Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i]);
971 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
972 FIXME("Failed to create surface %p\n", object);
973 /* clean up */
974 object->surfaces[i] = NULL;
975 IWineD3DTexture_Release((IWineD3DTexture *)object);
977 *ppTexture = NULL;
978 return hr;
981 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
982 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
983 surface_set_texture_target(object->surfaces[i], object->target);
984 /* calculate the next mipmap level */
985 tmpW = max(1, tmpW >> 1);
986 tmpH = max(1, tmpH >> 1);
988 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
989 object->baseTexture.internal_preload = texture_internal_preload;
991 TRACE("(%p) : Created texture %p\n", This, object);
992 return WINED3D_OK;
995 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
996 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
997 IWineD3DVolumeTexture **ppVolumeTexture, HANDLE *pSharedHandle, IUnknown *parent)
999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1000 IWineD3DVolumeTextureImpl *object;
1001 unsigned int i;
1002 UINT tmpW;
1003 UINT tmpH;
1004 UINT tmpD;
1005 const struct GlPixelFormatDesc *glDesc;
1006 HRESULT hr;
1008 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1010 /* TODO: It should only be possible to create textures for formats
1011 that are reported as supported */
1012 if (WINED3DFMT_UNKNOWN >= Format) {
1013 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1014 return WINED3DERR_INVALIDCALL;
1016 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1017 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
1018 return WINED3DERR_INVALIDCALL;
1021 /* Calculate levels for mip mapping */
1022 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1024 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1026 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1027 return WINED3DERR_INVALIDCALL;
1030 if (Levels > 1)
1032 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1033 return WINED3DERR_INVALIDCALL;
1036 Levels = 1;
1038 else if (!Levels)
1040 Levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
1041 TRACE("Calculated levels = %d\n", Levels);
1044 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1045 if (!object)
1047 ERR("Out of memory\n");
1048 *ppVolumeTexture = NULL;
1049 return WINED3DERR_OUTOFVIDEOMEMORY;
1052 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1053 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUMETEXTURE, This, 0, Usage, Format, Pool, parent);
1054 if (FAILED(hr))
1056 WARN("Failed to initialize resource, returning %#x\n", hr);
1057 HeapFree(GetProcessHeap(), 0, object);
1058 *ppVolumeTexture = NULL;
1059 return hr;
1062 TRACE("(%p) : Created resource %p\n", This, object);
1064 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1066 basetexture_init(&object->baseTexture, Levels, Usage);
1068 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1069 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1071 /* Is NP2 support for volumes needed? */
1072 object->baseTexture.pow2Matrix[ 0] = 1.0;
1073 object->baseTexture.pow2Matrix[ 5] = 1.0;
1074 object->baseTexture.pow2Matrix[10] = 1.0;
1075 object->baseTexture.pow2Matrix[15] = 1.0;
1077 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1078 object->baseTexture.minMipLookup = minMipLookup;
1079 object->baseTexture.magLookup = magLookup;
1080 } else {
1081 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1082 object->baseTexture.magLookup = magLookup_noFilter;
1085 /* Generate all the surfaces */
1086 tmpW = Width;
1087 tmpH = Height;
1088 tmpD = Depth;
1090 for (i = 0; i < object->baseTexture.levels; i++)
1092 HRESULT hr;
1093 /* Create the volume */
1094 hr = IWineD3DDeviceParent_CreateVolume(This->device_parent, parent,
1095 tmpW, tmpH, tmpD, Format, Pool, Usage, &object->volumes[i]);
1096 if(FAILED(hr)) {
1097 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1098 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1099 *ppVolumeTexture = NULL;
1100 return hr;
1103 /* Set its container to this object */
1104 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1106 /* calculate the next mipmap level */
1107 tmpW = max(1, tmpW >> 1);
1108 tmpH = max(1, tmpH >> 1);
1109 tmpD = max(1, tmpD >> 1);
1111 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
1112 object->baseTexture.internal_preload = volumetexture_internal_preload;
1114 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1115 TRACE("(%p) : Created volume texture %p\n", This, object);
1116 return WINED3D_OK;
1119 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1120 UINT Width, UINT Height, UINT Depth,
1121 DWORD Usage,
1122 WINED3DFORMAT Format, WINED3DPOOL Pool,
1123 IWineD3DVolume** ppVolume,
1124 HANDLE* pSharedHandle, IUnknown *parent) {
1126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1127 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1128 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1129 HRESULT hr;
1131 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1132 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1133 return WINED3DERR_INVALIDCALL;
1136 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1137 if (!object)
1139 ERR("Out of memory\n");
1140 *ppVolume = NULL;
1141 return WINED3DERR_OUTOFVIDEOMEMORY;
1144 object->lpVtbl = &IWineD3DVolume_Vtbl;
1145 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUME, This,
1146 Width * Height * Depth * formatDesc->bpp, Usage, Format, Pool, parent);
1147 if (FAILED(hr))
1149 WARN("Failed to initialize resource, returning %#x\n", hr);
1150 HeapFree(GetProcessHeap(), 0, object);
1151 *ppVolume = NULL;
1152 return hr;
1155 TRACE("(%p) : Created resource %p\n", This, object);
1157 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1159 *ppVolume = (IWineD3DVolume *)object;
1161 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1162 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1164 object->currentDesc.Width = Width;
1165 object->currentDesc.Height = Height;
1166 object->currentDesc.Depth = Depth;
1167 object->bytesPerPixel = formatDesc->bpp;
1169 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1170 object->lockable = TRUE;
1171 object->locked = FALSE;
1172 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1173 object->dirty = TRUE;
1175 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1177 return WINED3D_OK;
1180 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1181 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1182 IWineD3DCubeTexture **ppCubeTexture, HANDLE *pSharedHandle, IUnknown *parent)
1184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1185 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1186 unsigned int i, j;
1187 UINT tmpW;
1188 HRESULT hr;
1189 unsigned int pow2EdgeLength;
1190 const struct GlPixelFormatDesc *glDesc;
1191 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1193 /* TODO: It should only be possible to create textures for formats
1194 that are reported as supported */
1195 if (WINED3DFMT_UNKNOWN >= Format) {
1196 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1197 return WINED3DERR_INVALIDCALL;
1200 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1201 WARN("(%p) : Tried to create not supported cube texture\n", This);
1202 return WINED3DERR_INVALIDCALL;
1205 /* Calculate levels for mip mapping */
1206 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1208 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1210 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1211 return WINED3DERR_INVALIDCALL;
1214 if (Levels > 1)
1216 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1217 return WINED3DERR_INVALIDCALL;
1220 Levels = 1;
1222 else if (!Levels)
1224 Levels = wined3d_log2i(EdgeLength) + 1;
1225 TRACE("Calculated levels = %d\n", Levels);
1228 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1229 if (!object)
1231 ERR("Out of memory\n");
1232 *ppCubeTexture = NULL;
1233 return WINED3DERR_OUTOFVIDEOMEMORY;
1236 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1237 hr = resource_init(&object->resource, WINED3DRTYPE_CUBETEXTURE, This, 0, Usage, Format, Pool, parent);
1238 if (FAILED(hr))
1240 WARN("Failed to initialize resource, returning %#x\n", hr);
1241 HeapFree(GetProcessHeap(), 0, object);
1242 *ppCubeTexture = NULL;
1243 return hr;
1246 TRACE("(%p) : Created resource %p\n", This, object);
1248 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1250 basetexture_init(&object->baseTexture, Levels, Usage);
1252 TRACE("(%p) Create Cube Texture\n", This);
1254 /* Find the nearest pow2 match */
1255 pow2EdgeLength = 1;
1256 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1258 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
1259 /* Precalculated scaling for 'faked' non power of two texture coords */
1260 object->baseTexture.pow2Matrix[ 0] = 1.0;
1261 object->baseTexture.pow2Matrix[ 5] = 1.0;
1262 object->baseTexture.pow2Matrix[10] = 1.0;
1263 object->baseTexture.pow2Matrix[15] = 1.0;
1264 } else {
1265 /* Precalculated scaling for 'faked' non power of two texture coords */
1266 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1267 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1268 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1269 object->baseTexture.pow2Matrix[15] = 1.0;
1272 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1273 object->baseTexture.minMipLookup = minMipLookup;
1274 object->baseTexture.magLookup = magLookup;
1275 } else {
1276 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1277 object->baseTexture.magLookup = magLookup_noFilter;
1280 /* Generate all the surfaces */
1281 tmpW = EdgeLength;
1282 for (i = 0; i < object->baseTexture.levels; i++) {
1284 /* Create the 6 faces */
1285 for (j = 0; j < 6; j++) {
1286 static const GLenum cube_targets[6] = {
1287 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1288 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1289 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1290 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1291 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1292 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1295 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpW,
1296 Format, Usage, Pool, i /* Level */, j, &object->surfaces[j][i]);
1297 if (FAILED(hr))
1299 FIXME("(%p) Failed to create surface\n",object);
1300 IWineD3DCubeTexture_Release((IWineD3DCubeTexture *)object);
1301 *ppCubeTexture = NULL;
1302 return hr;
1304 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1305 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1306 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1308 tmpW = max(1, tmpW >> 1);
1310 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
1311 object->baseTexture.internal_preload = cubetexture_internal_preload;
1313 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1314 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1315 return WINED3D_OK;
1318 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1320 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1321 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1322 const IWineD3DQueryVtbl *vtable;
1324 /* Just a check to see if we support this type of query */
1325 switch(Type) {
1326 case WINED3DQUERYTYPE_OCCLUSION:
1327 TRACE("(%p) occlusion query\n", This);
1328 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1329 hr = WINED3D_OK;
1330 else
1331 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1333 vtable = &IWineD3DOcclusionQuery_Vtbl;
1334 break;
1336 case WINED3DQUERYTYPE_EVENT:
1337 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1338 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1339 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1341 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1343 vtable = &IWineD3DEventQuery_Vtbl;
1344 hr = WINED3D_OK;
1345 break;
1347 case WINED3DQUERYTYPE_VCACHE:
1348 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1349 case WINED3DQUERYTYPE_VERTEXSTATS:
1350 case WINED3DQUERYTYPE_TIMESTAMP:
1351 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1352 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1353 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1354 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1355 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1356 case WINED3DQUERYTYPE_PIXELTIMINGS:
1357 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1358 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1359 default:
1360 /* Use the base Query vtable until we have a special one for each query */
1361 vtable = &IWineD3DQuery_Vtbl;
1362 FIXME("(%p) Unhandled query type %d\n", This, Type);
1364 if(NULL == ppQuery || hr != WINED3D_OK) {
1365 return hr;
1368 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1369 if(!object)
1371 ERR("Out of memory\n");
1372 *ppQuery = NULL;
1373 return WINED3DERR_OUTOFVIDEOMEMORY;
1376 object->lpVtbl = vtable;
1377 object->type = Type;
1378 object->state = QUERY_CREATED;
1379 object->wineD3DDevice = This;
1380 object->parent = parent;
1381 object->ref = 1;
1383 *ppQuery = (IWineD3DQuery *)object;
1385 /* allocated the 'extended' data based on the type of query requested */
1386 switch(Type){
1387 case WINED3DQUERYTYPE_OCCLUSION:
1388 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1389 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1391 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1392 TRACE("(%p) Allocating data for an occlusion query\n", This);
1394 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1395 ENTER_GL();
1396 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1397 LEAVE_GL();
1398 break;
1400 case WINED3DQUERYTYPE_EVENT:
1401 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1402 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1404 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1405 ENTER_GL();
1406 if(GL_SUPPORT(APPLE_FENCE)) {
1407 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1408 checkGLcall("glGenFencesAPPLE");
1409 } else if(GL_SUPPORT(NV_FENCE)) {
1410 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1411 checkGLcall("glGenFencesNV");
1413 LEAVE_GL();
1414 break;
1416 case WINED3DQUERYTYPE_VCACHE:
1417 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1418 case WINED3DQUERYTYPE_VERTEXSTATS:
1419 case WINED3DQUERYTYPE_TIMESTAMP:
1420 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1421 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1422 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1423 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1424 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1425 case WINED3DQUERYTYPE_PIXELTIMINGS:
1426 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1427 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1428 default:
1429 object->extendedData = 0;
1430 FIXME("(%p) Unhandled query type %d\n",This , Type);
1432 TRACE("(%p) : Created Query %p\n", This, object);
1433 return WINED3D_OK;
1436 /*****************************************************************************
1437 * IWineD3DDeviceImpl_SetupFullscreenWindow
1439 * Helper function that modifies a HWND's Style and ExStyle for proper
1440 * fullscreen use.
1442 * Params:
1443 * iface: Pointer to the IWineD3DDevice interface
1444 * window: Window to setup
1446 *****************************************************************************/
1447 static LONG fullscreen_style(LONG orig_style) {
1448 LONG style = orig_style;
1449 style &= ~WS_CAPTION;
1450 style &= ~WS_THICKFRAME;
1452 /* Make sure the window is managed, otherwise we won't get keyboard input */
1453 style |= WS_POPUP | WS_SYSMENU;
1455 return style;
1458 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1459 LONG exStyle = orig_exStyle;
1461 /* Filter out window decorations */
1462 exStyle &= ~WS_EX_WINDOWEDGE;
1463 exStyle &= ~WS_EX_CLIENTEDGE;
1465 return exStyle;
1468 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1471 LONG style, exStyle;
1472 /* Don't do anything if an original style is stored.
1473 * That shouldn't happen
1475 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1476 if (This->style || This->exStyle) {
1477 ERR("(%p): Want to change the window parameters of HWND %p, but "
1478 "another style is stored for restoration afterwards\n", This, window);
1481 /* Get the parameters and save them */
1482 style = GetWindowLongW(window, GWL_STYLE);
1483 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1484 This->style = style;
1485 This->exStyle = exStyle;
1487 style = fullscreen_style(style);
1488 exStyle = fullscreen_exStyle(exStyle);
1490 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1491 This->style, This->exStyle, style, exStyle);
1493 SetWindowLongW(window, GWL_STYLE, style);
1494 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1496 /* Inform the window about the update. */
1497 SetWindowPos(window, HWND_TOP, 0, 0,
1498 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1501 /*****************************************************************************
1502 * IWineD3DDeviceImpl_RestoreWindow
1504 * Helper function that restores a windows' properties when taking it out
1505 * of fullscreen mode
1507 * Params:
1508 * iface: Pointer to the IWineD3DDevice interface
1509 * window: Window to setup
1511 *****************************************************************************/
1512 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1514 LONG style, exStyle;
1516 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1517 * switch, do nothing
1519 if (!This->style && !This->exStyle) return;
1521 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1522 This, window, This->style, This->exStyle);
1524 style = GetWindowLongW(window, GWL_STYLE);
1525 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1527 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1528 * Some applications change it before calling Reset() when switching between windowed and
1529 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1531 if(style == fullscreen_style(This->style) &&
1532 exStyle == fullscreen_style(This->exStyle)) {
1533 SetWindowLongW(window, GWL_STYLE, This->style);
1534 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1537 /* Delete the old values */
1538 This->style = 0;
1539 This->exStyle = 0;
1541 /* Inform the window about the update */
1542 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1543 0, 0, 0, 0, /* Pos, Size, ignored */
1544 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1547 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1548 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1549 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1550 IUnknown *parent, WINED3DSURFTYPE surface_type)
1552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1554 HDC hDc;
1555 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1556 HRESULT hr;
1557 IUnknown *bufferParent;
1558 BOOL displaymode_set = FALSE;
1559 WINED3DDISPLAYMODE Mode;
1560 const StaticPixelFormatDesc *formatDesc;
1562 TRACE("(%p) : Created Additional Swap Chain\n", This);
1564 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1565 * does a device hold a reference to a swap chain giving them a lifetime of the device
1566 * or does the swap chain notify the device of its destruction.
1567 *******************************/
1569 /* Check the params */
1570 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1571 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1572 return WINED3DERR_INVALIDCALL;
1573 } else if (pPresentationParameters->BackBufferCount > 1) {
1574 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");
1577 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1578 if(!object)
1580 ERR("Out of memory\n");
1581 *ppSwapChain = NULL;
1582 return WINED3DERR_OUTOFVIDEOMEMORY;
1585 switch(surface_type) {
1586 case SURFACE_GDI:
1587 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1588 break;
1589 case SURFACE_OPENGL:
1590 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1591 break;
1592 case SURFACE_UNKNOWN:
1593 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1594 HeapFree(GetProcessHeap(), 0, object);
1595 return WINED3DERR_INVALIDCALL;
1597 object->wineD3DDevice = This;
1598 object->parent = parent;
1599 object->ref = 1;
1601 *ppSwapChain = (IWineD3DSwapChain *)object;
1603 /*********************
1604 * Lookup the window Handle and the relating X window handle
1605 ********************/
1607 /* Setup hwnd we are using, plus which display this equates to */
1608 object->win_handle = pPresentationParameters->hDeviceWindow;
1609 if (!object->win_handle) {
1610 object->win_handle = This->createParms.hFocusWindow;
1612 if(!pPresentationParameters->Windowed && object->win_handle) {
1613 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1614 pPresentationParameters->BackBufferWidth,
1615 pPresentationParameters->BackBufferHeight);
1618 hDc = GetDC(object->win_handle);
1619 TRACE("Using hDc %p\n", hDc);
1621 if (NULL == hDc) {
1622 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1623 return WINED3DERR_NOTAVAILABLE;
1626 /* Get info on the current display setup */
1627 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1628 object->orig_width = Mode.Width;
1629 object->orig_height = Mode.Height;
1630 object->orig_fmt = Mode.Format;
1631 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1633 if (pPresentationParameters->Windowed &&
1634 ((pPresentationParameters->BackBufferWidth == 0) ||
1635 (pPresentationParameters->BackBufferHeight == 0) ||
1636 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1638 RECT Rect;
1639 GetClientRect(object->win_handle, &Rect);
1641 if (pPresentationParameters->BackBufferWidth == 0) {
1642 pPresentationParameters->BackBufferWidth = Rect.right;
1643 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1645 if (pPresentationParameters->BackBufferHeight == 0) {
1646 pPresentationParameters->BackBufferHeight = Rect.bottom;
1647 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1649 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1650 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1651 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1655 /* Put the correct figures in the presentation parameters */
1656 TRACE("Copying across presentation parameters\n");
1657 object->presentParms = *pPresentationParameters;
1659 TRACE("calling rendertarget CB\n");
1660 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1661 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1662 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1663 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1664 if (SUCCEEDED(hr)) {
1665 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1666 if(surface_type == SURFACE_OPENGL) {
1667 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1669 } else {
1670 ERR("Failed to create the front buffer\n");
1671 goto error;
1674 /*********************
1675 * Windowed / Fullscreen
1676 *******************/
1679 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1680 * so we should really check to see if there is a fullscreen swapchain already
1681 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1682 **************************************/
1684 if (!pPresentationParameters->Windowed) {
1685 WINED3DDISPLAYMODE mode;
1688 /* Change the display settings */
1689 mode.Width = pPresentationParameters->BackBufferWidth;
1690 mode.Height = pPresentationParameters->BackBufferHeight;
1691 mode.Format = pPresentationParameters->BackBufferFormat;
1692 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1694 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1695 displaymode_set = TRUE;
1699 * Create an opengl context for the display visual
1700 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1701 * use different properties after that point in time. FIXME: How to handle when requested format
1702 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1703 * it chooses is identical to the one already being used!
1704 **********************************/
1705 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1707 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1708 if(!object->context) {
1709 ERR("Failed to create the context array\n");
1710 hr = E_OUTOFMEMORY;
1711 goto error;
1713 object->num_contexts = 1;
1715 if(surface_type == SURFACE_OPENGL) {
1716 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1717 if (!object->context[0]) {
1718 ERR("Failed to create a new context\n");
1719 hr = WINED3DERR_NOTAVAILABLE;
1720 goto error;
1721 } else {
1722 TRACE("Context created (HWND=%p, glContext=%p)\n",
1723 object->win_handle, object->context[0]->glCtx);
1727 /*********************
1728 * Create the back, front and stencil buffers
1729 *******************/
1730 if(object->presentParms.BackBufferCount > 0) {
1731 UINT i;
1733 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1734 if(!object->backBuffer) {
1735 ERR("Out of memory\n");
1736 hr = E_OUTOFMEMORY;
1737 goto error;
1740 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1741 TRACE("calling rendertarget CB\n");
1742 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1743 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1744 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1745 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1746 if(SUCCEEDED(hr)) {
1747 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1748 } else {
1749 ERR("Cannot create new back buffer\n");
1750 goto error;
1752 if(surface_type == SURFACE_OPENGL) {
1753 ENTER_GL();
1754 glDrawBuffer(GL_BACK);
1755 checkGLcall("glDrawBuffer(GL_BACK)");
1756 LEAVE_GL();
1759 } else {
1760 object->backBuffer = NULL;
1762 /* Single buffering - draw to front buffer */
1763 if(surface_type == SURFACE_OPENGL) {
1764 ENTER_GL();
1765 glDrawBuffer(GL_FRONT);
1766 checkGLcall("glDrawBuffer(GL_FRONT)");
1767 LEAVE_GL();
1771 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1772 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1773 TRACE("Creating depth stencil buffer\n");
1774 if (This->auto_depth_stencil_buffer == NULL ) {
1775 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1776 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1777 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1778 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1779 &This->auto_depth_stencil_buffer);
1780 if (SUCCEEDED(hr)) {
1781 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1782 } else {
1783 ERR("Failed to create the auto depth stencil\n");
1784 goto error;
1789 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1791 TRACE("Created swapchain %p\n", object);
1792 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1793 return WINED3D_OK;
1795 error:
1796 if (displaymode_set) {
1797 DEVMODEW devmode;
1798 RECT clip_rc;
1800 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1801 ClipCursor(NULL);
1803 /* Change the display settings */
1804 memset(&devmode, 0, sizeof(devmode));
1805 devmode.dmSize = sizeof(devmode);
1806 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1807 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1808 devmode.dmPelsWidth = object->orig_width;
1809 devmode.dmPelsHeight = object->orig_height;
1810 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1813 if (object->backBuffer) {
1814 UINT i;
1815 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1816 if(object->backBuffer[i]) {
1817 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1818 IUnknown_Release(bufferParent); /* once for the get parent */
1819 if (IUnknown_Release(bufferParent) > 0) {
1820 FIXME("(%p) Something's still holding the back buffer\n",This);
1824 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1825 object->backBuffer = NULL;
1827 if(object->context && object->context[0])
1828 DestroyContext(This, object->context[0]);
1829 if(object->frontBuffer) {
1830 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1831 IUnknown_Release(bufferParent); /* once for the get parent */
1832 if (IUnknown_Release(bufferParent) > 0) {
1833 FIXME("(%p) Something's still holding the front buffer\n",This);
1836 HeapFree(GetProcessHeap(), 0, object);
1837 return hr;
1840 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1841 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1843 TRACE("(%p)\n", This);
1845 return This->NumberOfSwapChains;
1848 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1850 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1852 if(iSwapChain < This->NumberOfSwapChains) {
1853 *pSwapChain = This->swapchains[iSwapChain];
1854 IWineD3DSwapChain_AddRef(*pSwapChain);
1855 TRACE("(%p) returning %p\n", This, *pSwapChain);
1856 return WINED3D_OK;
1857 } else {
1858 TRACE("Swapchain out of range\n");
1859 *pSwapChain = NULL;
1860 return WINED3DERR_INVALIDCALL;
1864 /*****
1865 * Vertex Declaration
1866 *****/
1867 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1868 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1870 IWineD3DVertexDeclarationImpl *object = NULL;
1871 HRESULT hr = WINED3D_OK;
1873 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1874 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1876 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1877 if(!object)
1879 ERR("Out of memory\n");
1880 *ppVertexDeclaration = NULL;
1881 return WINED3DERR_OUTOFVIDEOMEMORY;
1884 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
1885 object->wineD3DDevice = This;
1886 object->parent = parent;
1887 object->ref = 1;
1889 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1891 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1892 if(FAILED(hr)) {
1893 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1894 *ppVertexDeclaration = NULL;
1897 return hr;
1900 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1901 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1903 unsigned int idx, idx2;
1904 unsigned int offset;
1905 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1906 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1907 BOOL has_blend_idx = has_blend &&
1908 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1909 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1910 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1911 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1912 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1913 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1914 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1916 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1917 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1919 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1920 WINED3DVERTEXELEMENT *elements = NULL;
1922 unsigned int size;
1923 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1924 if (has_blend_idx) num_blends--;
1926 /* Compute declaration size */
1927 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1928 has_psize + has_diffuse + has_specular + num_textures + 1;
1930 /* convert the declaration */
1931 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1932 if (!elements)
1933 return 0;
1935 elements[size-1] = end_element;
1936 idx = 0;
1937 if (has_pos) {
1938 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1939 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1940 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1942 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1943 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1944 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1946 else {
1947 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1948 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1950 elements[idx].UsageIndex = 0;
1951 idx++;
1953 if (has_blend && (num_blends > 0)) {
1954 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1955 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1956 else {
1957 switch(num_blends) {
1958 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
1959 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
1960 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
1961 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
1962 default:
1963 ERR("Unexpected amount of blend values: %u\n", num_blends);
1966 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1967 elements[idx].UsageIndex = 0;
1968 idx++;
1970 if (has_blend_idx) {
1971 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1972 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1973 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1974 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1975 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1976 else
1977 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1978 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1979 elements[idx].UsageIndex = 0;
1980 idx++;
1982 if (has_normal) {
1983 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1984 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1985 elements[idx].UsageIndex = 0;
1986 idx++;
1988 if (has_psize) {
1989 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1990 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1991 elements[idx].UsageIndex = 0;
1992 idx++;
1994 if (has_diffuse) {
1995 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1996 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1997 elements[idx].UsageIndex = 0;
1998 idx++;
2000 if (has_specular) {
2001 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2002 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
2003 elements[idx].UsageIndex = 1;
2004 idx++;
2006 for (idx2 = 0; idx2 < num_textures; idx2++) {
2007 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
2008 switch (numcoords) {
2009 case WINED3DFVF_TEXTUREFORMAT1:
2010 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2011 break;
2012 case WINED3DFVF_TEXTUREFORMAT2:
2013 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
2014 break;
2015 case WINED3DFVF_TEXTUREFORMAT3:
2016 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2017 break;
2018 case WINED3DFVF_TEXTUREFORMAT4:
2019 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2020 break;
2022 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
2023 elements[idx].UsageIndex = idx2;
2024 idx++;
2027 /* Now compute offsets, and initialize the rest of the fields */
2028 for (idx = 0, offset = 0; idx < size-1; idx++) {
2029 elements[idx].Stream = 0;
2030 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
2031 elements[idx].Offset = offset;
2032 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
2035 *ppVertexElements = elements;
2036 return size;
2039 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
2040 WINED3DVERTEXELEMENT* elements = NULL;
2041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2042 unsigned int size;
2043 DWORD hr;
2045 size = ConvertFvfToDeclaration(This, Fvf, &elements);
2046 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
2048 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
2049 HeapFree(GetProcessHeap(), 0, elements);
2050 if (hr != S_OK) return hr;
2052 return WINED3D_OK;
2055 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
2056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2057 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
2058 HRESULT hr = WINED3D_OK;
2060 if (!pFunction) return WINED3DERR_INVALIDCALL;
2062 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2063 if (!object)
2065 ERR("Out of memory\n");
2066 *ppVertexShader = NULL;
2067 return WINED3DERR_OUTOFVIDEOMEMORY;
2070 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
2071 object->parent = parent;
2072 shader_init(&object->baseShader, iface, IWineD3DVertexShaderImpl_shader_ins);
2073 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2074 *ppVertexShader = (IWineD3DVertexShader *)object;
2076 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
2078 if (vertex_declaration) {
2079 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
2082 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
2083 if (FAILED(hr))
2085 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2086 IWineD3DVertexShader_Release(*ppVertexShader);
2087 *ppVertexShader = NULL;
2088 return hr;
2091 return hr;
2094 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
2095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2096 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2097 HRESULT hr = WINED3D_OK;
2099 if (!pFunction) return WINED3DERR_INVALIDCALL;
2101 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2102 if (!object)
2104 ERR("Out of memory\n");
2105 *ppPixelShader = NULL;
2106 return WINED3DERR_OUTOFVIDEOMEMORY;
2109 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2110 object->parent = parent;
2111 shader_init(&object->baseShader, iface, IWineD3DPixelShaderImpl_shader_ins);
2112 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2113 *ppPixelShader = (IWineD3DPixelShader *)object;
2115 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2117 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
2118 if (FAILED(hr))
2120 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2121 IWineD3DPixelShader_Release(*ppPixelShader);
2122 *ppPixelShader = NULL;
2123 return hr;
2126 return hr;
2129 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2130 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2133 IWineD3DPaletteImpl *object;
2134 HRESULT hr;
2135 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2137 /* Create the new object */
2138 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2139 if(!object) {
2140 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2141 return E_OUTOFMEMORY;
2144 object->lpVtbl = &IWineD3DPalette_Vtbl;
2145 object->ref = 1;
2146 object->Flags = Flags;
2147 object->parent = Parent;
2148 object->wineD3DDevice = This;
2149 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2150 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2152 if(!object->hpal) {
2153 HeapFree( GetProcessHeap(), 0, object);
2154 return E_OUTOFMEMORY;
2157 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2158 if(FAILED(hr)) {
2159 IWineD3DPalette_Release((IWineD3DPalette *) object);
2160 return hr;
2163 *Palette = (IWineD3DPalette *) object;
2165 return WINED3D_OK;
2168 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2169 HBITMAP hbm;
2170 BITMAP bm;
2171 HRESULT hr;
2172 HDC dcb = NULL, dcs = NULL;
2173 WINEDDCOLORKEY colorkey;
2175 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2176 if(hbm)
2178 GetObjectA(hbm, sizeof(BITMAP), &bm);
2179 dcb = CreateCompatibleDC(NULL);
2180 if(!dcb) goto out;
2181 SelectObject(dcb, hbm);
2183 else
2185 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2186 * couldn't be loaded
2188 memset(&bm, 0, sizeof(bm));
2189 bm.bmWidth = 32;
2190 bm.bmHeight = 32;
2193 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2194 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2195 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
2196 if(FAILED(hr)) {
2197 ERR("Wine logo requested, but failed to create surface\n");
2198 goto out;
2201 if(dcb) {
2202 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2203 if(FAILED(hr)) goto out;
2204 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2205 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2207 colorkey.dwColorSpaceLowValue = 0;
2208 colorkey.dwColorSpaceHighValue = 0;
2209 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2210 } else {
2211 /* Fill the surface with a white color to show that wined3d is there */
2212 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2215 out:
2216 if(dcb) {
2217 DeleteDC(dcb);
2219 if(hbm) {
2220 DeleteObject(hbm);
2222 return;
2225 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2226 unsigned int i;
2227 /* Under DirectX you can have texture stage operations even if no texture is
2228 bound, whereas opengl will only do texture operations when a valid texture is
2229 bound. We emulate this by creating dummy textures and binding them to each
2230 texture stage, but disable all stages by default. Hence if a stage is enabled
2231 then the default texture will kick in until replaced by a SetTexture call */
2232 ENTER_GL();
2234 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2235 /* The dummy texture does not have client storage backing */
2236 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2237 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2239 for (i = 0; i < GL_LIMITS(textures); i++) {
2240 GLubyte white = 255;
2242 /* Make appropriate texture active */
2243 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2244 checkGLcall("glActiveTextureARB");
2246 /* Generate an opengl texture name */
2247 glGenTextures(1, &This->dummyTextureName[i]);
2248 checkGLcall("glGenTextures");
2249 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2251 /* Generate a dummy 2d texture (not using 1d because they cause many
2252 * DRI drivers fall back to sw) */
2253 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2254 checkGLcall("glBindTexture");
2256 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2257 checkGLcall("glTexImage2D");
2259 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2260 /* Reenable because if supported it is enabled by default */
2261 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2262 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2265 LEAVE_GL();
2268 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2269 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2272 IWineD3DSwapChainImpl *swapchain = NULL;
2273 HRESULT hr;
2274 DWORD state;
2275 unsigned int i;
2277 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2279 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2280 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2282 /* TODO: Test if OpenGL is compiled in and loaded */
2284 TRACE("(%p) : Creating stateblock\n", This);
2285 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2286 hr = IWineD3DDevice_CreateStateBlock(iface,
2287 WINED3DSBT_INIT,
2288 (IWineD3DStateBlock **)&This->stateBlock,
2289 NULL);
2290 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2291 WARN("Failed to create stateblock\n");
2292 goto err_out;
2294 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2295 This->updateStateBlock = This->stateBlock;
2296 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2298 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2299 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2301 This->NumberOfPalettes = 1;
2302 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2303 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2304 ERR("Out of memory!\n");
2305 goto err_out;
2307 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2308 if(!This->palettes[0]) {
2309 ERR("Out of memory!\n");
2310 goto err_out;
2312 for (i = 0; i < 256; ++i) {
2313 This->palettes[0][i].peRed = 0xFF;
2314 This->palettes[0][i].peGreen = 0xFF;
2315 This->palettes[0][i].peBlue = 0xFF;
2316 This->palettes[0][i].peFlags = 0xFF;
2318 This->currentPalette = 0;
2320 /* Initialize the texture unit mapping to a 1:1 mapping */
2321 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2322 if (state < GL_LIMITS(fragment_samplers)) {
2323 This->texUnitMap[state] = state;
2324 This->rev_tex_unit_map[state] = state;
2325 } else {
2326 This->texUnitMap[state] = -1;
2327 This->rev_tex_unit_map[state] = -1;
2331 /* Setup the implicit swapchain */
2332 TRACE("Creating implicit swapchain\n");
2333 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2334 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2335 if (FAILED(hr))
2337 WARN("Failed to create implicit swapchain\n");
2338 goto err_out;
2341 This->NumberOfSwapChains = 1;
2342 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2343 if(!This->swapchains) {
2344 ERR("Out of memory!\n");
2345 goto err_out;
2347 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2349 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2350 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2351 This->render_targets[0] = swapchain->backBuffer[0];
2352 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2354 else {
2355 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2356 This->render_targets[0] = swapchain->frontBuffer;
2357 This->lastActiveRenderTarget = swapchain->frontBuffer;
2359 IWineD3DSurface_AddRef(This->render_targets[0]);
2360 This->activeContext = swapchain->context[0];
2361 This->lastThread = GetCurrentThreadId();
2363 /* Depth Stencil support */
2364 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2365 if (NULL != This->stencilBufferTarget) {
2366 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2369 hr = This->shader_backend->shader_alloc_private(iface);
2370 if(FAILED(hr)) {
2371 TRACE("Shader private data couldn't be allocated\n");
2372 goto err_out;
2374 hr = This->frag_pipe->alloc_private(iface);
2375 if(FAILED(hr)) {
2376 TRACE("Fragment pipeline private data couldn't be allocated\n");
2377 goto err_out;
2379 hr = This->blitter->alloc_private(iface);
2380 if(FAILED(hr)) {
2381 TRACE("Blitter private data couldn't be allocated\n");
2382 goto err_out;
2385 /* Set up some starting GL setup */
2387 /* Setup all the devices defaults */
2388 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2389 create_dummy_textures(This);
2391 ENTER_GL();
2393 /* Initialize the current view state */
2394 This->view_ident = 1;
2395 This->contexts[0]->last_was_rhw = 0;
2396 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2397 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2399 switch(wined3d_settings.offscreen_rendering_mode) {
2400 case ORM_FBO:
2401 case ORM_PBUFFER:
2402 This->offscreenBuffer = GL_BACK;
2403 break;
2405 case ORM_BACKBUFFER:
2407 if(This->activeContext->aux_buffers > 0) {
2408 TRACE("Using auxilliary buffer for offscreen rendering\n");
2409 This->offscreenBuffer = GL_AUX0;
2410 } else {
2411 TRACE("Using back buffer for offscreen rendering\n");
2412 This->offscreenBuffer = GL_BACK;
2417 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2418 LEAVE_GL();
2420 /* Clear the screen */
2421 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2422 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2423 0x00, 1.0, 0);
2425 This->d3d_initialized = TRUE;
2427 if(wined3d_settings.logo) {
2428 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2430 This->highest_dirty_ps_const = 0;
2431 This->highest_dirty_vs_const = 0;
2432 return WINED3D_OK;
2434 err_out:
2435 HeapFree(GetProcessHeap(), 0, This->render_targets);
2436 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2437 HeapFree(GetProcessHeap(), 0, This->swapchains);
2438 This->NumberOfSwapChains = 0;
2439 if(This->palettes) {
2440 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2441 HeapFree(GetProcessHeap(), 0, This->palettes);
2443 This->NumberOfPalettes = 0;
2444 if(swapchain) {
2445 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2447 if(This->stateBlock) {
2448 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2449 This->stateBlock = NULL;
2451 if (This->blit_priv) {
2452 This->blitter->free_private(iface);
2454 if (This->fragment_priv) {
2455 This->frag_pipe->free_private(iface);
2457 if (This->shader_priv) {
2458 This->shader_backend->shader_free_private(iface);
2460 return hr;
2463 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2464 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2467 IWineD3DSwapChainImpl *swapchain = NULL;
2468 HRESULT hr;
2470 /* Setup the implicit swapchain */
2471 TRACE("Creating implicit swapchain\n");
2472 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2473 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2474 if (FAILED(hr))
2476 WARN("Failed to create implicit swapchain\n");
2477 goto err_out;
2480 This->NumberOfSwapChains = 1;
2481 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2482 if(!This->swapchains) {
2483 ERR("Out of memory!\n");
2484 goto err_out;
2486 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2487 return WINED3D_OK;
2489 err_out:
2490 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2491 return hr;
2494 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2496 int sampler;
2497 UINT i;
2498 TRACE("(%p)\n", This);
2500 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2502 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2503 * it was created. Thus make sure a context is active for the glDelete* calls
2505 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2507 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2509 TRACE("Deleting high order patches\n");
2510 for(i = 0; i < PATCHMAP_SIZE; i++) {
2511 struct list *e1, *e2;
2512 struct WineD3DRectPatch *patch;
2513 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2514 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2515 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2519 /* Delete the palette conversion shader if it is around */
2520 if(This->paletteConversionShader) {
2521 ENTER_GL();
2522 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2523 LEAVE_GL();
2524 This->paletteConversionShader = 0;
2527 /* Delete the pbuffer context if there is any */
2528 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2530 /* Delete the mouse cursor texture */
2531 if(This->cursorTexture) {
2532 ENTER_GL();
2533 glDeleteTextures(1, &This->cursorTexture);
2534 LEAVE_GL();
2535 This->cursorTexture = 0;
2538 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2539 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2541 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2542 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2545 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2546 * private data, it might contain opengl pointers
2548 if(This->depth_blt_texture) {
2549 glDeleteTextures(1, &This->depth_blt_texture);
2550 This->depth_blt_texture = 0;
2552 if (This->depth_blt_rb) {
2553 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2554 This->depth_blt_rb = 0;
2555 This->depth_blt_rb_w = 0;
2556 This->depth_blt_rb_h = 0;
2559 /* Release the update stateblock */
2560 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2561 if(This->updateStateBlock != This->stateBlock)
2562 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2564 This->updateStateBlock = NULL;
2566 { /* because were not doing proper internal refcounts releasing the primary state block
2567 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2568 to set this->stateBlock = NULL; first */
2569 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2570 This->stateBlock = NULL;
2572 /* Release the stateblock */
2573 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2574 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2578 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2579 This->blitter->free_private(iface);
2580 This->frag_pipe->free_private(iface);
2581 This->shader_backend->shader_free_private(iface);
2583 /* Release the buffers (with sanity checks)*/
2584 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2585 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2586 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2587 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2589 This->stencilBufferTarget = NULL;
2591 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2592 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2593 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2595 TRACE("Setting rendertarget to NULL\n");
2596 This->render_targets[0] = NULL;
2598 if (This->auto_depth_stencil_buffer) {
2599 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2600 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2602 This->auto_depth_stencil_buffer = NULL;
2605 for(i=0; i < This->NumberOfSwapChains; i++) {
2606 TRACE("Releasing the implicit swapchain %d\n", i);
2607 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2608 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2612 HeapFree(GetProcessHeap(), 0, This->swapchains);
2613 This->swapchains = NULL;
2614 This->NumberOfSwapChains = 0;
2616 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2617 HeapFree(GetProcessHeap(), 0, This->palettes);
2618 This->palettes = NULL;
2619 This->NumberOfPalettes = 0;
2621 HeapFree(GetProcessHeap(), 0, This->render_targets);
2622 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2623 This->render_targets = NULL;
2624 This->draw_buffers = NULL;
2626 This->d3d_initialized = FALSE;
2627 return WINED3D_OK;
2630 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2632 unsigned int i;
2634 for(i=0; i < This->NumberOfSwapChains; i++) {
2635 TRACE("Releasing the implicit swapchain %d\n", i);
2636 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2637 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2641 HeapFree(GetProcessHeap(), 0, This->swapchains);
2642 This->swapchains = NULL;
2643 This->NumberOfSwapChains = 0;
2644 return WINED3D_OK;
2647 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2648 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2649 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2651 * There is no way to deactivate thread safety once it is enabled.
2653 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2656 /*For now just store the flag(needed in case of ddraw) */
2657 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2659 return;
2662 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2663 const WINED3DDISPLAYMODE* pMode) {
2664 DEVMODEW devmode;
2665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2666 LONG ret;
2667 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2668 RECT clip_rc;
2670 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2672 /* Resize the screen even without a window:
2673 * The app could have unset it with SetCooperativeLevel, but not called
2674 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2675 * but we don't have any hwnd
2678 memset(&devmode, 0, sizeof(devmode));
2679 devmode.dmSize = sizeof(devmode);
2680 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2681 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2682 devmode.dmPelsWidth = pMode->Width;
2683 devmode.dmPelsHeight = pMode->Height;
2685 devmode.dmDisplayFrequency = pMode->RefreshRate;
2686 if (pMode->RefreshRate != 0) {
2687 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2690 /* Only change the mode if necessary */
2691 if( (This->ddraw_width == pMode->Width) &&
2692 (This->ddraw_height == pMode->Height) &&
2693 (This->ddraw_format == pMode->Format) &&
2694 (pMode->RefreshRate == 0) ) {
2695 return WINED3D_OK;
2698 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2699 if (ret != DISP_CHANGE_SUCCESSFUL) {
2700 if(devmode.dmDisplayFrequency != 0) {
2701 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2702 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2703 devmode.dmDisplayFrequency = 0;
2704 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2706 if(ret != DISP_CHANGE_SUCCESSFUL) {
2707 return WINED3DERR_NOTAVAILABLE;
2711 /* Store the new values */
2712 This->ddraw_width = pMode->Width;
2713 This->ddraw_height = pMode->Height;
2714 This->ddraw_format = pMode->Format;
2716 /* And finally clip mouse to our screen */
2717 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2718 ClipCursor(&clip_rc);
2720 return WINED3D_OK;
2723 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2725 *ppD3D= This->wineD3D;
2726 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2727 IWineD3D_AddRef(*ppD3D);
2728 return WINED3D_OK;
2731 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2734 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2735 (This->adapter->TextureRam/(1024*1024)),
2736 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2737 /* return simulated texture memory left */
2738 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2741 /*****
2742 * Get / Set Stream Source
2743 *****/
2744 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2746 IWineD3DVertexBuffer *oldSrc;
2748 if (StreamNumber >= MAX_STREAMS) {
2749 WARN("Stream out of range %d\n", StreamNumber);
2750 return WINED3DERR_INVALIDCALL;
2751 } else if(OffsetInBytes & 0x3) {
2752 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2753 return WINED3DERR_INVALIDCALL;
2756 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2757 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2759 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2761 if(oldSrc == pStreamData &&
2762 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2763 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2764 TRACE("Application is setting the old values over, nothing to do\n");
2765 return WINED3D_OK;
2768 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2769 if (pStreamData) {
2770 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2771 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2774 /* Handle recording of state blocks */
2775 if (This->isRecordingState) {
2776 TRACE("Recording... not performing anything\n");
2777 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2778 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2779 return WINED3D_OK;
2782 if (pStreamData != NULL) {
2783 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2784 InterlockedIncrement(&vbImpl->bindCount);
2785 IWineD3DVertexBuffer_AddRef(pStreamData);
2787 if (oldSrc != NULL) {
2788 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2789 IWineD3DVertexBuffer_Release(oldSrc);
2792 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2794 return WINED3D_OK;
2797 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2800 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2801 This->stateBlock->streamSource[StreamNumber],
2802 This->stateBlock->streamOffset[StreamNumber],
2803 This->stateBlock->streamStride[StreamNumber]);
2805 if (StreamNumber >= MAX_STREAMS) {
2806 WARN("Stream out of range %d\n", StreamNumber);
2807 return WINED3DERR_INVALIDCALL;
2809 *pStream = This->stateBlock->streamSource[StreamNumber];
2810 *pStride = This->stateBlock->streamStride[StreamNumber];
2811 if (pOffset) {
2812 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2815 if (*pStream != NULL) {
2816 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2818 return WINED3D_OK;
2821 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2823 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2824 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2826 /* Verify input at least in d3d9 this is invalid*/
2827 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2828 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2829 return WINED3DERR_INVALIDCALL;
2831 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2832 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2833 return WINED3DERR_INVALIDCALL;
2835 if( Divider == 0 ){
2836 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2837 return WINED3DERR_INVALIDCALL;
2840 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2841 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2843 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2844 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2846 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2847 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2848 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2851 return WINED3D_OK;
2854 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2857 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2858 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2860 TRACE("(%p) : returning %d\n", This, *Divider);
2862 return WINED3D_OK;
2865 /*****
2866 * Get / Set & Multiply Transform
2867 *****/
2868 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2871 /* Most of this routine, comments included copied from ddraw tree initially: */
2872 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2874 /* Handle recording of state blocks */
2875 if (This->isRecordingState) {
2876 TRACE("Recording... not performing anything\n");
2877 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2878 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2879 return WINED3D_OK;
2883 * If the new matrix is the same as the current one,
2884 * we cut off any further processing. this seems to be a reasonable
2885 * optimization because as was noticed, some apps (warcraft3 for example)
2886 * tend towards setting the same matrix repeatedly for some reason.
2888 * From here on we assume that the new matrix is different, wherever it matters.
2890 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2891 TRACE("The app is setting the same matrix over again\n");
2892 return WINED3D_OK;
2893 } else {
2894 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2898 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2899 where ViewMat = Camera space, WorldMat = world space.
2901 In OpenGL, camera and world space is combined into GL_MODELVIEW
2902 matrix. The Projection matrix stay projection matrix.
2905 /* Capture the times we can just ignore the change for now */
2906 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2907 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2908 /* Handled by the state manager */
2911 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2912 return WINED3D_OK;
2915 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2917 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2918 *pMatrix = This->stateBlock->transforms[State];
2919 return WINED3D_OK;
2922 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2923 const WINED3DMATRIX *mat = NULL;
2924 WINED3DMATRIX temp;
2926 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2927 * below means it will be recorded in a state block change, but it
2928 * works regardless where it is recorded.
2929 * If this is found to be wrong, change to StateBlock.
2931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2932 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2934 if (State <= HIGHEST_TRANSFORMSTATE)
2936 mat = &This->updateStateBlock->transforms[State];
2937 } else {
2938 FIXME("Unhandled transform state!!\n");
2941 multiply_matrix(&temp, mat, pMatrix);
2943 /* Apply change via set transform - will reapply to eg. lights this way */
2944 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2947 /*****
2948 * Get / Set Light
2949 *****/
2950 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2951 you can reference any indexes you want as long as that number max are enabled at any
2952 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2953 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2954 but when recording, just build a chain pretty much of commands to be replayed. */
2956 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2957 float rho;
2958 PLIGHTINFOEL *object = NULL;
2959 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2960 struct list *e;
2962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2963 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2965 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2966 * the gl driver.
2968 if(!pLight) {
2969 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2970 return WINED3DERR_INVALIDCALL;
2973 switch(pLight->Type) {
2974 case WINED3DLIGHT_POINT:
2975 case WINED3DLIGHT_SPOT:
2976 case WINED3DLIGHT_PARALLELPOINT:
2977 case WINED3DLIGHT_GLSPOT:
2978 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2979 * most wanted
2981 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2982 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2983 return WINED3DERR_INVALIDCALL;
2985 break;
2987 case WINED3DLIGHT_DIRECTIONAL:
2988 /* Ignores attenuation */
2989 break;
2991 default:
2992 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2993 return WINED3DERR_INVALIDCALL;
2996 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2997 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2998 if(object->OriginalIndex == Index) break;
2999 object = NULL;
3002 if(!object) {
3003 TRACE("Adding new light\n");
3004 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
3005 if(!object) {
3006 ERR("Out of memory error when allocating a light\n");
3007 return E_OUTOFMEMORY;
3009 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
3010 object->glIndex = -1;
3011 object->OriginalIndex = Index;
3012 object->changed = TRUE;
3015 /* Initialize the object */
3016 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,
3017 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
3018 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
3019 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
3020 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
3021 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
3022 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
3024 /* Save away the information */
3025 object->OriginalParms = *pLight;
3027 switch (pLight->Type) {
3028 case WINED3DLIGHT_POINT:
3029 /* Position */
3030 object->lightPosn[0] = pLight->Position.x;
3031 object->lightPosn[1] = pLight->Position.y;
3032 object->lightPosn[2] = pLight->Position.z;
3033 object->lightPosn[3] = 1.0f;
3034 object->cutoff = 180.0f;
3035 /* FIXME: Range */
3036 break;
3038 case WINED3DLIGHT_DIRECTIONAL:
3039 /* Direction */
3040 object->lightPosn[0] = -pLight->Direction.x;
3041 object->lightPosn[1] = -pLight->Direction.y;
3042 object->lightPosn[2] = -pLight->Direction.z;
3043 object->lightPosn[3] = 0.0;
3044 object->exponent = 0.0f;
3045 object->cutoff = 180.0f;
3046 break;
3048 case WINED3DLIGHT_SPOT:
3049 /* Position */
3050 object->lightPosn[0] = pLight->Position.x;
3051 object->lightPosn[1] = pLight->Position.y;
3052 object->lightPosn[2] = pLight->Position.z;
3053 object->lightPosn[3] = 1.0;
3055 /* Direction */
3056 object->lightDirn[0] = pLight->Direction.x;
3057 object->lightDirn[1] = pLight->Direction.y;
3058 object->lightDirn[2] = pLight->Direction.z;
3059 object->lightDirn[3] = 1.0;
3062 * opengl-ish and d3d-ish spot lights use too different models for the
3063 * light "intensity" as a function of the angle towards the main light direction,
3064 * so we only can approximate very roughly.
3065 * however spot lights are rather rarely used in games (if ever used at all).
3066 * furthermore if still used, probably nobody pays attention to such details.
3068 if (pLight->Falloff == 0) {
3069 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3070 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3071 * will always be 1.0 for both of them, and we don't have to care for the
3072 * rest of the rather complex calculation
3074 object->exponent = 0;
3075 } else {
3076 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3077 if (rho < 0.0001) rho = 0.0001f;
3078 object->exponent = -0.3/log(cos(rho/2));
3080 if (object->exponent > 128.0) {
3081 object->exponent = 128.0;
3083 object->cutoff = pLight->Phi*90/M_PI;
3085 /* FIXME: Range */
3086 break;
3088 default:
3089 FIXME("Unrecognized light type %d\n", pLight->Type);
3092 /* Update the live definitions if the light is currently assigned a glIndex */
3093 if (object->glIndex != -1 && !This->isRecordingState) {
3094 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3096 return WINED3D_OK;
3099 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3100 PLIGHTINFOEL *lightInfo = NULL;
3101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3102 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3103 struct list *e;
3104 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3106 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3107 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3108 if(lightInfo->OriginalIndex == Index) break;
3109 lightInfo = NULL;
3112 if (lightInfo == NULL) {
3113 TRACE("Light information requested but light not defined\n");
3114 return WINED3DERR_INVALIDCALL;
3117 *pLight = lightInfo->OriginalParms;
3118 return WINED3D_OK;
3121 /*****
3122 * Get / Set Light Enable
3123 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3124 *****/
3125 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3126 PLIGHTINFOEL *lightInfo = NULL;
3127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3128 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3129 struct list *e;
3130 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3132 /* Tests show true = 128...not clear why */
3133 Enable = Enable? 128: 0;
3135 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3136 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3137 if(lightInfo->OriginalIndex == Index) break;
3138 lightInfo = NULL;
3140 TRACE("Found light: %p\n", lightInfo);
3142 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3143 if (lightInfo == NULL) {
3145 TRACE("Light enabled requested but light not defined, so defining one!\n");
3146 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3148 /* Search for it again! Should be fairly quick as near head of list */
3149 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3150 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3151 if(lightInfo->OriginalIndex == Index) break;
3152 lightInfo = NULL;
3154 if (lightInfo == NULL) {
3155 FIXME("Adding default lights has failed dismally\n");
3156 return WINED3DERR_INVALIDCALL;
3160 lightInfo->enabledChanged = TRUE;
3161 if(!Enable) {
3162 if(lightInfo->glIndex != -1) {
3163 if(!This->isRecordingState) {
3164 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3167 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3168 lightInfo->glIndex = -1;
3169 } else {
3170 TRACE("Light already disabled, nothing to do\n");
3172 lightInfo->enabled = FALSE;
3173 } else {
3174 lightInfo->enabled = TRUE;
3175 if (lightInfo->glIndex != -1) {
3176 /* nop */
3177 TRACE("Nothing to do as light was enabled\n");
3178 } else {
3179 int i;
3180 /* Find a free gl light */
3181 for(i = 0; i < This->maxConcurrentLights; i++) {
3182 if(This->updateStateBlock->activeLights[i] == NULL) {
3183 This->updateStateBlock->activeLights[i] = lightInfo;
3184 lightInfo->glIndex = i;
3185 break;
3188 if(lightInfo->glIndex == -1) {
3189 /* Our tests show that Windows returns D3D_OK in this situation, even with
3190 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3191 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3192 * as well for those lights.
3194 * TODO: Test how this affects rendering
3196 WARN("Too many concurrently active lights\n");
3197 return WINED3D_OK;
3200 /* i == lightInfo->glIndex */
3201 if(!This->isRecordingState) {
3202 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3207 return WINED3D_OK;
3210 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3212 PLIGHTINFOEL *lightInfo = NULL;
3213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3214 struct list *e;
3215 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3216 TRACE("(%p) : for idx(%d)\n", This, Index);
3218 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3219 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3220 if(lightInfo->OriginalIndex == Index) break;
3221 lightInfo = NULL;
3224 if (lightInfo == NULL) {
3225 TRACE("Light enabled state requested but light not defined\n");
3226 return WINED3DERR_INVALIDCALL;
3228 /* true is 128 according to SetLightEnable */
3229 *pEnable = lightInfo->enabled ? 128 : 0;
3230 return WINED3D_OK;
3233 /*****
3234 * Get / Set Clip Planes
3235 *****/
3236 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3238 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3240 /* Validate Index */
3241 if (Index >= GL_LIMITS(clipplanes)) {
3242 TRACE("Application has requested clipplane this device doesn't support\n");
3243 return WINED3DERR_INVALIDCALL;
3246 This->updateStateBlock->changed.clipplane |= 1 << Index;
3248 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3249 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3250 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3251 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3252 TRACE("Application is setting old values over, nothing to do\n");
3253 return WINED3D_OK;
3256 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3257 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3258 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3259 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3261 /* Handle recording of state blocks */
3262 if (This->isRecordingState) {
3263 TRACE("Recording... not performing anything\n");
3264 return WINED3D_OK;
3267 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3269 return WINED3D_OK;
3272 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3274 TRACE("(%p) : for idx %d\n", This, Index);
3276 /* Validate Index */
3277 if (Index >= GL_LIMITS(clipplanes)) {
3278 TRACE("Application has requested clipplane this device doesn't support\n");
3279 return WINED3DERR_INVALIDCALL;
3282 pPlane[0] = This->stateBlock->clipplane[Index][0];
3283 pPlane[1] = This->stateBlock->clipplane[Index][1];
3284 pPlane[2] = This->stateBlock->clipplane[Index][2];
3285 pPlane[3] = This->stateBlock->clipplane[Index][3];
3286 return WINED3D_OK;
3289 /*****
3290 * Get / Set Clip Plane Status
3291 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3292 *****/
3293 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3295 FIXME("(%p) : stub\n", This);
3296 if (NULL == pClipStatus) {
3297 return WINED3DERR_INVALIDCALL;
3299 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3300 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3301 return WINED3D_OK;
3304 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3306 FIXME("(%p) : stub\n", This);
3307 if (NULL == pClipStatus) {
3308 return WINED3DERR_INVALIDCALL;
3310 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3311 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3312 return WINED3D_OK;
3315 /*****
3316 * Get / Set Material
3317 *****/
3318 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3321 This->updateStateBlock->changed.material = TRUE;
3322 This->updateStateBlock->material = *pMaterial;
3324 /* Handle recording of state blocks */
3325 if (This->isRecordingState) {
3326 TRACE("Recording... not performing anything\n");
3327 return WINED3D_OK;
3330 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3331 return WINED3D_OK;
3334 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3336 *pMaterial = This->updateStateBlock->material;
3337 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3338 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3339 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3340 pMaterial->Ambient.b, pMaterial->Ambient.a);
3341 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3342 pMaterial->Specular.b, pMaterial->Specular.a);
3343 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3344 pMaterial->Emissive.b, pMaterial->Emissive.a);
3345 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3347 return WINED3D_OK;
3350 /*****
3351 * Get / Set Indices
3352 *****/
3353 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3355 IWineD3DIndexBuffer *oldIdxs;
3357 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3358 oldIdxs = This->updateStateBlock->pIndexData;
3360 This->updateStateBlock->changed.indices = TRUE;
3361 This->updateStateBlock->pIndexData = pIndexData;
3363 /* Handle recording of state blocks */
3364 if (This->isRecordingState) {
3365 TRACE("Recording... not performing anything\n");
3366 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3367 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3368 return WINED3D_OK;
3371 if(oldIdxs != pIndexData) {
3372 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3373 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3374 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3376 return WINED3D_OK;
3379 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3382 *ppIndexData = This->stateBlock->pIndexData;
3384 /* up ref count on ppindexdata */
3385 if (*ppIndexData) {
3386 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3387 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3388 }else{
3389 TRACE("(%p) No index data set\n", This);
3391 TRACE("Returning %p\n", *ppIndexData);
3393 return WINED3D_OK;
3396 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3397 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3399 TRACE("(%p)->(%d)\n", This, BaseIndex);
3401 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3402 TRACE("Application is setting the old value over, nothing to do\n");
3403 return WINED3D_OK;
3406 This->updateStateBlock->baseVertexIndex = BaseIndex;
3408 if (This->isRecordingState) {
3409 TRACE("Recording... not performing anything\n");
3410 return WINED3D_OK;
3412 /* The base vertex index affects the stream sources */
3413 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3414 return WINED3D_OK;
3417 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3419 TRACE("(%p) : base_index %p\n", This, base_index);
3421 *base_index = This->stateBlock->baseVertexIndex;
3423 TRACE("Returning %u\n", *base_index);
3425 return WINED3D_OK;
3428 /*****
3429 * Get / Set Viewports
3430 *****/
3431 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3434 TRACE("(%p)\n", This);
3435 This->updateStateBlock->changed.viewport = TRUE;
3436 This->updateStateBlock->viewport = *pViewport;
3438 /* Handle recording of state blocks */
3439 if (This->isRecordingState) {
3440 TRACE("Recording... not performing anything\n");
3441 return WINED3D_OK;
3444 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3445 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3447 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3448 return WINED3D_OK;
3452 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3454 TRACE("(%p)\n", This);
3455 *pViewport = This->stateBlock->viewport;
3456 return WINED3D_OK;
3459 /*****
3460 * Get / Set Render States
3461 * TODO: Verify against dx9 definitions
3462 *****/
3463 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3465 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3466 DWORD oldValue = This->stateBlock->renderState[State];
3468 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3470 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3471 This->updateStateBlock->renderState[State] = Value;
3473 /* Handle recording of state blocks */
3474 if (This->isRecordingState) {
3475 TRACE("Recording... not performing anything\n");
3476 return WINED3D_OK;
3479 /* Compared here and not before the assignment to allow proper stateblock recording */
3480 if(Value == oldValue) {
3481 TRACE("Application is setting the old value over, nothing to do\n");
3482 } else {
3483 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3486 return WINED3D_OK;
3489 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3490 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3491 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3492 *pValue = This->stateBlock->renderState[State];
3493 return WINED3D_OK;
3496 /*****
3497 * Get / Set Sampler States
3498 * TODO: Verify against dx9 definitions
3499 *****/
3501 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3503 DWORD oldValue;
3505 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3506 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3508 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3509 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3512 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3513 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3514 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3517 * SetSampler is designed to allow for more than the standard up to 8 textures
3518 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3519 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3521 * http://developer.nvidia.com/object/General_FAQ.html#t6
3523 * There are two new settings for GForce
3524 * the sampler one:
3525 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3526 * and the texture one:
3527 * GL_MAX_TEXTURE_COORDS_ARB.
3528 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3529 ******************/
3531 oldValue = This->stateBlock->samplerState[Sampler][Type];
3532 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3533 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3535 /* Handle recording of state blocks */
3536 if (This->isRecordingState) {
3537 TRACE("Recording... not performing anything\n");
3538 return WINED3D_OK;
3541 if(oldValue == Value) {
3542 TRACE("Application is setting the old value over, nothing to do\n");
3543 return WINED3D_OK;
3546 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3548 return WINED3D_OK;
3551 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3554 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3555 This, Sampler, debug_d3dsamplerstate(Type), Type);
3557 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3558 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3561 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3562 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3563 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3565 *Value = This->stateBlock->samplerState[Sampler][Type];
3566 TRACE("(%p) : Returning %#x\n", This, *Value);
3568 return WINED3D_OK;
3571 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3574 This->updateStateBlock->changed.scissorRect = TRUE;
3575 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3576 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3577 return WINED3D_OK;
3579 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3581 if(This->isRecordingState) {
3582 TRACE("Recording... not performing anything\n");
3583 return WINED3D_OK;
3586 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3588 return WINED3D_OK;
3591 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3594 *pRect = This->updateStateBlock->scissorRect;
3595 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3596 return WINED3D_OK;
3599 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3601 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3603 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3605 This->updateStateBlock->vertexDecl = pDecl;
3606 This->updateStateBlock->changed.vertexDecl = TRUE;
3608 if (This->isRecordingState) {
3609 TRACE("Recording... not performing anything\n");
3610 return WINED3D_OK;
3611 } else if(pDecl == oldDecl) {
3612 /* Checked after the assignment to allow proper stateblock recording */
3613 TRACE("Application is setting the old declaration over, nothing to do\n");
3614 return WINED3D_OK;
3617 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3618 return WINED3D_OK;
3621 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3624 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3626 *ppDecl = This->stateBlock->vertexDecl;
3627 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3628 return WINED3D_OK;
3631 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3633 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3635 This->updateStateBlock->vertexShader = pShader;
3636 This->updateStateBlock->changed.vertexShader = TRUE;
3638 if (This->isRecordingState) {
3639 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3640 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3641 TRACE("Recording... not performing anything\n");
3642 return WINED3D_OK;
3643 } else if(oldShader == pShader) {
3644 /* Checked here to allow proper stateblock recording */
3645 TRACE("App is setting the old shader over, nothing to do\n");
3646 return WINED3D_OK;
3649 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3650 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3651 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3653 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3655 return WINED3D_OK;
3658 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3661 if (NULL == ppShader) {
3662 return WINED3DERR_INVALIDCALL;
3664 *ppShader = This->stateBlock->vertexShader;
3665 if( NULL != *ppShader)
3666 IWineD3DVertexShader_AddRef(*ppShader);
3668 TRACE("(%p) : returning %p\n", This, *ppShader);
3669 return WINED3D_OK;
3672 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3673 IWineD3DDevice *iface,
3674 UINT start,
3675 CONST BOOL *srcData,
3676 UINT count) {
3678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3679 int i, cnt = min(count, MAX_CONST_B - 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->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3688 for (i = 0; i < cnt; i++)
3689 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3691 for (i = start; i < cnt + start; ++i) {
3692 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3695 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3697 return WINED3D_OK;
3700 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3701 IWineD3DDevice *iface,
3702 UINT start,
3703 BOOL *dstData,
3704 UINT count) {
3706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3707 int cnt = min(count, MAX_CONST_B - start);
3709 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3710 iface, dstData, start, count);
3712 if (dstData == NULL || cnt < 0)
3713 return WINED3DERR_INVALIDCALL;
3715 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3716 return WINED3D_OK;
3719 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3720 IWineD3DDevice *iface,
3721 UINT start,
3722 CONST int *srcData,
3723 UINT count) {
3725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3726 int i, cnt = min(count, MAX_CONST_I - start);
3728 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3729 iface, srcData, start, count);
3731 if (srcData == NULL || cnt < 0)
3732 return WINED3DERR_INVALIDCALL;
3734 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3735 for (i = 0; i < cnt; i++)
3736 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3737 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3739 for (i = start; i < cnt + start; ++i) {
3740 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3743 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3745 return WINED3D_OK;
3748 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3749 IWineD3DDevice *iface,
3750 UINT start,
3751 int *dstData,
3752 UINT count) {
3754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3755 int cnt = min(count, MAX_CONST_I - start);
3757 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3758 iface, dstData, start, count);
3760 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3761 return WINED3DERR_INVALIDCALL;
3763 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3764 return WINED3D_OK;
3767 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3768 IWineD3DDevice *iface,
3769 UINT start,
3770 CONST float *srcData,
3771 UINT count) {
3773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3774 UINT i;
3776 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3777 iface, srcData, start, count);
3779 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3780 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3781 return WINED3DERR_INVALIDCALL;
3783 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3784 if(TRACE_ON(d3d)) {
3785 for (i = 0; i < count; i++)
3786 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3787 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3790 if (!This->isRecordingState)
3792 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3793 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3796 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3797 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3799 return WINED3D_OK;
3802 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3803 IWineD3DDevice *iface,
3804 UINT start,
3805 float *dstData,
3806 UINT count) {
3808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3809 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3811 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3812 iface, dstData, start, count);
3814 if (dstData == NULL || cnt < 0)
3815 return WINED3DERR_INVALIDCALL;
3817 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3818 return WINED3D_OK;
3821 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3822 DWORD i;
3823 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3825 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3829 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3830 int i = This->rev_tex_unit_map[unit];
3831 int j = This->texUnitMap[stage];
3833 This->texUnitMap[stage] = unit;
3834 if (i != -1 && i != stage) {
3835 This->texUnitMap[i] = -1;
3838 This->rev_tex_unit_map[unit] = stage;
3839 if (j != -1 && j != unit) {
3840 This->rev_tex_unit_map[j] = -1;
3844 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3845 int i;
3847 This->fixed_function_usage_map = 0;
3848 for (i = 0; i < MAX_TEXTURES; ++i) {
3849 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3850 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3851 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3852 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3853 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3854 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3855 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3856 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3858 if (color_op == WINED3DTOP_DISABLE) {
3859 /* Not used, and disable higher stages */
3860 break;
3863 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3864 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3865 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3866 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3867 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3868 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3869 This->fixed_function_usage_map |= (1 << i);
3872 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3873 This->fixed_function_usage_map |= (1 << (i + 1));
3878 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3879 int i, tex;
3880 WORD ffu_map;
3882 device_update_fixed_function_usage_map(This);
3883 ffu_map = This->fixed_function_usage_map;
3885 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3886 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3887 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3889 if (!(ffu_map & 1)) continue;
3891 if (This->texUnitMap[i] != i) {
3892 device_map_stage(This, i, i);
3893 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3894 markTextureStagesDirty(This, i);
3897 return;
3900 /* Now work out the mapping */
3901 tex = 0;
3902 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3904 if (!(ffu_map & 1)) continue;
3906 if (This->texUnitMap[i] != tex) {
3907 device_map_stage(This, i, tex);
3908 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3909 markTextureStagesDirty(This, i);
3912 ++tex;
3916 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3917 const DWORD *sampler_tokens =
3918 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3919 int i;
3921 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3922 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3923 device_map_stage(This, i, i);
3924 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3925 if (i < MAX_TEXTURES) {
3926 markTextureStagesDirty(This, i);
3932 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3933 const DWORD *vshader_sampler_tokens, int unit)
3935 int current_mapping = This->rev_tex_unit_map[unit];
3937 if (current_mapping == -1) {
3938 /* Not currently used */
3939 return TRUE;
3942 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3943 /* Used by a fragment sampler */
3945 if (!pshader_sampler_tokens) {
3946 /* No pixel shader, check fixed function */
3947 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3950 /* Pixel shader, check the shader's sampler map */
3951 return !pshader_sampler_tokens[current_mapping];
3954 /* Used by a vertex sampler */
3955 return !vshader_sampler_tokens[current_mapping];
3958 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3959 const DWORD *vshader_sampler_tokens =
3960 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3961 const DWORD *pshader_sampler_tokens = NULL;
3962 int start = GL_LIMITS(combined_samplers) - 1;
3963 int i;
3965 if (ps) {
3966 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3968 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3969 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3970 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3973 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3974 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3975 if (vshader_sampler_tokens[i]) {
3976 if (This->texUnitMap[vsampler_idx] != -1) {
3977 /* Already mapped somewhere */
3978 continue;
3981 while (start >= 0) {
3982 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3983 device_map_stage(This, vsampler_idx, start);
3984 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3986 --start;
3987 break;
3990 --start;
3996 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3997 BOOL vs = use_vs(This->stateBlock);
3998 BOOL ps = use_ps(This->stateBlock);
4000 * Rules are:
4001 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
4002 * that would be really messy and require shader recompilation
4003 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
4004 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
4006 if (ps) {
4007 device_map_psamplers(This);
4008 } else {
4009 device_map_fixed_function_samplers(This);
4012 if (vs) {
4013 device_map_vsamplers(This, ps);
4017 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4019 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4020 This->updateStateBlock->pixelShader = pShader;
4021 This->updateStateBlock->changed.pixelShader = TRUE;
4023 /* Handle recording of state blocks */
4024 if (This->isRecordingState) {
4025 TRACE("Recording... not performing anything\n");
4028 if (This->isRecordingState) {
4029 TRACE("Recording... not performing anything\n");
4030 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4031 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4032 return WINED3D_OK;
4035 if(pShader == oldShader) {
4036 TRACE("App is setting the old pixel shader over, nothing to do\n");
4037 return WINED3D_OK;
4040 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4041 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4043 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4044 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4046 return WINED3D_OK;
4049 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4052 if (NULL == ppShader) {
4053 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4054 return WINED3DERR_INVALIDCALL;
4057 *ppShader = This->stateBlock->pixelShader;
4058 if (NULL != *ppShader) {
4059 IWineD3DPixelShader_AddRef(*ppShader);
4061 TRACE("(%p) : returning %p\n", This, *ppShader);
4062 return WINED3D_OK;
4065 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4066 IWineD3DDevice *iface,
4067 UINT start,
4068 CONST BOOL *srcData,
4069 UINT count) {
4071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4072 int i, cnt = min(count, MAX_CONST_B - 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->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4081 for (i = 0; i < cnt; i++)
4082 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4084 for (i = start; i < cnt + start; ++i) {
4085 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4088 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4090 return WINED3D_OK;
4093 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4094 IWineD3DDevice *iface,
4095 UINT start,
4096 BOOL *dstData,
4097 UINT count) {
4099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4100 int cnt = min(count, MAX_CONST_B - start);
4102 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4103 iface, dstData, start, count);
4105 if (dstData == NULL || cnt < 0)
4106 return WINED3DERR_INVALIDCALL;
4108 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4109 return WINED3D_OK;
4112 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4113 IWineD3DDevice *iface,
4114 UINT start,
4115 CONST int *srcData,
4116 UINT count) {
4118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4119 int i, cnt = min(count, MAX_CONST_I - start);
4121 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4122 iface, srcData, start, count);
4124 if (srcData == NULL || cnt < 0)
4125 return WINED3DERR_INVALIDCALL;
4127 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4128 for (i = 0; i < cnt; i++)
4129 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4130 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4132 for (i = start; i < cnt + start; ++i) {
4133 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4136 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4138 return WINED3D_OK;
4141 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4142 IWineD3DDevice *iface,
4143 UINT start,
4144 int *dstData,
4145 UINT count) {
4147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4148 int cnt = min(count, MAX_CONST_I - start);
4150 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4151 iface, dstData, start, count);
4153 if (dstData == NULL || cnt < 0)
4154 return WINED3DERR_INVALIDCALL;
4156 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4157 return WINED3D_OK;
4160 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4161 IWineD3DDevice *iface,
4162 UINT start,
4163 CONST float *srcData,
4164 UINT count) {
4166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4167 UINT i;
4169 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4170 iface, srcData, start, count);
4172 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4173 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4174 return WINED3DERR_INVALIDCALL;
4176 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4177 if(TRACE_ON(d3d)) {
4178 for (i = 0; i < count; i++)
4179 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4180 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4183 if (!This->isRecordingState)
4185 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4186 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4189 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4190 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4192 return WINED3D_OK;
4195 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4196 IWineD3DDevice *iface,
4197 UINT start,
4198 float *dstData,
4199 UINT count) {
4201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4202 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4204 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4205 iface, dstData, start, count);
4207 if (dstData == NULL || cnt < 0)
4208 return WINED3DERR_INVALIDCALL;
4210 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4211 return WINED3D_OK;
4214 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4215 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4216 const WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags)
4218 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4219 unsigned int i;
4220 DWORD DestFVF = dest->fvf;
4221 WINED3DVIEWPORT vp;
4222 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4223 BOOL doClip;
4224 DWORD numTextures;
4226 if (lpStrideData->u.s.normal.lpData) {
4227 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4230 if (lpStrideData->u.s.position.lpData == NULL) {
4231 ERR("Source has no position mask\n");
4232 return WINED3DERR_INVALIDCALL;
4235 /* We might access VBOs from this code, so hold the lock */
4236 ENTER_GL();
4238 if (dest->resource.allocatedMemory == NULL) {
4239 /* This may happen if we do direct locking into a vbo. Unlikely,
4240 * but theoretically possible(ddraw processvertices test)
4242 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4243 if(!dest->resource.allocatedMemory) {
4244 LEAVE_GL();
4245 ERR("Out of memory\n");
4246 return E_OUTOFMEMORY;
4248 if(dest->vbo) {
4249 const void *src;
4250 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4251 checkGLcall("glBindBufferARB");
4252 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4253 if(src) {
4254 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4256 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4257 checkGLcall("glUnmapBufferARB");
4261 /* Get a pointer into the destination vbo(create one if none exists) and
4262 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4264 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4265 dest->Flags |= VBFLAG_CREATEVBO;
4266 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4269 if(dest->vbo) {
4270 unsigned char extrabytes = 0;
4271 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4272 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4273 * this may write 4 extra bytes beyond the area that should be written
4275 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4276 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4277 if(!dest_conv_addr) {
4278 ERR("Out of memory\n");
4279 /* Continue without storing converted vertices */
4281 dest_conv = dest_conv_addr;
4284 /* Should I clip?
4285 * a) WINED3DRS_CLIPPING is enabled
4286 * b) WINED3DVOP_CLIP is passed
4288 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4289 static BOOL warned = FALSE;
4291 * The clipping code is not quite correct. Some things need
4292 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4293 * so disable clipping for now.
4294 * (The graphics in Half-Life are broken, and my processvertices
4295 * test crashes with IDirect3DDevice3)
4296 doClip = TRUE;
4298 doClip = FALSE;
4299 if(!warned) {
4300 warned = TRUE;
4301 FIXME("Clipping is broken and disabled for now\n");
4303 } else doClip = FALSE;
4304 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4306 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4307 WINED3DTS_VIEW,
4308 &view_mat);
4309 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4310 WINED3DTS_PROJECTION,
4311 &proj_mat);
4312 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4313 WINED3DTS_WORLDMATRIX(0),
4314 &world_mat);
4316 TRACE("View mat:\n");
4317 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);
4318 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);
4319 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);
4320 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);
4322 TRACE("Proj mat:\n");
4323 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);
4324 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);
4325 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);
4326 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);
4328 TRACE("World mat:\n");
4329 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);
4330 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);
4331 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);
4332 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);
4334 /* Get the viewport */
4335 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4336 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4337 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4339 multiply_matrix(&mat,&view_mat,&world_mat);
4340 multiply_matrix(&mat,&proj_mat,&mat);
4342 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4344 for (i = 0; i < dwCount; i+= 1) {
4345 unsigned int tex_index;
4347 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4348 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4349 /* The position first */
4350 const float *p =
4351 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4352 float x, y, z, rhw;
4353 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4355 /* Multiplication with world, view and projection matrix */
4356 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);
4357 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);
4358 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);
4359 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);
4361 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4363 /* WARNING: The following things are taken from d3d7 and were not yet checked
4364 * against d3d8 or d3d9!
4367 /* Clipping conditions: From msdn
4369 * A vertex is clipped if it does not match the following requirements
4370 * -rhw < x <= rhw
4371 * -rhw < y <= rhw
4372 * 0 < z <= rhw
4373 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4375 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4376 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4380 if( !doClip ||
4381 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4382 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4383 ( rhw > eps ) ) ) {
4385 /* "Normal" viewport transformation (not clipped)
4386 * 1) The values are divided by rhw
4387 * 2) The y axis is negative, so multiply it with -1
4388 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4389 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4390 * 4) Multiply x with Width/2 and add Width/2
4391 * 5) The same for the height
4392 * 6) Add the viewpoint X and Y to the 2D coordinates and
4393 * The minimum Z value to z
4394 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4396 * Well, basically it's simply a linear transformation into viewport
4397 * coordinates
4400 x /= rhw;
4401 y /= rhw;
4402 z /= rhw;
4404 y *= -1;
4406 x *= vp.Width / 2;
4407 y *= vp.Height / 2;
4408 z *= vp.MaxZ - vp.MinZ;
4410 x += vp.Width / 2 + vp.X;
4411 y += vp.Height / 2 + vp.Y;
4412 z += vp.MinZ;
4414 rhw = 1 / rhw;
4415 } else {
4416 /* That vertex got clipped
4417 * Contrary to OpenGL it is not dropped completely, it just
4418 * undergoes a different calculation.
4420 TRACE("Vertex got clipped\n");
4421 x += rhw;
4422 y += rhw;
4424 x /= 2;
4425 y /= 2;
4427 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4428 * outside of the main vertex buffer memory. That needs some more
4429 * investigation...
4433 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4436 ( (float *) dest_ptr)[0] = x;
4437 ( (float *) dest_ptr)[1] = y;
4438 ( (float *) dest_ptr)[2] = z;
4439 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4441 dest_ptr += 3 * sizeof(float);
4443 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4444 dest_ptr += sizeof(float);
4447 if(dest_conv) {
4448 float w = 1 / rhw;
4449 ( (float *) dest_conv)[0] = x * w;
4450 ( (float *) dest_conv)[1] = y * w;
4451 ( (float *) dest_conv)[2] = z * w;
4452 ( (float *) dest_conv)[3] = w;
4454 dest_conv += 3 * sizeof(float);
4456 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4457 dest_conv += sizeof(float);
4461 if (DestFVF & WINED3DFVF_PSIZE) {
4462 dest_ptr += sizeof(DWORD);
4463 if(dest_conv) dest_conv += sizeof(DWORD);
4465 if (DestFVF & WINED3DFVF_NORMAL) {
4466 const float *normal =
4467 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4468 /* AFAIK this should go into the lighting information */
4469 FIXME("Didn't expect the destination to have a normal\n");
4470 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4471 if(dest_conv) {
4472 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4476 if (DestFVF & WINED3DFVF_DIFFUSE) {
4477 const DWORD *color_d =
4478 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4479 if(!color_d) {
4480 static BOOL warned = FALSE;
4482 if(!warned) {
4483 ERR("No diffuse color in source, but destination has one\n");
4484 warned = TRUE;
4487 *( (DWORD *) dest_ptr) = 0xffffffff;
4488 dest_ptr += sizeof(DWORD);
4490 if(dest_conv) {
4491 *( (DWORD *) dest_conv) = 0xffffffff;
4492 dest_conv += sizeof(DWORD);
4495 else {
4496 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4497 if(dest_conv) {
4498 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4499 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4500 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4501 dest_conv += sizeof(DWORD);
4506 if (DestFVF & WINED3DFVF_SPECULAR) {
4507 /* What's the color value in the feedback buffer? */
4508 const DWORD *color_s =
4509 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4510 if(!color_s) {
4511 static BOOL warned = FALSE;
4513 if(!warned) {
4514 ERR("No specular color in source, but destination has one\n");
4515 warned = TRUE;
4518 *( (DWORD *) dest_ptr) = 0xFF000000;
4519 dest_ptr += sizeof(DWORD);
4521 if(dest_conv) {
4522 *( (DWORD *) dest_conv) = 0xFF000000;
4523 dest_conv += sizeof(DWORD);
4526 else {
4527 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4528 if(dest_conv) {
4529 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4530 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4531 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4532 dest_conv += sizeof(DWORD);
4537 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4538 const float *tex_coord =
4539 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4540 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4541 if(!tex_coord) {
4542 ERR("No source texture, but destination requests one\n");
4543 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4544 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4546 else {
4547 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4548 if(dest_conv) {
4549 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4555 if(dest_conv) {
4556 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4557 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4558 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4559 dwCount * get_flexible_vertex_size(DestFVF),
4560 dest_conv_addr));
4561 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4562 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4565 LEAVE_GL();
4567 return WINED3D_OK;
4569 #undef copy_and_next
4571 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4573 WineDirect3DVertexStridedData strided;
4574 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4575 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4577 if(pVertexDecl) {
4578 ERR("Output vertex declaration not implemented yet\n");
4581 /* Need any context to write to the vbo. */
4582 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4584 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4585 * control the streamIsUP flag, thus restore it afterwards.
4587 This->stateBlock->streamIsUP = FALSE;
4588 memset(&strided, 0, sizeof(strided));
4589 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4590 This->stateBlock->streamIsUP = streamWasUP;
4592 if(vbo || SrcStartIndex) {
4593 unsigned int i;
4594 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4595 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4597 * Also get the start index in, but only loop over all elements if there's something to add at all.
4599 #define FIXSRC(type) \
4600 if(strided.u.s.type.VBO) { \
4601 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4602 strided.u.s.type.VBO = 0; \
4603 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4604 ENTER_GL(); \
4605 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4606 vb->vbo = 0; \
4607 LEAVE_GL(); \
4609 if(strided.u.s.type.lpData) { \
4610 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4612 FIXSRC(position);
4613 FIXSRC(blendWeights);
4614 FIXSRC(blendMatrixIndices);
4615 FIXSRC(normal);
4616 FIXSRC(pSize);
4617 FIXSRC(diffuse);
4618 FIXSRC(specular);
4619 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4620 FIXSRC(texCoords[i]);
4622 FIXSRC(position2);
4623 FIXSRC(normal2);
4624 FIXSRC(tangent);
4625 FIXSRC(binormal);
4626 FIXSRC(tessFactor);
4627 FIXSRC(fog);
4628 FIXSRC(depth);
4629 FIXSRC(sample);
4630 #undef FIXSRC
4633 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4636 /*****
4637 * Get / Set Texture Stage States
4638 * TODO: Verify against dx9 definitions
4639 *****/
4640 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4642 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4644 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4646 if (Stage >= MAX_TEXTURES) {
4647 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4648 return WINED3D_OK;
4651 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4652 This->updateStateBlock->textureState[Stage][Type] = Value;
4654 if (This->isRecordingState) {
4655 TRACE("Recording... not performing anything\n");
4656 return WINED3D_OK;
4659 /* Checked after the assignments to allow proper stateblock recording */
4660 if(oldValue == Value) {
4661 TRACE("App is setting the old value over, nothing to do\n");
4662 return WINED3D_OK;
4665 if(Stage > This->stateBlock->lowest_disabled_stage &&
4666 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4667 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4668 * Changes in other states are important on disabled stages too
4670 return WINED3D_OK;
4673 if(Type == WINED3DTSS_COLOROP) {
4674 int i;
4676 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4677 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4678 * they have to be disabled
4680 * The current stage is dirtified below.
4682 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4683 TRACE("Additionally dirtifying stage %d\n", i);
4684 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4686 This->stateBlock->lowest_disabled_stage = Stage;
4687 TRACE("New lowest disabled: %d\n", Stage);
4688 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4689 /* Previously disabled stage enabled. Stages above it may need enabling
4690 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4691 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4693 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4696 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4697 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4698 break;
4700 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4701 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4703 This->stateBlock->lowest_disabled_stage = i;
4704 TRACE("New lowest disabled: %d\n", i);
4708 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4710 return WINED3D_OK;
4713 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4715 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4716 *pValue = This->updateStateBlock->textureState[Stage][Type];
4717 return WINED3D_OK;
4720 /*****
4721 * Get / Set Texture
4722 *****/
4723 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4725 IWineD3DBaseTexture *oldTexture;
4727 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4729 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4730 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4733 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4734 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4735 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4738 oldTexture = This->updateStateBlock->textures[Stage];
4740 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4741 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4743 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4744 return WINED3DERR_INVALIDCALL;
4747 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4748 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4750 This->updateStateBlock->changed.textures |= 1 << Stage;
4751 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4752 This->updateStateBlock->textures[Stage] = pTexture;
4754 /* Handle recording of state blocks */
4755 if (This->isRecordingState) {
4756 TRACE("Recording... not performing anything\n");
4757 return WINED3D_OK;
4760 if(oldTexture == pTexture) {
4761 TRACE("App is setting the same texture again, nothing to do\n");
4762 return WINED3D_OK;
4765 /** NOTE: MSDN says that setTexture increases the reference count,
4766 * and that the application must set the texture back to null (or have a leaky application),
4767 * This means we should pass the refcount up to the parent
4768 *******************************/
4769 if (NULL != This->updateStateBlock->textures[Stage]) {
4770 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4771 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4772 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4774 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4776 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4778 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4781 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4782 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4783 * so the COLOROP and ALPHAOP have to be dirtified.
4785 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4786 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4788 if(bindCount == 1) {
4789 new->baseTexture.sampler = Stage;
4791 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4795 if (NULL != oldTexture) {
4796 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4797 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4799 IWineD3DBaseTexture_Release(oldTexture);
4800 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4801 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4802 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4805 if(bindCount && old->baseTexture.sampler == Stage) {
4806 int i;
4807 /* Have to do a search for the other sampler(s) where the texture is bound to
4808 * Shouldn't happen as long as apps bind a texture only to one stage
4810 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4811 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4812 if(This->updateStateBlock->textures[i] == oldTexture) {
4813 old->baseTexture.sampler = i;
4814 break;
4820 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4822 return WINED3D_OK;
4825 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4826 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4828 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4830 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4831 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4834 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4835 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4836 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4839 *ppTexture=This->stateBlock->textures[Stage];
4840 if (*ppTexture)
4841 IWineD3DBaseTexture_AddRef(*ppTexture);
4843 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4845 return WINED3D_OK;
4848 /*****
4849 * Get Back Buffer
4850 *****/
4851 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4852 IWineD3DSurface **ppBackBuffer) {
4853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4854 IWineD3DSwapChain *swapChain;
4855 HRESULT hr;
4857 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4859 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4860 if (hr == WINED3D_OK) {
4861 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4862 IWineD3DSwapChain_Release(swapChain);
4863 } else {
4864 *ppBackBuffer = NULL;
4866 return hr;
4869 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4871 WARN("(%p) : stub, calling idirect3d for now\n", This);
4872 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4875 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4877 IWineD3DSwapChain *swapChain;
4878 HRESULT hr;
4880 if(iSwapChain > 0) {
4881 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4882 if (hr == WINED3D_OK) {
4883 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4884 IWineD3DSwapChain_Release(swapChain);
4885 } else {
4886 FIXME("(%p) Error getting display mode\n", This);
4888 } else {
4889 /* Don't read the real display mode,
4890 but return the stored mode instead. X11 can't change the color
4891 depth, and some apps are pretty angry if they SetDisplayMode from
4892 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4894 Also don't relay to the swapchain because with ddraw it's possible
4895 that there isn't a swapchain at all */
4896 pMode->Width = This->ddraw_width;
4897 pMode->Height = This->ddraw_height;
4898 pMode->Format = This->ddraw_format;
4899 pMode->RefreshRate = 0;
4900 hr = WINED3D_OK;
4903 return hr;
4906 /*****
4907 * Stateblock related functions
4908 *****/
4910 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4912 IWineD3DStateBlock *stateblock;
4913 HRESULT hr;
4915 TRACE("(%p)\n", This);
4917 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4919 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4920 if (FAILED(hr)) return hr;
4922 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4923 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4924 This->isRecordingState = TRUE;
4926 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4928 return WINED3D_OK;
4931 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4933 unsigned int i, j;
4934 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4936 if (!This->isRecordingState) {
4937 WARN("(%p) not recording! returning error\n", This);
4938 *ppStateBlock = NULL;
4939 return WINED3DERR_INVALIDCALL;
4942 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
4944 DWORD map = object->changed.renderState[i];
4945 for (j = 0; map; map >>= 1, ++j)
4947 if (!(map & 1)) continue;
4949 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
4953 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
4955 DWORD map = object->changed.transform[i];
4956 for (j = 0; map; map >>= 1, ++j)
4958 if (!(map & 1)) continue;
4960 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
4963 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4964 if(object->changed.vertexShaderConstantsF[i]) {
4965 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4966 object->num_contained_vs_consts_f++;
4969 for(i = 0; i < MAX_CONST_I; i++) {
4970 if (object->changed.vertexShaderConstantsI & (1 << i))
4972 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4973 object->num_contained_vs_consts_i++;
4976 for(i = 0; i < MAX_CONST_B; i++) {
4977 if (object->changed.vertexShaderConstantsB & (1 << i))
4979 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4980 object->num_contained_vs_consts_b++;
4983 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4985 if (object->changed.pixelShaderConstantsF[i])
4987 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4988 ++object->num_contained_ps_consts_f;
4991 for(i = 0; i < MAX_CONST_I; i++) {
4992 if (object->changed.pixelShaderConstantsI & (1 << i))
4994 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4995 object->num_contained_ps_consts_i++;
4998 for(i = 0; i < MAX_CONST_B; i++) {
4999 if (object->changed.pixelShaderConstantsB & (1 << i))
5001 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
5002 object->num_contained_ps_consts_b++;
5005 for(i = 0; i < MAX_TEXTURES; i++) {
5006 DWORD map = object->changed.textureState[i];
5008 for(j = 0; map; map >>= 1, ++j)
5010 if (!(map & 1)) continue;
5012 object->contained_tss_states[object->num_contained_tss_states].stage = i;
5013 object->contained_tss_states[object->num_contained_tss_states].state = j;
5014 ++object->num_contained_tss_states;
5017 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
5018 DWORD map = object->changed.samplerState[i];
5020 for (j = 0; map; map >>= 1, ++j)
5022 if (!(map & 1)) continue;
5024 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
5025 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
5026 ++object->num_contained_sampler_states;
5030 *ppStateBlock = (IWineD3DStateBlock*) object;
5031 This->isRecordingState = FALSE;
5032 This->updateStateBlock = This->stateBlock;
5033 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5034 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5035 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5036 return WINED3D_OK;
5039 /*****
5040 * Scene related functions
5041 *****/
5042 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5043 /* At the moment we have no need for any functionality at the beginning
5044 of a scene */
5045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5046 TRACE("(%p)\n", This);
5048 if(This->inScene) {
5049 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
5050 return WINED3DERR_INVALIDCALL;
5052 This->inScene = TRUE;
5053 return WINED3D_OK;
5056 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5058 TRACE("(%p)\n", This);
5060 if(!This->inScene) {
5061 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
5062 return WINED3DERR_INVALIDCALL;
5065 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5066 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5067 glFlush();
5068 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5069 * fails
5072 This->inScene = FALSE;
5073 return WINED3D_OK;
5076 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5077 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5078 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5080 IWineD3DSwapChain *swapChain = NULL;
5081 int i;
5082 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5084 TRACE("(%p) Presenting the frame\n", This);
5086 for(i = 0 ; i < swapchains ; i ++) {
5088 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5089 TRACE("presentinng chain %d, %p\n", i, swapChain);
5090 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5091 IWineD3DSwapChain_Release(swapChain);
5094 return WINED3D_OK;
5097 /* Not called from the VTable (internal subroutine) */
5098 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5099 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5100 float Z, DWORD Stencil) {
5101 GLbitfield glMask = 0;
5102 unsigned int i;
5103 WINED3DRECT curRect;
5104 RECT vp_rect;
5105 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5106 UINT drawable_width, drawable_height;
5107 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5108 IWineD3DSwapChainImpl *swapchain = NULL;
5110 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5111 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5112 * for the cleared parts, and the untouched parts.
5114 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5115 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5116 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5117 * checking all this if the dest surface is in the drawable anyway.
5119 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5120 while(1) {
5121 if(vp->X != 0 || vp->Y != 0 ||
5122 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5123 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5124 break;
5126 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5127 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5128 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5129 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5130 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5131 break;
5133 if(Count > 0 && pRects && (
5134 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5135 pRects[0].x2 < target->currentDesc.Width ||
5136 pRects[0].y2 < target->currentDesc.Height)) {
5137 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5138 break;
5140 break;
5144 target->get_drawable_size(target, &drawable_width, &drawable_height);
5146 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5147 ENTER_GL();
5149 /* Only set the values up once, as they are not changing */
5150 if (Flags & WINED3DCLEAR_STENCIL) {
5151 glClearStencil(Stencil);
5152 checkGLcall("glClearStencil");
5153 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5154 glStencilMask(0xFFFFFFFF);
5157 if (Flags & WINED3DCLEAR_ZBUFFER) {
5158 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5159 glDepthMask(GL_TRUE);
5160 glClearDepth(Z);
5161 checkGLcall("glClearDepth");
5162 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5163 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5165 if (vp->X != 0 || vp->Y != 0 ||
5166 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5167 surface_load_ds_location(This->stencilBufferTarget, location);
5169 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5170 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5171 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5172 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5173 surface_load_ds_location(This->stencilBufferTarget, location);
5175 else if (Count > 0 && pRects && (
5176 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5177 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5178 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5179 surface_load_ds_location(This->stencilBufferTarget, location);
5183 if (Flags & WINED3DCLEAR_TARGET) {
5184 TRACE("Clearing screen with glClear to color %x\n", Color);
5185 glClearColor(D3DCOLOR_R(Color),
5186 D3DCOLOR_G(Color),
5187 D3DCOLOR_B(Color),
5188 D3DCOLOR_A(Color));
5189 checkGLcall("glClearColor");
5191 /* Clear ALL colors! */
5192 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5193 glMask = glMask | GL_COLOR_BUFFER_BIT;
5196 vp_rect.left = vp->X;
5197 vp_rect.top = vp->Y;
5198 vp_rect.right = vp->X + vp->Width;
5199 vp_rect.bottom = vp->Y + vp->Height;
5200 if (!(Count > 0 && pRects)) {
5201 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5202 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5204 if(This->render_offscreen) {
5205 glScissor(vp_rect.left, vp_rect.top,
5206 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5207 } else {
5208 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5209 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5211 checkGLcall("glScissor");
5212 glClear(glMask);
5213 checkGLcall("glClear");
5214 } else {
5215 /* Now process each rect in turn */
5216 for (i = 0; i < Count; i++) {
5217 /* Note gl uses lower left, width/height */
5218 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5219 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5220 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5222 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5223 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5224 curRect.x1, (target->currentDesc.Height - curRect.y2),
5225 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5227 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5228 * The rectangle is not cleared, no error is returned, but further rectanlges are
5229 * still cleared if they are valid
5231 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5232 TRACE("Rectangle with negative dimensions, ignoring\n");
5233 continue;
5236 if(This->render_offscreen) {
5237 glScissor(curRect.x1, curRect.y1,
5238 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5239 } else {
5240 glScissor(curRect.x1, drawable_height - curRect.y2,
5241 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5243 checkGLcall("glScissor");
5245 glClear(glMask);
5246 checkGLcall("glClear");
5250 /* Restore the old values (why..?) */
5251 if (Flags & WINED3DCLEAR_STENCIL) {
5252 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5254 if (Flags & WINED3DCLEAR_TARGET) {
5255 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5256 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5257 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5258 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5259 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5261 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5262 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5264 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5266 if (Flags & WINED3DCLEAR_ZBUFFER) {
5267 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5268 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5269 surface_modify_ds_location(This->stencilBufferTarget, location);
5272 LEAVE_GL();
5274 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5275 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5276 glFlush();
5278 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5281 return WINED3D_OK;
5284 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5285 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5287 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5289 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5290 Count, pRects, Flags, Color, Z, Stencil);
5292 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5293 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5294 /* TODO: What about depth stencil buffers without stencil bits? */
5295 return WINED3DERR_INVALIDCALL;
5298 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5301 /*****
5302 * Drawing functions
5303 *****/
5304 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5305 UINT PrimitiveCount) {
5307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5309 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5310 debug_d3dprimitivetype(PrimitiveType),
5311 StartVertex, PrimitiveCount);
5313 if(!This->stateBlock->vertexDecl) {
5314 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5315 return WINED3DERR_INVALIDCALL;
5318 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5319 if(This->stateBlock->streamIsUP) {
5320 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5321 This->stateBlock->streamIsUP = FALSE;
5324 if(This->stateBlock->loadBaseVertexIndex != 0) {
5325 This->stateBlock->loadBaseVertexIndex = 0;
5326 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5328 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5329 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0/* NumVertices */, StartVertex /* start_idx */,
5330 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5331 return WINED3D_OK;
5334 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5335 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5336 WINED3DPRIMITIVETYPE PrimitiveType,
5337 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5340 UINT idxStride = 2;
5341 IWineD3DIndexBuffer *pIB;
5342 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5343 GLuint vbo;
5345 pIB = This->stateBlock->pIndexData;
5346 if (!pIB) {
5347 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5348 * without an index buffer set. (The first time at least...)
5349 * D3D8 simply dies, but I doubt it can do much harm to return
5350 * D3DERR_INVALIDCALL there as well. */
5351 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5352 return WINED3DERR_INVALIDCALL;
5355 if(!This->stateBlock->vertexDecl) {
5356 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5357 return WINED3DERR_INVALIDCALL;
5360 if(This->stateBlock->streamIsUP) {
5361 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5362 This->stateBlock->streamIsUP = FALSE;
5364 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5366 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5367 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5368 minIndex, NumVertices, startIndex, primCount);
5370 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5371 if (IdxBufDsc.Format == WINED3DFMT_R16_UINT) {
5372 idxStride = 2;
5373 } else {
5374 idxStride = 4;
5377 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5378 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5379 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5382 drawPrimitive(iface, PrimitiveType, primCount, NumVertices, startIndex,
5383 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5385 return WINED3D_OK;
5388 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5389 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5390 UINT VertexStreamZeroStride) {
5391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5392 IWineD3DVertexBuffer *vb;
5394 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5395 debug_d3dprimitivetype(PrimitiveType),
5396 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5398 if(!This->stateBlock->vertexDecl) {
5399 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5400 return WINED3DERR_INVALIDCALL;
5403 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5404 vb = This->stateBlock->streamSource[0];
5405 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5406 if(vb) IWineD3DVertexBuffer_Release(vb);
5407 This->stateBlock->streamOffset[0] = 0;
5408 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5409 This->stateBlock->streamIsUP = TRUE;
5410 This->stateBlock->loadBaseVertexIndex = 0;
5412 /* TODO: Only mark dirty if drawing from a different UP address */
5413 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5415 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* NumVertices */,
5416 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5418 /* MSDN specifies stream zero settings must be set to NULL */
5419 This->stateBlock->streamStride[0] = 0;
5420 This->stateBlock->streamSource[0] = NULL;
5422 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5423 * the new stream sources or use UP drawing again
5425 return WINED3D_OK;
5428 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5429 UINT MinVertexIndex, UINT NumVertices,
5430 UINT PrimitiveCount, CONST void* pIndexData,
5431 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5432 UINT VertexStreamZeroStride) {
5433 int idxStride;
5434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5435 IWineD3DVertexBuffer *vb;
5436 IWineD3DIndexBuffer *ib;
5438 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5439 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5440 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5441 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5443 if(!This->stateBlock->vertexDecl) {
5444 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5445 return WINED3DERR_INVALIDCALL;
5448 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5449 idxStride = 2;
5450 } else {
5451 idxStride = 4;
5454 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5455 vb = This->stateBlock->streamSource[0];
5456 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5457 if(vb) IWineD3DVertexBuffer_Release(vb);
5458 This->stateBlock->streamIsUP = TRUE;
5459 This->stateBlock->streamOffset[0] = 0;
5460 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5462 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5463 This->stateBlock->baseVertexIndex = 0;
5464 This->stateBlock->loadBaseVertexIndex = 0;
5465 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5466 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5467 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5469 drawPrimitive(iface, PrimitiveType, PrimitiveCount, NumVertices, 0 /* start_idx */, idxStride, pIndexData, MinVertexIndex);
5471 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5472 This->stateBlock->streamSource[0] = NULL;
5473 This->stateBlock->streamStride[0] = 0;
5474 ib = This->stateBlock->pIndexData;
5475 if(ib) {
5476 IWineD3DIndexBuffer_Release(ib);
5477 This->stateBlock->pIndexData = NULL;
5479 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5480 * SetStreamSource to specify a vertex buffer
5483 return WINED3D_OK;
5486 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5487 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5488 const WineDirect3DVertexStridedData *DrawPrimStrideData)
5490 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5492 /* Mark the state dirty until we have nicer tracking
5493 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5494 * that value.
5496 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5497 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5498 This->stateBlock->baseVertexIndex = 0;
5499 This->up_strided = DrawPrimStrideData;
5500 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, NULL, 0);
5501 This->up_strided = NULL;
5502 return WINED3D_OK;
5505 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5506 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5507 const WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, const void *pIndexData,
5508 WINED3DFORMAT IndexDataFormat)
5510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5511 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5513 /* Mark the state dirty until we have nicer tracking
5514 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5515 * that value.
5517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5518 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5519 This->stateBlock->streamIsUP = TRUE;
5520 This->stateBlock->baseVertexIndex = 0;
5521 This->up_strided = DrawPrimStrideData;
5522 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5523 This->up_strided = NULL;
5524 return WINED3D_OK;
5527 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5528 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5529 * not callable by the app directly no parameter validation checks are needed here.
5531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5532 WINED3DLOCKED_BOX src;
5533 WINED3DLOCKED_BOX dst;
5534 HRESULT hr;
5535 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5537 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5538 * dirtification to improve loading performance.
5540 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5541 if(FAILED(hr)) return hr;
5542 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5543 if(FAILED(hr)) {
5544 IWineD3DVolume_UnlockBox(pSourceVolume);
5545 return hr;
5548 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5550 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5551 if(FAILED(hr)) {
5552 IWineD3DVolume_UnlockBox(pSourceVolume);
5553 } else {
5554 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5556 return hr;
5559 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5560 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5562 HRESULT hr = WINED3D_OK;
5563 WINED3DRESOURCETYPE sourceType;
5564 WINED3DRESOURCETYPE destinationType;
5565 int i ,levels;
5567 /* TODO: think about moving the code into IWineD3DBaseTexture */
5569 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5571 /* verify that the source and destination textures aren't NULL */
5572 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5573 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5574 This, pSourceTexture, pDestinationTexture);
5575 hr = WINED3DERR_INVALIDCALL;
5578 if (pSourceTexture == pDestinationTexture) {
5579 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5580 This, pSourceTexture, pDestinationTexture);
5581 hr = WINED3DERR_INVALIDCALL;
5583 /* Verify that the source and destination textures are the same type */
5584 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5585 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5587 if (sourceType != destinationType) {
5588 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5589 This);
5590 hr = WINED3DERR_INVALIDCALL;
5593 /* check that both textures have the identical numbers of levels */
5594 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5595 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5596 hr = WINED3DERR_INVALIDCALL;
5599 if (WINED3D_OK == hr) {
5600 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5602 /* Make sure that the destination texture is loaded */
5603 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5605 /* Update every surface level of the texture */
5606 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5608 switch (sourceType) {
5609 case WINED3DRTYPE_TEXTURE:
5611 IWineD3DSurface *srcSurface;
5612 IWineD3DSurface *destSurface;
5614 for (i = 0 ; i < levels ; ++i) {
5615 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5616 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5617 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5618 IWineD3DSurface_Release(srcSurface);
5619 IWineD3DSurface_Release(destSurface);
5620 if (WINED3D_OK != hr) {
5621 WARN("(%p) : Call to update surface failed\n", This);
5622 return hr;
5626 break;
5627 case WINED3DRTYPE_CUBETEXTURE:
5629 IWineD3DSurface *srcSurface;
5630 IWineD3DSurface *destSurface;
5631 WINED3DCUBEMAP_FACES faceType;
5633 for (i = 0 ; i < levels ; ++i) {
5634 /* Update each cube face */
5635 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5636 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5637 if (WINED3D_OK != hr) {
5638 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5639 } else {
5640 TRACE("Got srcSurface %p\n", srcSurface);
5642 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5643 if (WINED3D_OK != hr) {
5644 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5645 } else {
5646 TRACE("Got desrSurface %p\n", destSurface);
5648 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5649 IWineD3DSurface_Release(srcSurface);
5650 IWineD3DSurface_Release(destSurface);
5651 if (WINED3D_OK != hr) {
5652 WARN("(%p) : Call to update surface failed\n", This);
5653 return hr;
5658 break;
5660 case WINED3DRTYPE_VOLUMETEXTURE:
5662 IWineD3DVolume *srcVolume = NULL;
5663 IWineD3DVolume *destVolume = NULL;
5665 for (i = 0 ; i < levels ; ++i) {
5666 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5667 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5668 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5669 IWineD3DVolume_Release(srcVolume);
5670 IWineD3DVolume_Release(destVolume);
5671 if (WINED3D_OK != hr) {
5672 WARN("(%p) : Call to update volume failed\n", This);
5673 return hr;
5677 break;
5679 default:
5680 FIXME("(%p) : Unsupported source and destination type\n", This);
5681 hr = WINED3DERR_INVALIDCALL;
5685 return hr;
5688 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5689 IWineD3DSwapChain *swapChain;
5690 HRESULT hr;
5691 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5692 if(hr == WINED3D_OK) {
5693 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5694 IWineD3DSwapChain_Release(swapChain);
5696 return hr;
5699 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5700 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5701 IWineD3DBaseTextureImpl *texture;
5702 const struct GlPixelFormatDesc *gl_info;
5703 DWORD i;
5705 TRACE("(%p) : %p\n", This, pNumPasses);
5707 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5708 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5709 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5710 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5712 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5713 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5714 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5717 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5718 if(!texture) continue;
5719 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5720 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5722 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5723 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5724 return E_FAIL;
5726 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5727 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5728 return E_FAIL;
5730 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5731 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5732 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5733 return E_FAIL;
5737 /* return a sensible default */
5738 *pNumPasses = 1;
5740 TRACE("returning D3D_OK\n");
5741 return WINED3D_OK;
5744 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5746 int i;
5748 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5749 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5750 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5751 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5756 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5758 int j;
5759 UINT NewSize;
5760 PALETTEENTRY **palettes;
5762 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5764 if (PaletteNumber >= MAX_PALETTES) {
5765 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5766 return WINED3DERR_INVALIDCALL;
5769 if (PaletteNumber >= This->NumberOfPalettes) {
5770 NewSize = This->NumberOfPalettes;
5771 do {
5772 NewSize *= 2;
5773 } while(PaletteNumber >= NewSize);
5774 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5775 if (!palettes) {
5776 ERR("Out of memory!\n");
5777 return E_OUTOFMEMORY;
5779 This->palettes = palettes;
5780 This->NumberOfPalettes = NewSize;
5783 if (!This->palettes[PaletteNumber]) {
5784 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5785 if (!This->palettes[PaletteNumber]) {
5786 ERR("Out of memory!\n");
5787 return E_OUTOFMEMORY;
5791 for (j = 0; j < 256; ++j) {
5792 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5793 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5794 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5795 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5797 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5798 TRACE("(%p) : returning\n", This);
5799 return WINED3D_OK;
5802 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5804 int j;
5805 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5806 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5807 /* What happens in such situation isn't documented; Native seems to silently abort
5808 on such conditions. Return Invalid Call. */
5809 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5810 return WINED3DERR_INVALIDCALL;
5812 for (j = 0; j < 256; ++j) {
5813 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5814 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5815 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5816 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5818 TRACE("(%p) : returning\n", This);
5819 return WINED3D_OK;
5822 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5824 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5825 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5826 (tested with reference rasterizer). Return Invalid Call. */
5827 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5828 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5829 return WINED3DERR_INVALIDCALL;
5831 /*TODO: stateblocks */
5832 if (This->currentPalette != PaletteNumber) {
5833 This->currentPalette = PaletteNumber;
5834 dirtify_p8_texture_samplers(This);
5836 TRACE("(%p) : returning\n", This);
5837 return WINED3D_OK;
5840 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5842 if (PaletteNumber == NULL) {
5843 WARN("(%p) : returning Invalid Call\n", This);
5844 return WINED3DERR_INVALIDCALL;
5846 /*TODO: stateblocks */
5847 *PaletteNumber = This->currentPalette;
5848 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5849 return WINED3D_OK;
5852 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5854 static BOOL warned;
5855 if (!warned)
5857 FIXME("(%p) : stub\n", This);
5858 warned = TRUE;
5861 This->softwareVertexProcessing = bSoftware;
5862 return WINED3D_OK;
5866 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5868 static BOOL warned;
5869 if (!warned)
5871 FIXME("(%p) : stub\n", This);
5872 warned = TRUE;
5874 return This->softwareVertexProcessing;
5878 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5880 IWineD3DSwapChain *swapChain;
5881 HRESULT hr;
5883 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5885 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5886 if(hr == WINED3D_OK){
5887 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5888 IWineD3DSwapChain_Release(swapChain);
5889 }else{
5890 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5892 return hr;
5896 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5898 static BOOL warned;
5899 if(nSegments != 0.0f) {
5900 if (!warned)
5902 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5903 warned = TRUE;
5906 return WINED3D_OK;
5909 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5911 static BOOL warned;
5912 if (!warned)
5914 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5915 warned = TRUE;
5917 return 0.0f;
5920 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5922 /** TODO: remove casts to IWineD3DSurfaceImpl
5923 * NOTE: move code to surface to accomplish this
5924 ****************************************/
5925 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5926 int srcWidth, srcHeight;
5927 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5928 WINED3DFORMAT destFormat, srcFormat;
5929 UINT destSize;
5930 int srcLeft, destLeft, destTop;
5931 WINED3DPOOL srcPool, destPool;
5932 int offset = 0;
5933 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5934 glDescriptor *glDescription = NULL;
5935 GLenum dummy;
5936 int sampler;
5937 int bpp;
5938 CONVERT_TYPES convert = NO_CONVERSION;
5940 WINED3DSURFACE_DESC winedesc;
5942 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5943 memset(&winedesc, 0, sizeof(winedesc));
5944 winedesc.Width = &srcSurfaceWidth;
5945 winedesc.Height = &srcSurfaceHeight;
5946 winedesc.Pool = &srcPool;
5947 winedesc.Format = &srcFormat;
5949 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5951 winedesc.Width = &destSurfaceWidth;
5952 winedesc.Height = &destSurfaceHeight;
5953 winedesc.Pool = &destPool;
5954 winedesc.Format = &destFormat;
5955 winedesc.Size = &destSize;
5957 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5959 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5960 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5961 return WINED3DERR_INVALIDCALL;
5964 /* This call loads the opengl surface directly, instead of copying the surface to the
5965 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5966 * copy in sysmem and use regular surface loading.
5968 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5969 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5970 if(convert != NO_CONVERSION) {
5971 return IWineD3DSurface_BltFast(pDestinationSurface,
5972 pDestPoint ? pDestPoint->x : 0,
5973 pDestPoint ? pDestPoint->y : 0,
5974 pSourceSurface, pSourceRect, 0);
5977 if (destFormat == WINED3DFMT_UNKNOWN) {
5978 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5979 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5981 /* Get the update surface description */
5982 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5985 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5987 ENTER_GL();
5988 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5989 checkGLcall("glActiveTextureARB");
5990 LEAVE_GL();
5992 /* Make sure the surface is loaded and up to date */
5993 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5994 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5996 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5998 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5999 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6000 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
6001 srcLeft = pSourceRect ? pSourceRect->left : 0;
6002 destLeft = pDestPoint ? pDestPoint->x : 0;
6003 destTop = pDestPoint ? pDestPoint->y : 0;
6006 /* This function doesn't support compressed textures
6007 the pitch is just bytesPerPixel * width */
6008 if(srcWidth != srcSurfaceWidth || srcLeft ){
6009 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
6010 offset += srcLeft * pSrcSurface->bytesPerPixel;
6011 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6013 /* TODO DXT formats */
6015 if(pSourceRect != NULL && pSourceRect->top != 0){
6016 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
6018 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
6019 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
6020 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
6022 /* Sanity check */
6023 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6025 /* need to lock the surface to get the data */
6026 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6029 ENTER_GL();
6031 /* TODO: Cube and volume support */
6032 if(rowoffset != 0){
6033 /* not a whole row so we have to do it a line at a time */
6034 int j;
6036 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
6037 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6039 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6041 glTexSubImage2D(glDescription->target
6042 ,glDescription->level
6043 ,destLeft
6045 ,srcWidth
6047 ,glDescription->glFormat
6048 ,glDescription->glType
6049 ,data /* could be quicker using */
6051 data += rowoffset;
6054 } else { /* Full width, so just write out the whole texture */
6055 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6057 if (WINED3DFMT_DXT1 == destFormat ||
6058 WINED3DFMT_DXT2 == destFormat ||
6059 WINED3DFMT_DXT3 == destFormat ||
6060 WINED3DFMT_DXT4 == destFormat ||
6061 WINED3DFMT_DXT5 == destFormat) {
6062 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6063 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6064 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6065 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6066 } if (destFormat != srcFormat) {
6067 FIXME("Updating mixed format compressed texture is not curretly support\n");
6068 } else {
6069 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6070 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
6072 } else {
6073 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6077 } else {
6078 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6079 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
6082 checkGLcall("glTexSubImage2D");
6084 LEAVE_GL();
6086 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6087 sampler = This->rev_tex_unit_map[0];
6088 if (sampler != -1) {
6089 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6092 return WINED3D_OK;
6095 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6097 struct WineD3DRectPatch *patch;
6098 unsigned int i;
6099 struct list *e;
6100 BOOL found;
6101 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6103 if(!(Handle || pRectPatchInfo)) {
6104 /* TODO: Write a test for the return value, thus the FIXME */
6105 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6106 return WINED3DERR_INVALIDCALL;
6109 if(Handle) {
6110 i = PATCHMAP_HASHFUNC(Handle);
6111 found = FALSE;
6112 LIST_FOR_EACH(e, &This->patches[i]) {
6113 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6114 if(patch->Handle == Handle) {
6115 found = TRUE;
6116 break;
6120 if(!found) {
6121 TRACE("Patch does not exist. Creating a new one\n");
6122 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6123 patch->Handle = Handle;
6124 list_add_head(&This->patches[i], &patch->entry);
6125 } else {
6126 TRACE("Found existing patch %p\n", patch);
6128 } else {
6129 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6130 * attributes we have to tesselate, read back, and draw. This needs a patch
6131 * management structure instance. Create one.
6133 * A possible improvement is to check if a vertex shader is used, and if not directly
6134 * draw the patch.
6136 FIXME("Drawing an uncached patch. This is slow\n");
6137 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6140 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6141 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6142 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6143 HRESULT hr;
6144 TRACE("Tesselation density or patch info changed, retesselating\n");
6146 if(pRectPatchInfo) {
6147 patch->RectPatchInfo = *pRectPatchInfo;
6149 patch->numSegs[0] = pNumSegs[0];
6150 patch->numSegs[1] = pNumSegs[1];
6151 patch->numSegs[2] = pNumSegs[2];
6152 patch->numSegs[3] = pNumSegs[3];
6154 hr = tesselate_rectpatch(This, patch);
6155 if(FAILED(hr)) {
6156 WARN("Patch tesselation failed\n");
6158 /* Do not release the handle to store the params of the patch */
6159 if(!Handle) {
6160 HeapFree(GetProcessHeap(), 0, patch);
6162 return hr;
6166 This->currentPatch = patch;
6167 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6168 This->currentPatch = NULL;
6170 /* Destroy uncached patches */
6171 if(!Handle) {
6172 HeapFree(GetProcessHeap(), 0, patch->mem);
6173 HeapFree(GetProcessHeap(), 0, patch);
6175 return WINED3D_OK;
6178 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6180 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6181 FIXME("(%p) : Stub\n", This);
6182 return WINED3D_OK;
6185 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6187 int i;
6188 struct WineD3DRectPatch *patch;
6189 struct list *e;
6190 TRACE("(%p) Handle(%d)\n", This, Handle);
6192 i = PATCHMAP_HASHFUNC(Handle);
6193 LIST_FOR_EACH(e, &This->patches[i]) {
6194 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6195 if(patch->Handle == Handle) {
6196 TRACE("Deleting patch %p\n", patch);
6197 list_remove(&patch->entry);
6198 HeapFree(GetProcessHeap(), 0, patch->mem);
6199 HeapFree(GetProcessHeap(), 0, patch);
6200 return WINED3D_OK;
6204 /* TODO: Write a test for the return value */
6205 FIXME("Attempt to destroy nonexistent patch\n");
6206 return WINED3DERR_INVALIDCALL;
6209 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6210 HRESULT hr;
6211 IWineD3DSwapChain *swapchain;
6213 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6214 if (SUCCEEDED(hr)) {
6215 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6216 return swapchain;
6219 return NULL;
6222 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6223 const WINED3DRECT *rect, const float color[4])
6225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6226 IWineD3DSwapChain *swapchain;
6228 swapchain = get_swapchain(surface);
6229 if (swapchain) {
6230 GLenum buffer;
6232 TRACE("Surface %p is onscreen\n", surface);
6234 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6235 ENTER_GL();
6236 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6237 buffer = surface_get_gl_buffer(surface, swapchain);
6238 glDrawBuffer(buffer);
6239 checkGLcall("glDrawBuffer()");
6240 } else {
6241 TRACE("Surface %p is offscreen\n", surface);
6243 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6244 ENTER_GL();
6245 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6246 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6247 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6248 checkGLcall("glFramebufferRenderbufferEXT");
6251 if (rect) {
6252 glEnable(GL_SCISSOR_TEST);
6253 if(!swapchain) {
6254 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6255 } else {
6256 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6257 rect->x2 - rect->x1, rect->y2 - rect->y1);
6259 checkGLcall("glScissor");
6260 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6261 } else {
6262 glDisable(GL_SCISSOR_TEST);
6264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6266 glDisable(GL_BLEND);
6267 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6269 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6270 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6272 glClearColor(color[0], color[1], color[2], color[3]);
6273 glClear(GL_COLOR_BUFFER_BIT);
6274 checkGLcall("glClear");
6276 if (This->activeContext->current_fbo) {
6277 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6278 } else {
6279 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6280 checkGLcall("glBindFramebuffer()");
6283 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6284 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6285 glDrawBuffer(GL_BACK);
6286 checkGLcall("glDrawBuffer()");
6289 LEAVE_GL();
6292 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6293 unsigned int r, g, b, a;
6294 DWORD ret;
6296 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6297 destfmt == WINED3DFMT_R8G8B8)
6298 return color;
6300 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6302 a = (color & 0xff000000) >> 24;
6303 r = (color & 0x00ff0000) >> 16;
6304 g = (color & 0x0000ff00) >> 8;
6305 b = (color & 0x000000ff) >> 0;
6307 switch(destfmt)
6309 case WINED3DFMT_R5G6B5:
6310 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6311 r = (r * 32) / 256;
6312 g = (g * 64) / 256;
6313 b = (b * 32) / 256;
6314 ret = r << 11;
6315 ret |= g << 5;
6316 ret |= b;
6317 TRACE("Returning %08x\n", ret);
6318 return ret;
6320 case WINED3DFMT_X1R5G5B5:
6321 case WINED3DFMT_A1R5G5B5:
6322 a = (a * 2) / 256;
6323 r = (r * 32) / 256;
6324 g = (g * 32) / 256;
6325 b = (b * 32) / 256;
6326 ret = a << 15;
6327 ret |= r << 10;
6328 ret |= g << 5;
6329 ret |= b << 0;
6330 TRACE("Returning %08x\n", ret);
6331 return ret;
6333 case WINED3DFMT_A8_UNORM:
6334 TRACE("Returning %08x\n", a);
6335 return a;
6337 case WINED3DFMT_X4R4G4B4:
6338 case WINED3DFMT_A4R4G4B4:
6339 a = (a * 16) / 256;
6340 r = (r * 16) / 256;
6341 g = (g * 16) / 256;
6342 b = (b * 16) / 256;
6343 ret = a << 12;
6344 ret |= r << 8;
6345 ret |= g << 4;
6346 ret |= b << 0;
6347 TRACE("Returning %08x\n", ret);
6348 return ret;
6350 case WINED3DFMT_R3G3B2:
6351 r = (r * 8) / 256;
6352 g = (g * 8) / 256;
6353 b = (b * 4) / 256;
6354 ret = r << 5;
6355 ret |= g << 2;
6356 ret |= b << 0;
6357 TRACE("Returning %08x\n", ret);
6358 return ret;
6360 case WINED3DFMT_X8B8G8R8:
6361 case WINED3DFMT_R8G8B8A8_UNORM:
6362 ret = a << 24;
6363 ret |= b << 16;
6364 ret |= g << 8;
6365 ret |= r << 0;
6366 TRACE("Returning %08x\n", ret);
6367 return ret;
6369 case WINED3DFMT_A2R10G10B10:
6370 a = (a * 4) / 256;
6371 r = (r * 1024) / 256;
6372 g = (g * 1024) / 256;
6373 b = (b * 1024) / 256;
6374 ret = a << 30;
6375 ret |= r << 20;
6376 ret |= g << 10;
6377 ret |= b << 0;
6378 TRACE("Returning %08x\n", ret);
6379 return ret;
6381 case WINED3DFMT_R10G10B10A2_UNORM:
6382 a = (a * 4) / 256;
6383 r = (r * 1024) / 256;
6384 g = (g * 1024) / 256;
6385 b = (b * 1024) / 256;
6386 ret = a << 30;
6387 ret |= b << 20;
6388 ret |= g << 10;
6389 ret |= r << 0;
6390 TRACE("Returning %08x\n", ret);
6391 return ret;
6393 default:
6394 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6395 return 0;
6399 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6401 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6402 WINEDDBLTFX BltFx;
6403 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6405 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6406 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6407 return WINED3DERR_INVALIDCALL;
6410 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6411 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6412 color_fill_fbo(iface, pSurface, pRect, c);
6413 return WINED3D_OK;
6414 } else {
6415 /* Just forward this to the DirectDraw blitting engine */
6416 memset(&BltFx, 0, sizeof(BltFx));
6417 BltFx.dwSize = sizeof(BltFx);
6418 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6419 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6420 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6424 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6425 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6427 IWineD3DResource *resource;
6428 IWineD3DSurface *surface;
6429 HRESULT hr;
6431 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6432 if (FAILED(hr))
6434 ERR("Failed to get resource, hr %#x\n", hr);
6435 return;
6438 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6440 FIXME("Only supported on surface resources\n");
6441 IWineD3DResource_Release(resource);
6442 return;
6445 surface = (IWineD3DSurface *)resource;
6447 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6449 color_fill_fbo(iface, surface, NULL, color);
6451 else
6453 WINEDDBLTFX BltFx;
6454 WINED3DCOLOR c;
6456 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6458 c = ((DWORD)(color[2] * 255.0));
6459 c |= ((DWORD)(color[1] * 255.0)) << 8;
6460 c |= ((DWORD)(color[0] * 255.0)) << 16;
6461 c |= ((DWORD)(color[3] * 255.0)) << 24;
6463 /* Just forward this to the DirectDraw blitting engine */
6464 memset(&BltFx, 0, sizeof(BltFx));
6465 BltFx.dwSize = sizeof(BltFx);
6466 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format);
6467 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6468 if (FAILED(hr))
6470 ERR("Blt failed, hr %#x\n", hr);
6474 IWineD3DResource_Release(resource);
6477 /* rendertarget and depth stencil functions */
6478 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6481 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6482 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6483 return WINED3DERR_INVALIDCALL;
6486 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6487 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6488 /* Note inc ref on returned surface */
6489 if(*ppRenderTarget != NULL)
6490 IWineD3DSurface_AddRef(*ppRenderTarget);
6491 return WINED3D_OK;
6494 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6496 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6497 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6498 IWineD3DSwapChainImpl *Swapchain;
6499 HRESULT hr;
6501 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6503 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6504 if(hr != WINED3D_OK) {
6505 ERR("Can't get the swapchain\n");
6506 return hr;
6509 /* Make sure to release the swapchain */
6510 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6512 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6513 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6514 return WINED3DERR_INVALIDCALL;
6516 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6517 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6518 return WINED3DERR_INVALIDCALL;
6521 if(Swapchain->frontBuffer != Front) {
6522 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6524 if(Swapchain->frontBuffer)
6525 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6526 Swapchain->frontBuffer = Front;
6528 if(Swapchain->frontBuffer) {
6529 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6533 if(Back && !Swapchain->backBuffer) {
6534 /* We need memory for the back buffer array - only one back buffer this way */
6535 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6536 if(!Swapchain->backBuffer) {
6537 ERR("Out of memory\n");
6538 return E_OUTOFMEMORY;
6542 if(Swapchain->backBuffer[0] != Back) {
6543 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6545 /* What to do about the context here in the case of multithreading? Not sure.
6546 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6548 ENTER_GL();
6549 if(!Swapchain->backBuffer[0]) {
6550 /* GL was told to draw to the front buffer at creation,
6551 * undo that
6553 glDrawBuffer(GL_BACK);
6554 checkGLcall("glDrawBuffer(GL_BACK)");
6555 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6556 Swapchain->presentParms.BackBufferCount = 1;
6557 } else if (!Back) {
6558 /* That makes problems - disable for now */
6559 /* glDrawBuffer(GL_FRONT); */
6560 checkGLcall("glDrawBuffer(GL_FRONT)");
6561 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6562 Swapchain->presentParms.BackBufferCount = 0;
6564 LEAVE_GL();
6566 if(Swapchain->backBuffer[0])
6567 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6568 Swapchain->backBuffer[0] = Back;
6570 if(Swapchain->backBuffer[0]) {
6571 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6572 } else {
6573 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6574 Swapchain->backBuffer = NULL;
6579 return WINED3D_OK;
6582 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6584 *ppZStencilSurface = This->stencilBufferTarget;
6585 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6587 if(*ppZStencilSurface != NULL) {
6588 /* Note inc ref on returned surface */
6589 IWineD3DSurface_AddRef(*ppZStencilSurface);
6590 return WINED3D_OK;
6591 } else {
6592 return WINED3DERR_NOTFOUND;
6596 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6597 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6600 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6601 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6602 GLenum gl_filter;
6603 POINT offset = {0, 0};
6605 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6606 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6607 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6608 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6610 switch (filter) {
6611 case WINED3DTEXF_LINEAR:
6612 gl_filter = GL_LINEAR;
6613 break;
6615 default:
6616 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6617 case WINED3DTEXF_NONE:
6618 case WINED3DTEXF_POINT:
6619 gl_filter = GL_NEAREST;
6620 break;
6623 /* Attach src surface to src fbo */
6624 src_swapchain = get_swapchain(src_surface);
6625 if (src_swapchain) {
6626 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6628 TRACE("Source surface %p is onscreen\n", src_surface);
6629 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6630 /* Make sure the drawable is up to date. In the offscreen case
6631 * attach_surface_fbo() implicitly takes care of this. */
6632 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6634 if(buffer == GL_FRONT) {
6635 RECT windowsize;
6636 UINT h;
6637 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6638 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6639 h = windowsize.bottom - windowsize.top;
6640 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6641 src_rect->y1 = offset.y + h - src_rect->y1;
6642 src_rect->y2 = offset.y + h - src_rect->y2;
6643 } else {
6644 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6645 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6648 ENTER_GL();
6649 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6650 glReadBuffer(buffer);
6651 checkGLcall("glReadBuffer()");
6652 } else {
6653 TRACE("Source surface %p is offscreen\n", src_surface);
6654 ENTER_GL();
6655 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6656 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6657 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6658 checkGLcall("glReadBuffer()");
6659 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6660 checkGLcall("glFramebufferRenderbufferEXT");
6662 LEAVE_GL();
6664 /* Attach dst surface to dst fbo */
6665 dst_swapchain = get_swapchain(dst_surface);
6666 if (dst_swapchain) {
6667 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6669 TRACE("Destination surface %p is onscreen\n", dst_surface);
6670 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6671 /* Make sure the drawable is up to date. In the offscreen case
6672 * attach_surface_fbo() implicitly takes care of this. */
6673 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6675 if(buffer == GL_FRONT) {
6676 RECT windowsize;
6677 UINT h;
6678 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6679 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6680 h = windowsize.bottom - windowsize.top;
6681 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6682 dst_rect->y1 = offset.y + h - dst_rect->y1;
6683 dst_rect->y2 = offset.y + h - dst_rect->y2;
6684 } else {
6685 /* Screen coords = window coords, surface height = window height */
6686 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6687 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6690 ENTER_GL();
6691 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6692 glDrawBuffer(buffer);
6693 checkGLcall("glDrawBuffer()");
6694 } else {
6695 TRACE("Destination surface %p is offscreen\n", dst_surface);
6697 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6698 if(!src_swapchain) {
6699 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6702 ENTER_GL();
6703 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6704 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6705 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6706 checkGLcall("glDrawBuffer()");
6707 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6708 checkGLcall("glFramebufferRenderbufferEXT");
6710 glDisable(GL_SCISSOR_TEST);
6711 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6713 if (flip) {
6714 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6715 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6716 checkGLcall("glBlitFramebuffer()");
6717 } else {
6718 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6719 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6720 checkGLcall("glBlitFramebuffer()");
6723 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6725 if (This->activeContext->current_fbo) {
6726 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6727 } else {
6728 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6729 checkGLcall("glBindFramebuffer()");
6732 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6733 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6734 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6735 glDrawBuffer(GL_BACK);
6736 checkGLcall("glDrawBuffer()");
6738 LEAVE_GL();
6741 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6743 WINED3DVIEWPORT viewport;
6745 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6747 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6748 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6749 This, RenderTargetIndex, GL_LIMITS(buffers));
6750 return WINED3DERR_INVALIDCALL;
6753 /* MSDN says that null disables the render target
6754 but a device must always be associated with a render target
6755 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6757 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6758 FIXME("Trying to set render target 0 to NULL\n");
6759 return WINED3DERR_INVALIDCALL;
6761 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6762 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);
6763 return WINED3DERR_INVALIDCALL;
6766 /* If we are trying to set what we already have, don't bother */
6767 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6768 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6769 return WINED3D_OK;
6771 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6772 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6773 This->render_targets[RenderTargetIndex] = pRenderTarget;
6775 /* Render target 0 is special */
6776 if(RenderTargetIndex == 0) {
6777 /* Finally, reset the viewport as the MSDN states. */
6778 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6779 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6780 viewport.X = 0;
6781 viewport.Y = 0;
6782 viewport.MaxZ = 1.0f;
6783 viewport.MinZ = 0.0f;
6784 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6785 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6786 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6788 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6790 return WINED3D_OK;
6793 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6795 HRESULT hr = WINED3D_OK;
6796 IWineD3DSurface *tmp;
6798 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6800 if (pNewZStencil == This->stencilBufferTarget) {
6801 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6802 } else {
6803 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6804 * depending on the renter target implementation being used.
6805 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6806 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6807 * stencil buffer and incur an extra memory overhead
6808 ******************************************************/
6810 if (This->stencilBufferTarget) {
6811 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6812 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6813 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6814 } else {
6815 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6816 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6817 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6821 tmp = This->stencilBufferTarget;
6822 This->stencilBufferTarget = pNewZStencil;
6823 /* should we be calling the parent or the wined3d surface? */
6824 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6825 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6826 hr = WINED3D_OK;
6828 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6829 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6830 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6831 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6832 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6836 return hr;
6839 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6840 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6842 /* TODO: the use of Impl is deprecated. */
6843 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6844 WINED3DLOCKED_RECT lockedRect;
6846 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6848 /* some basic validation checks */
6849 if(This->cursorTexture) {
6850 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6851 ENTER_GL();
6852 glDeleteTextures(1, &This->cursorTexture);
6853 LEAVE_GL();
6854 This->cursorTexture = 0;
6857 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6858 This->haveHardwareCursor = TRUE;
6859 else
6860 This->haveHardwareCursor = FALSE;
6862 if(pCursorBitmap) {
6863 WINED3DLOCKED_RECT rect;
6865 /* MSDN: Cursor must be A8R8G8B8 */
6866 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6867 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6868 return WINED3DERR_INVALIDCALL;
6871 /* MSDN: Cursor must be smaller than the display mode */
6872 if(pSur->currentDesc.Width > This->ddraw_width ||
6873 pSur->currentDesc.Height > This->ddraw_height) {
6874 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);
6875 return WINED3DERR_INVALIDCALL;
6878 if (!This->haveHardwareCursor) {
6879 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6881 /* Do not store the surface's pointer because the application may
6882 * release it after setting the cursor image. Windows doesn't
6883 * addref the set surface, so we can't do this either without
6884 * creating circular refcount dependencies. Copy out the gl texture
6885 * instead.
6887 This->cursorWidth = pSur->currentDesc.Width;
6888 This->cursorHeight = pSur->currentDesc.Height;
6889 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6891 const struct GlPixelFormatDesc *glDesc;
6892 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6893 char *mem, *bits = rect.pBits;
6894 GLint intfmt = glDesc->glInternal;
6895 GLint format = glDesc->glFormat;
6896 GLint type = glDesc->glType;
6897 INT height = This->cursorHeight;
6898 INT width = This->cursorWidth;
6899 INT bpp = tableEntry->bpp;
6900 INT i, sampler;
6902 /* Reformat the texture memory (pitch and width can be
6903 * different) */
6904 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6905 for(i = 0; i < height; i++)
6906 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6907 IWineD3DSurface_UnlockRect(pCursorBitmap);
6908 ENTER_GL();
6910 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6911 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6912 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6915 /* Make sure that a proper texture unit is selected */
6916 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6917 checkGLcall("glActiveTextureARB");
6918 sampler = This->rev_tex_unit_map[0];
6919 if (sampler != -1) {
6920 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6922 /* Create a new cursor texture */
6923 glGenTextures(1, &This->cursorTexture);
6924 checkGLcall("glGenTextures");
6925 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6926 checkGLcall("glBindTexture");
6927 /* Copy the bitmap memory into the cursor texture */
6928 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6929 HeapFree(GetProcessHeap(), 0, mem);
6930 checkGLcall("glTexImage2D");
6932 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6933 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6934 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6937 LEAVE_GL();
6939 else
6941 FIXME("A cursor texture was not returned.\n");
6942 This->cursorTexture = 0;
6945 else
6947 /* Draw a hardware cursor */
6948 ICONINFO cursorInfo;
6949 HCURSOR cursor;
6950 /* Create and clear maskBits because it is not needed for
6951 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6952 * chunks. */
6953 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6954 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6955 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6956 WINED3DLOCK_NO_DIRTY_UPDATE |
6957 WINED3DLOCK_READONLY
6959 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6960 pSur->currentDesc.Height);
6962 cursorInfo.fIcon = FALSE;
6963 cursorInfo.xHotspot = XHotSpot;
6964 cursorInfo.yHotspot = YHotSpot;
6965 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6966 pSur->currentDesc.Height, 1,
6967 1, &maskBits);
6968 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6969 pSur->currentDesc.Height, 1,
6970 32, lockedRect.pBits);
6971 IWineD3DSurface_UnlockRect(pCursorBitmap);
6972 /* Create our cursor and clean up. */
6973 cursor = CreateIconIndirect(&cursorInfo);
6974 SetCursor(cursor);
6975 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6976 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6977 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6978 This->hardwareCursor = cursor;
6979 HeapFree(GetProcessHeap(), 0, maskBits);
6983 This->xHotSpot = XHotSpot;
6984 This->yHotSpot = YHotSpot;
6985 return WINED3D_OK;
6988 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6990 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6992 This->xScreenSpace = XScreenSpace;
6993 This->yScreenSpace = YScreenSpace;
6995 return;
6999 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7001 BOOL oldVisible = This->bCursorVisible;
7002 POINT pt;
7004 TRACE("(%p) : visible(%d)\n", This, bShow);
7007 * When ShowCursor is first called it should make the cursor appear at the OS's last
7008 * known cursor position. Because of this, some applications just repetitively call
7009 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7011 GetCursorPos(&pt);
7012 This->xScreenSpace = pt.x;
7013 This->yScreenSpace = pt.y;
7015 if (This->haveHardwareCursor) {
7016 This->bCursorVisible = bShow;
7017 if (bShow)
7018 SetCursor(This->hardwareCursor);
7019 else
7020 SetCursor(NULL);
7022 else
7024 if (This->cursorTexture)
7025 This->bCursorVisible = bShow;
7028 return oldVisible;
7031 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7033 IWineD3DResourceImpl *resource;
7034 TRACE("(%p) : state (%u)\n", This, This->state);
7036 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7037 switch (This->state) {
7038 case WINED3D_OK:
7039 return WINED3D_OK;
7040 case WINED3DERR_DEVICELOST:
7042 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7043 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7044 return WINED3DERR_DEVICENOTRESET;
7046 return WINED3DERR_DEVICELOST;
7048 case WINED3DERR_DRIVERINTERNALERROR:
7049 return WINED3DERR_DRIVERINTERNALERROR;
7052 /* Unknown state */
7053 return WINED3DERR_DRIVERINTERNALERROR;
7057 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7058 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7059 /** FIXME: Resource tracking needs to be done,
7060 * The closes we can do to this is set the priorities of all managed textures low
7061 * and then reset them.
7062 ***********************************************************/
7063 FIXME("(%p) : stub\n", This);
7064 return WINED3D_OK;
7067 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
7069 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7071 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7072 if(surface->Flags & SFLAG_DIBSECTION) {
7073 /* Release the DC */
7074 SelectObject(surface->hDC, surface->dib.holdbitmap);
7075 DeleteDC(surface->hDC);
7076 /* Release the DIB section */
7077 DeleteObject(surface->dib.DIBsection);
7078 surface->dib.bitmap_data = NULL;
7079 surface->resource.allocatedMemory = NULL;
7080 surface->Flags &= ~SFLAG_DIBSECTION;
7082 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7083 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7084 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7085 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7086 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7087 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7088 } else {
7089 surface->pow2Width = surface->pow2Height = 1;
7090 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7091 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7093 surface->glRect.left = 0;
7094 surface->glRect.top = 0;
7095 surface->glRect.right = surface->pow2Width;
7096 surface->glRect.bottom = surface->pow2Height;
7098 if(surface->glDescription.textureName) {
7099 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7100 ENTER_GL();
7101 glDeleteTextures(1, &surface->glDescription.textureName);
7102 LEAVE_GL();
7103 surface->glDescription.textureName = 0;
7104 surface->Flags &= ~SFLAG_CLIENT;
7106 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7107 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7108 surface->Flags |= SFLAG_NONPOW2;
7109 } else {
7110 surface->Flags &= ~SFLAG_NONPOW2;
7112 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7113 surface->resource.allocatedMemory = NULL;
7114 surface->resource.heapMemory = NULL;
7115 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7116 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7117 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7118 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7119 } else {
7120 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7124 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7125 TRACE("Unloading resource %p\n", resource);
7126 IWineD3DResource_UnLoad(resource);
7127 IWineD3DResource_Release(resource);
7128 return S_OK;
7131 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7133 UINT i, count;
7134 WINED3DDISPLAYMODE m;
7135 HRESULT hr;
7137 /* All Windowed modes are supported, as is leaving the current mode */
7138 if(pp->Windowed) return TRUE;
7139 if(!pp->BackBufferWidth) return TRUE;
7140 if(!pp->BackBufferHeight) return TRUE;
7142 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7143 for(i = 0; i < count; i++) {
7144 memset(&m, 0, sizeof(m));
7145 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7146 if(FAILED(hr)) {
7147 ERR("EnumAdapterModes failed\n");
7149 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7150 /* Mode found, it is supported */
7151 return TRUE;
7154 /* Mode not found -> not supported */
7155 return FALSE;
7158 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7160 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7161 UINT i;
7162 IWineD3DBaseShaderImpl *shader;
7164 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7165 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7166 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7169 ENTER_GL();
7170 if(This->depth_blt_texture) {
7171 glDeleteTextures(1, &This->depth_blt_texture);
7172 This->depth_blt_texture = 0;
7174 if (This->depth_blt_rb) {
7175 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7176 This->depth_blt_rb = 0;
7177 This->depth_blt_rb_w = 0;
7178 This->depth_blt_rb_h = 0;
7180 LEAVE_GL();
7182 This->blitter->free_private(iface);
7183 This->frag_pipe->free_private(iface);
7184 This->shader_backend->shader_free_private(iface);
7186 ENTER_GL();
7187 for (i = 0; i < GL_LIMITS(textures); i++) {
7188 /* Textures are recreated below */
7189 glDeleteTextures(1, &This->dummyTextureName[i]);
7190 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7191 This->dummyTextureName[i] = 0;
7193 LEAVE_GL();
7195 while(This->numContexts) {
7196 DestroyContext(This, This->contexts[0]);
7198 This->activeContext = NULL;
7199 HeapFree(GetProcessHeap(), 0, swapchain->context);
7200 swapchain->context = NULL;
7201 swapchain->num_contexts = 0;
7204 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7206 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7207 HRESULT hr;
7208 IWineD3DSurfaceImpl *target;
7210 /* Recreate the primary swapchain's context */
7211 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7212 if(swapchain->backBuffer) {
7213 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7214 } else {
7215 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7217 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7218 &swapchain->presentParms);
7219 swapchain->num_contexts = 1;
7220 This->activeContext = swapchain->context[0];
7222 create_dummy_textures(This);
7224 hr = This->shader_backend->shader_alloc_private(iface);
7225 if(FAILED(hr)) {
7226 ERR("Failed to recreate shader private data\n");
7227 goto err_out;
7229 hr = This->frag_pipe->alloc_private(iface);
7230 if(FAILED(hr)) {
7231 TRACE("Fragment pipeline private data couldn't be allocated\n");
7232 goto err_out;
7234 hr = This->blitter->alloc_private(iface);
7235 if(FAILED(hr)) {
7236 TRACE("Blitter private data couldn't be allocated\n");
7237 goto err_out;
7240 return WINED3D_OK;
7242 err_out:
7243 This->blitter->free_private(iface);
7244 This->frag_pipe->free_private(iface);
7245 This->shader_backend->shader_free_private(iface);
7246 return hr;
7249 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7251 IWineD3DSwapChainImpl *swapchain;
7252 HRESULT hr;
7253 BOOL DisplayModeChanged = FALSE;
7254 WINED3DDISPLAYMODE mode;
7255 TRACE("(%p)\n", This);
7257 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7258 if(FAILED(hr)) {
7259 ERR("Failed to get the first implicit swapchain\n");
7260 return hr;
7263 if(!is_display_mode_supported(This, pPresentationParameters)) {
7264 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7265 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7266 pPresentationParameters->BackBufferHeight);
7267 return WINED3DERR_INVALIDCALL;
7270 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7271 * on an existing gl context, so there's no real need for recreation.
7273 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7275 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7277 TRACE("New params:\n");
7278 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7279 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7280 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7281 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7282 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7283 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7284 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7285 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7286 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7287 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7288 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7289 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7290 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7292 /* No special treatment of these parameters. Just store them */
7293 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7294 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7295 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7296 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7298 /* What to do about these? */
7299 if(pPresentationParameters->BackBufferCount != 0 &&
7300 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7301 ERR("Cannot change the back buffer count yet\n");
7303 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7304 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7305 ERR("Cannot change the back buffer format yet\n");
7307 if(pPresentationParameters->hDeviceWindow != NULL &&
7308 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7309 ERR("Cannot change the device window yet\n");
7311 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7312 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7313 return WINED3DERR_INVALIDCALL;
7316 /* Reset the depth stencil */
7317 if (pPresentationParameters->EnableAutoDepthStencil)
7318 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7319 else
7320 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7322 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7324 if(pPresentationParameters->Windowed) {
7325 mode.Width = swapchain->orig_width;
7326 mode.Height = swapchain->orig_height;
7327 mode.RefreshRate = 0;
7328 mode.Format = swapchain->presentParms.BackBufferFormat;
7329 } else {
7330 mode.Width = pPresentationParameters->BackBufferWidth;
7331 mode.Height = pPresentationParameters->BackBufferHeight;
7332 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7333 mode.Format = swapchain->presentParms.BackBufferFormat;
7336 /* Should Width == 800 && Height == 0 set 800x600? */
7337 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7338 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7339 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7341 UINT i;
7343 if(!pPresentationParameters->Windowed) {
7344 DisplayModeChanged = TRUE;
7346 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7347 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7349 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7350 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7351 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7353 if(This->auto_depth_stencil_buffer) {
7354 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7358 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7359 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7360 DisplayModeChanged) {
7362 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7364 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7365 if(swapchain->presentParms.Windowed) {
7366 /* switch from windowed to fs */
7367 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7368 pPresentationParameters->BackBufferWidth,
7369 pPresentationParameters->BackBufferHeight);
7370 } else {
7371 /* Fullscreen -> fullscreen mode change */
7372 MoveWindow(swapchain->win_handle, 0, 0,
7373 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7374 TRUE);
7376 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7377 /* Fullscreen -> windowed switch */
7378 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7380 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7381 } else if(!pPresentationParameters->Windowed) {
7382 DWORD style = This->style, exStyle = This->exStyle;
7383 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7384 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7385 * Reset to clear up their mess. Guild Wars also loses the device during that.
7387 This->style = 0;
7388 This->exStyle = 0;
7389 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7390 pPresentationParameters->BackBufferWidth,
7391 pPresentationParameters->BackBufferHeight);
7392 This->style = style;
7393 This->exStyle = exStyle;
7396 TRACE("Resetting stateblock\n");
7397 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7398 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7400 /* Note: No parent needed for initial internal stateblock */
7401 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7402 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7403 else TRACE("Created stateblock %p\n", This->stateBlock);
7404 This->updateStateBlock = This->stateBlock;
7405 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7407 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7408 if(FAILED(hr)) {
7409 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7412 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7413 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7415 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7416 * first use
7418 return hr;
7421 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7423 /** FIXME: always true at the moment **/
7424 if(!bEnableDialogs) {
7425 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7427 return WINED3D_OK;
7431 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7433 TRACE("(%p) : pParameters %p\n", This, pParameters);
7435 *pParameters = This->createParms;
7436 return WINED3D_OK;
7439 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7440 IWineD3DSwapChain *swapchain;
7442 TRACE("Relaying to swapchain\n");
7444 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7445 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7446 IWineD3DSwapChain_Release(swapchain);
7448 return;
7451 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7452 IWineD3DSwapChain *swapchain;
7454 TRACE("Relaying to swapchain\n");
7456 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7457 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7458 IWineD3DSwapChain_Release(swapchain);
7460 return;
7464 /** ********************************************************
7465 * Notification functions
7466 ** ********************************************************/
7467 /** This function must be called in the release of a resource when ref == 0,
7468 * the contents of resource must still be correct,
7469 * any handles to other resource held by the caller must be closed
7470 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7471 *****************************************************/
7472 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7475 TRACE("(%p) : Adding Resource %p\n", This, resource);
7476 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7479 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7482 TRACE("(%p) : Removing resource %p\n", This, resource);
7484 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7488 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7490 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7491 int counter;
7493 TRACE("(%p) : resource %p\n", This, resource);
7495 context_resource_released(iface, resource, type);
7497 switch (type) {
7498 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7499 case WINED3DRTYPE_SURFACE: {
7500 unsigned int i;
7502 /* Cleanup any FBO attachments if d3d is enabled */
7503 if(This->d3d_initialized) {
7504 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7505 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7507 TRACE("Last active render target destroyed\n");
7508 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7509 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7510 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7511 * and the lastActiveRenderTarget member shouldn't matter
7513 if(swapchain) {
7514 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7515 TRACE("Activating primary back buffer\n");
7516 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7517 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7518 /* Single buffering environment */
7519 TRACE("Activating primary front buffer\n");
7520 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7521 } else {
7522 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7523 /* Implicit render target destroyed, that means the device is being destroyed
7524 * whatever we set here, it shouldn't matter
7526 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7528 } else {
7529 /* May happen during ddraw uninitialization */
7530 TRACE("Render target set, but swapchain does not exist!\n");
7531 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7535 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7536 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7537 This->render_targets[i] = NULL;
7540 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7541 This->stencilBufferTarget = NULL;
7545 break;
7547 case WINED3DRTYPE_TEXTURE:
7548 case WINED3DRTYPE_CUBETEXTURE:
7549 case WINED3DRTYPE_VOLUMETEXTURE:
7550 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7551 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7552 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7553 This->stateBlock->textures[counter] = NULL;
7555 if (This->updateStateBlock != This->stateBlock ){
7556 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7557 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7558 This->updateStateBlock->textures[counter] = NULL;
7562 break;
7563 case WINED3DRTYPE_VOLUME:
7564 /* TODO: nothing really? */
7565 break;
7566 case WINED3DRTYPE_VERTEXBUFFER:
7568 int streamNumber;
7569 TRACE("Cleaning up stream pointers\n");
7571 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7572 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7573 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7575 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7576 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7577 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7578 This->updateStateBlock->streamSource[streamNumber] = 0;
7579 /* Set changed flag? */
7582 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) */
7583 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7584 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7585 This->stateBlock->streamSource[streamNumber] = 0;
7590 break;
7591 case WINED3DRTYPE_INDEXBUFFER:
7592 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7593 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7594 This->updateStateBlock->pIndexData = NULL;
7597 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7598 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7599 This->stateBlock->pIndexData = NULL;
7602 break;
7604 case WINED3DRTYPE_BUFFER:
7605 /* Nothing to do, yet.*/
7606 break;
7608 default:
7609 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7610 break;
7614 /* Remove the resource from the resourceStore */
7615 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7617 TRACE("Resource released\n");
7621 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7623 IWineD3DResourceImpl *resource, *cursor;
7624 HRESULT ret;
7625 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7627 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7628 TRACE("enumerating resource %p\n", resource);
7629 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7630 ret = pCallback((IWineD3DResource *) resource, pData);
7631 if(ret == S_FALSE) {
7632 TRACE("Canceling enumeration\n");
7633 break;
7636 return WINED3D_OK;
7639 /**********************************************************
7640 * IWineD3DDevice VTbl follows
7641 **********************************************************/
7643 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7645 /*** IUnknown methods ***/
7646 IWineD3DDeviceImpl_QueryInterface,
7647 IWineD3DDeviceImpl_AddRef,
7648 IWineD3DDeviceImpl_Release,
7649 /*** IWineD3DDevice methods ***/
7650 IWineD3DDeviceImpl_GetParent,
7651 /*** Creation methods**/
7652 IWineD3DDeviceImpl_CreateBuffer,
7653 IWineD3DDeviceImpl_CreateVertexBuffer,
7654 IWineD3DDeviceImpl_CreateIndexBuffer,
7655 IWineD3DDeviceImpl_CreateStateBlock,
7656 IWineD3DDeviceImpl_CreateSurface,
7657 IWineD3DDeviceImpl_CreateRendertargetView,
7658 IWineD3DDeviceImpl_CreateTexture,
7659 IWineD3DDeviceImpl_CreateVolumeTexture,
7660 IWineD3DDeviceImpl_CreateVolume,
7661 IWineD3DDeviceImpl_CreateCubeTexture,
7662 IWineD3DDeviceImpl_CreateQuery,
7663 IWineD3DDeviceImpl_CreateSwapChain,
7664 IWineD3DDeviceImpl_CreateVertexDeclaration,
7665 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7666 IWineD3DDeviceImpl_CreateVertexShader,
7667 IWineD3DDeviceImpl_CreatePixelShader,
7668 IWineD3DDeviceImpl_CreatePalette,
7669 /*** Odd functions **/
7670 IWineD3DDeviceImpl_Init3D,
7671 IWineD3DDeviceImpl_InitGDI,
7672 IWineD3DDeviceImpl_Uninit3D,
7673 IWineD3DDeviceImpl_UninitGDI,
7674 IWineD3DDeviceImpl_SetMultithreaded,
7675 IWineD3DDeviceImpl_EvictManagedResources,
7676 IWineD3DDeviceImpl_GetAvailableTextureMem,
7677 IWineD3DDeviceImpl_GetBackBuffer,
7678 IWineD3DDeviceImpl_GetCreationParameters,
7679 IWineD3DDeviceImpl_GetDeviceCaps,
7680 IWineD3DDeviceImpl_GetDirect3D,
7681 IWineD3DDeviceImpl_GetDisplayMode,
7682 IWineD3DDeviceImpl_SetDisplayMode,
7683 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7684 IWineD3DDeviceImpl_GetRasterStatus,
7685 IWineD3DDeviceImpl_GetSwapChain,
7686 IWineD3DDeviceImpl_Reset,
7687 IWineD3DDeviceImpl_SetDialogBoxMode,
7688 IWineD3DDeviceImpl_SetCursorProperties,
7689 IWineD3DDeviceImpl_SetCursorPosition,
7690 IWineD3DDeviceImpl_ShowCursor,
7691 IWineD3DDeviceImpl_TestCooperativeLevel,
7692 /*** Getters and setters **/
7693 IWineD3DDeviceImpl_SetClipPlane,
7694 IWineD3DDeviceImpl_GetClipPlane,
7695 IWineD3DDeviceImpl_SetClipStatus,
7696 IWineD3DDeviceImpl_GetClipStatus,
7697 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7698 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7699 IWineD3DDeviceImpl_SetDepthStencilSurface,
7700 IWineD3DDeviceImpl_GetDepthStencilSurface,
7701 IWineD3DDeviceImpl_SetGammaRamp,
7702 IWineD3DDeviceImpl_GetGammaRamp,
7703 IWineD3DDeviceImpl_SetIndices,
7704 IWineD3DDeviceImpl_GetIndices,
7705 IWineD3DDeviceImpl_SetBaseVertexIndex,
7706 IWineD3DDeviceImpl_GetBaseVertexIndex,
7707 IWineD3DDeviceImpl_SetLight,
7708 IWineD3DDeviceImpl_GetLight,
7709 IWineD3DDeviceImpl_SetLightEnable,
7710 IWineD3DDeviceImpl_GetLightEnable,
7711 IWineD3DDeviceImpl_SetMaterial,
7712 IWineD3DDeviceImpl_GetMaterial,
7713 IWineD3DDeviceImpl_SetNPatchMode,
7714 IWineD3DDeviceImpl_GetNPatchMode,
7715 IWineD3DDeviceImpl_SetPaletteEntries,
7716 IWineD3DDeviceImpl_GetPaletteEntries,
7717 IWineD3DDeviceImpl_SetPixelShader,
7718 IWineD3DDeviceImpl_GetPixelShader,
7719 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7720 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7721 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7722 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7723 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7724 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7725 IWineD3DDeviceImpl_SetRenderState,
7726 IWineD3DDeviceImpl_GetRenderState,
7727 IWineD3DDeviceImpl_SetRenderTarget,
7728 IWineD3DDeviceImpl_GetRenderTarget,
7729 IWineD3DDeviceImpl_SetFrontBackBuffers,
7730 IWineD3DDeviceImpl_SetSamplerState,
7731 IWineD3DDeviceImpl_GetSamplerState,
7732 IWineD3DDeviceImpl_SetScissorRect,
7733 IWineD3DDeviceImpl_GetScissorRect,
7734 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7735 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7736 IWineD3DDeviceImpl_SetStreamSource,
7737 IWineD3DDeviceImpl_GetStreamSource,
7738 IWineD3DDeviceImpl_SetStreamSourceFreq,
7739 IWineD3DDeviceImpl_GetStreamSourceFreq,
7740 IWineD3DDeviceImpl_SetTexture,
7741 IWineD3DDeviceImpl_GetTexture,
7742 IWineD3DDeviceImpl_SetTextureStageState,
7743 IWineD3DDeviceImpl_GetTextureStageState,
7744 IWineD3DDeviceImpl_SetTransform,
7745 IWineD3DDeviceImpl_GetTransform,
7746 IWineD3DDeviceImpl_SetVertexDeclaration,
7747 IWineD3DDeviceImpl_GetVertexDeclaration,
7748 IWineD3DDeviceImpl_SetVertexShader,
7749 IWineD3DDeviceImpl_GetVertexShader,
7750 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7751 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7752 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7753 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7754 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7755 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7756 IWineD3DDeviceImpl_SetViewport,
7757 IWineD3DDeviceImpl_GetViewport,
7758 IWineD3DDeviceImpl_MultiplyTransform,
7759 IWineD3DDeviceImpl_ValidateDevice,
7760 IWineD3DDeviceImpl_ProcessVertices,
7761 /*** State block ***/
7762 IWineD3DDeviceImpl_BeginStateBlock,
7763 IWineD3DDeviceImpl_EndStateBlock,
7764 /*** Scene management ***/
7765 IWineD3DDeviceImpl_BeginScene,
7766 IWineD3DDeviceImpl_EndScene,
7767 IWineD3DDeviceImpl_Present,
7768 IWineD3DDeviceImpl_Clear,
7769 IWineD3DDeviceImpl_ClearRendertargetView,
7770 /*** Drawing ***/
7771 IWineD3DDeviceImpl_DrawPrimitive,
7772 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7773 IWineD3DDeviceImpl_DrawPrimitiveUP,
7774 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7775 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7776 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7777 IWineD3DDeviceImpl_DrawRectPatch,
7778 IWineD3DDeviceImpl_DrawTriPatch,
7779 IWineD3DDeviceImpl_DeletePatch,
7780 IWineD3DDeviceImpl_ColorFill,
7781 IWineD3DDeviceImpl_UpdateTexture,
7782 IWineD3DDeviceImpl_UpdateSurface,
7783 IWineD3DDeviceImpl_GetFrontBufferData,
7784 /*** object tracking ***/
7785 IWineD3DDeviceImpl_ResourceReleased,
7786 IWineD3DDeviceImpl_EnumResources
7789 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7790 WINED3DRS_ALPHABLENDENABLE ,
7791 WINED3DRS_ALPHAFUNC ,
7792 WINED3DRS_ALPHAREF ,
7793 WINED3DRS_ALPHATESTENABLE ,
7794 WINED3DRS_BLENDOP ,
7795 WINED3DRS_COLORWRITEENABLE ,
7796 WINED3DRS_DESTBLEND ,
7797 WINED3DRS_DITHERENABLE ,
7798 WINED3DRS_FILLMODE ,
7799 WINED3DRS_FOGDENSITY ,
7800 WINED3DRS_FOGEND ,
7801 WINED3DRS_FOGSTART ,
7802 WINED3DRS_LASTPIXEL ,
7803 WINED3DRS_SHADEMODE ,
7804 WINED3DRS_SRCBLEND ,
7805 WINED3DRS_STENCILENABLE ,
7806 WINED3DRS_STENCILFAIL ,
7807 WINED3DRS_STENCILFUNC ,
7808 WINED3DRS_STENCILMASK ,
7809 WINED3DRS_STENCILPASS ,
7810 WINED3DRS_STENCILREF ,
7811 WINED3DRS_STENCILWRITEMASK ,
7812 WINED3DRS_STENCILZFAIL ,
7813 WINED3DRS_TEXTUREFACTOR ,
7814 WINED3DRS_WRAP0 ,
7815 WINED3DRS_WRAP1 ,
7816 WINED3DRS_WRAP2 ,
7817 WINED3DRS_WRAP3 ,
7818 WINED3DRS_WRAP4 ,
7819 WINED3DRS_WRAP5 ,
7820 WINED3DRS_WRAP6 ,
7821 WINED3DRS_WRAP7 ,
7822 WINED3DRS_ZENABLE ,
7823 WINED3DRS_ZFUNC ,
7824 WINED3DRS_ZWRITEENABLE
7827 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7828 WINED3DTSS_ALPHAARG0 ,
7829 WINED3DTSS_ALPHAARG1 ,
7830 WINED3DTSS_ALPHAARG2 ,
7831 WINED3DTSS_ALPHAOP ,
7832 WINED3DTSS_BUMPENVLOFFSET ,
7833 WINED3DTSS_BUMPENVLSCALE ,
7834 WINED3DTSS_BUMPENVMAT00 ,
7835 WINED3DTSS_BUMPENVMAT01 ,
7836 WINED3DTSS_BUMPENVMAT10 ,
7837 WINED3DTSS_BUMPENVMAT11 ,
7838 WINED3DTSS_COLORARG0 ,
7839 WINED3DTSS_COLORARG1 ,
7840 WINED3DTSS_COLORARG2 ,
7841 WINED3DTSS_COLOROP ,
7842 WINED3DTSS_RESULTARG ,
7843 WINED3DTSS_TEXCOORDINDEX ,
7844 WINED3DTSS_TEXTURETRANSFORMFLAGS
7847 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7848 WINED3DSAMP_ADDRESSU ,
7849 WINED3DSAMP_ADDRESSV ,
7850 WINED3DSAMP_ADDRESSW ,
7851 WINED3DSAMP_BORDERCOLOR ,
7852 WINED3DSAMP_MAGFILTER ,
7853 WINED3DSAMP_MINFILTER ,
7854 WINED3DSAMP_MIPFILTER ,
7855 WINED3DSAMP_MIPMAPLODBIAS ,
7856 WINED3DSAMP_MAXMIPLEVEL ,
7857 WINED3DSAMP_MAXANISOTROPY ,
7858 WINED3DSAMP_SRGBTEXTURE ,
7859 WINED3DSAMP_ELEMENTINDEX
7862 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7863 WINED3DRS_AMBIENT ,
7864 WINED3DRS_AMBIENTMATERIALSOURCE ,
7865 WINED3DRS_CLIPPING ,
7866 WINED3DRS_CLIPPLANEENABLE ,
7867 WINED3DRS_COLORVERTEX ,
7868 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7869 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7870 WINED3DRS_FOGDENSITY ,
7871 WINED3DRS_FOGEND ,
7872 WINED3DRS_FOGSTART ,
7873 WINED3DRS_FOGTABLEMODE ,
7874 WINED3DRS_FOGVERTEXMODE ,
7875 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7876 WINED3DRS_LIGHTING ,
7877 WINED3DRS_LOCALVIEWER ,
7878 WINED3DRS_MULTISAMPLEANTIALIAS ,
7879 WINED3DRS_MULTISAMPLEMASK ,
7880 WINED3DRS_NORMALIZENORMALS ,
7881 WINED3DRS_PATCHEDGESTYLE ,
7882 WINED3DRS_POINTSCALE_A ,
7883 WINED3DRS_POINTSCALE_B ,
7884 WINED3DRS_POINTSCALE_C ,
7885 WINED3DRS_POINTSCALEENABLE ,
7886 WINED3DRS_POINTSIZE ,
7887 WINED3DRS_POINTSIZE_MAX ,
7888 WINED3DRS_POINTSIZE_MIN ,
7889 WINED3DRS_POINTSPRITEENABLE ,
7890 WINED3DRS_RANGEFOGENABLE ,
7891 WINED3DRS_SPECULARMATERIALSOURCE ,
7892 WINED3DRS_TWEENFACTOR ,
7893 WINED3DRS_VERTEXBLEND ,
7894 WINED3DRS_CULLMODE ,
7895 WINED3DRS_FOGCOLOR
7898 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7899 WINED3DTSS_TEXCOORDINDEX ,
7900 WINED3DTSS_TEXTURETRANSFORMFLAGS
7903 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7904 WINED3DSAMP_DMAPOFFSET
7907 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7908 DWORD rep = This->StateTable[state].representative;
7909 DWORD idx;
7910 BYTE shift;
7911 UINT i;
7912 WineD3DContext *context;
7914 if(!rep) return;
7915 for(i = 0; i < This->numContexts; i++) {
7916 context = This->contexts[i];
7917 if(isStateDirty(context, rep)) continue;
7919 context->dirtyArray[context->numDirtyEntries++] = rep;
7920 idx = rep >> 5;
7921 shift = rep & 0x1f;
7922 context->isStateDirty[idx] |= (1 << shift);
7926 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7927 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7928 /* The drawable size of a pbuffer render target is the current pbuffer size
7930 *width = dev->pbufferWidth;
7931 *height = dev->pbufferHeight;
7934 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7935 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7937 *width = This->pow2Width;
7938 *height = This->pow2Height;
7941 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7942 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7943 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7944 * current context's drawable, which is the size of the back buffer of the swapchain
7945 * the active context belongs to. The back buffer of the swapchain is stored as the
7946 * surface the context belongs to.
7948 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7949 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;