2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
54 /* static function declarations */
55 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
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 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
63 * actually have the same values in GL and D3D. */
64 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
66 switch(primitive_type)
68 case WINED3DPT_POINTLIST:
71 case WINED3DPT_LINELIST:
74 case WINED3DPT_LINESTRIP:
77 case WINED3DPT_TRIANGLELIST:
80 case WINED3DPT_TRIANGLESTRIP:
81 return GL_TRIANGLE_STRIP;
83 case WINED3DPT_TRIANGLEFAN:
84 return GL_TRIANGLE_FAN;
86 case WINED3DPT_LINELIST_ADJ:
87 return GL_LINES_ADJACENCY_ARB;
89 case WINED3DPT_LINESTRIP_ADJ:
90 return GL_LINE_STRIP_ADJACENCY_ARB;
92 case WINED3DPT_TRIANGLELIST_ADJ:
93 return GL_TRIANGLES_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLESTRIP_ADJ:
96 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
99 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
104 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
106 switch(primitive_type)
109 return WINED3DPT_POINTLIST;
112 return WINED3DPT_LINELIST;
115 return WINED3DPT_LINESTRIP;
118 return WINED3DPT_TRIANGLELIST;
120 case GL_TRIANGLE_STRIP:
121 return WINED3DPT_TRIANGLESTRIP;
123 case GL_TRIANGLE_FAN:
124 return WINED3DPT_TRIANGLEFAN;
126 case GL_LINES_ADJACENCY_ARB:
127 return WINED3DPT_LINELIST_ADJ;
129 case GL_LINE_STRIP_ADJACENCY_ARB:
130 return WINED3DPT_LINESTRIP_ADJ;
132 case GL_TRIANGLES_ADJACENCY_ARB:
133 return WINED3DPT_TRIANGLELIST_ADJ;
135 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLESTRIP_ADJ;
139 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
140 return WINED3DPT_UNDEFINED;
145 /**********************************************************
146 * IUnknown parts follows
147 **********************************************************/
149 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
154 if (IsEqualGUID(riid, &IID_IUnknown)
155 || IsEqualGUID(riid, &IID_IWineD3DBase)
156 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
157 IUnknown_AddRef(iface);
162 return E_NOINTERFACE;
165 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
167 ULONG refCount = InterlockedIncrement(&This->ref);
169 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
173 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
175 ULONG refCount = InterlockedDecrement(&This->ref);
177 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
182 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
183 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
184 This->multistate_funcs[i] = NULL;
187 /* TODO: Clean up all the surfaces and textures! */
188 /* NOTE: You must release the parent if the object was created via a callback
189 ** ***************************/
191 if (!list_empty(&This->resources)) {
192 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
193 dumpResources(&This->resources);
196 if(This->contexts) ERR("Context array not freed!\n");
197 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
198 This->haveHardwareCursor = FALSE;
200 IWineD3D_Release(This->wineD3D);
201 This->wineD3D = NULL;
202 HeapFree(GetProcessHeap(), 0, This);
203 TRACE("Freed device %p\n", This);
209 /**********************************************************
210 * IWineD3DDevice implementation follows
211 **********************************************************/
212 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
214 *pParent = This->parent;
215 IUnknown_AddRef(This->parent);
219 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface,
220 struct wined3d_buffer_desc *desc, IUnknown *parent, IWineD3DBuffer **buffer)
222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
223 struct wined3d_buffer *object;
226 TRACE("iface %p, desc %p, parent %p, buffer %p\n", iface, desc, parent, buffer);
228 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
231 ERR("Failed to allocate memory\n");
232 return E_OUTOFMEMORY;
235 object->vtbl = &wined3d_buffer_vtbl;
236 object->desc = *desc;
238 FIXME("Ignoring access flags (pool)\n");
240 hr = resource_init(&object->resource, WINED3DRTYPE_BUFFER, This, desc->byte_width,
241 desc->usage, WINED3DFMT_UNKNOWN, WINED3DPOOL_MANAGED, parent);
244 WARN("Failed to initialize resource, returning %#x\n", hr);
245 HeapFree(GetProcessHeap(), 0, object);
249 TRACE("Created resource %p\n", object);
251 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
253 TRACE("size %#x, usage=%#x, format %s, memory @ %p, iface @ %p\n", object->resource.size, object->resource.usage,
254 debug_d3dformat(object->resource.format_desc->format), object->resource.allocatedMemory, object);
256 *buffer = (IWineD3DBuffer *)object;
261 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
262 DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer, HANDLE *sharedHandle, IUnknown *parent)
264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
265 /* Dummy format for now */
266 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_VERTEXDATA, &This->adapter->gl_info);
267 struct wined3d_buffer *object;
268 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
273 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
274 *ppVertexBuffer = NULL;
275 return WINED3DERR_INVALIDCALL;
276 } else if(Pool == WINED3DPOOL_SCRATCH) {
277 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
278 * anyway, SCRATCH vertex buffers aren't usable anywhere
280 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
281 *ppVertexBuffer = NULL;
282 return WINED3DERR_INVALIDCALL;
285 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
288 ERR("Out of memory\n");
289 *ppVertexBuffer = NULL;
290 return WINED3DERR_OUTOFVIDEOMEMORY;
293 object->vtbl = &wined3d_buffer_vtbl;
294 hr = resource_init(&object->resource, WINED3DRTYPE_VERTEXBUFFER, This, Size, Usage, format_desc, Pool, parent);
297 WARN("Failed to initialize resource, returning %#x\n", hr);
298 HeapFree(GetProcessHeap(), 0, object);
299 *ppVertexBuffer = NULL;
303 TRACE("(%p) : Created resource %p\n", This, object);
305 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
307 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);
308 *ppVertexBuffer = (IWineD3DBuffer *)object;
312 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
313 * drawStridedFast (half-life 2).
315 * Basically converting the vertices in the buffer is quite expensive, and observations
316 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
317 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
319 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
320 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
321 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
322 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
324 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
325 * more. In this call we can convert dx7 buffers too.
327 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
328 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
329 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
330 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
331 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
332 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
333 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
334 } else if(dxVersion <= 7 && conv) {
335 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
337 object->flags |= WINED3D_BUFFER_CREATEBO;
342 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
343 GLenum error, glUsage;
344 TRACE("Creating VBO for Index Buffer %p\n", object);
346 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
347 * restored on the next draw
349 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
351 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
352 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
357 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
358 error = glGetError();
359 if(error != GL_NO_ERROR || object->vbo == 0) {
360 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
364 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
365 error = glGetError();
366 if(error != GL_NO_ERROR) {
367 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
371 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
372 * copy no readback will be needed
374 glUsage = GL_STATIC_DRAW_ARB;
375 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
376 error = glGetError();
377 if(error != GL_NO_ERROR) {
378 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
382 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
386 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
387 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
392 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
393 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
394 HANDLE *sharedHandle, IUnknown *parent) {
395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
396 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
397 IWineD3DIndexBufferImpl *object;
400 TRACE("(%p) Creating index buffer\n", This);
402 /* Allocate the storage for the device */
403 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
406 ERR("Out of memory\n");
407 *ppIndexBuffer = NULL;
408 return WINED3DERR_OUTOFVIDEOMEMORY;
411 object->lpVtbl = &IWineD3DIndexBuffer_Vtbl;
412 hr = resource_init(&object->resource, WINED3DRTYPE_INDEXBUFFER, This, Length, Usage, format_desc, Pool, parent);
415 WARN("Failed to initialize resource, returning %#x\n", hr);
416 HeapFree(GetProcessHeap(), 0, object);
417 *ppIndexBuffer = NULL;
421 TRACE("(%p) : Created resource %p\n", This, object);
423 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
425 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
426 CreateIndexBufferVBO(This, object);
429 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
430 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
431 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
436 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
439 IWineD3DStateBlockImpl *object;
443 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
446 ERR("Out of memory\n");
447 *ppStateBlock = NULL;
448 return WINED3DERR_OUTOFVIDEOMEMORY;
451 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
452 object->wineD3DDevice = This;
453 object->parent = parent;
455 object->blockType = Type;
457 *ppStateBlock = (IWineD3DStateBlock *)object;
459 for(i = 0; i < LIGHTMAP_SIZE; i++) {
460 list_init(&object->lightMap[i]);
463 temp_result = allocate_shader_constants(object);
464 if (FAILED(temp_result))
466 HeapFree(GetProcessHeap(), 0, object);
470 /* Special case - Used during initialization to produce a placeholder stateblock
471 so other functions called can update a state block */
472 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
474 /* Don't bother increasing the reference count otherwise a device will never
475 be freed due to circular dependencies */
479 /* Otherwise, might as well set the whole state block to the appropriate values */
480 if (This->stateBlock != NULL)
481 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
483 memset(object->streamFreq, 1, sizeof(object->streamFreq));
485 /* Reset the ref and type after kludging it */
486 object->wineD3DDevice = This;
488 object->blockType = Type;
490 TRACE("Updating changed flags appropriate for type %d\n", Type);
492 if (Type == WINED3DSBT_ALL) {
494 TRACE("ALL => Pretend everything has changed\n");
495 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
497 /* Lights are not part of the changed / set structure */
498 for(j = 0; j < LIGHTMAP_SIZE; j++) {
500 LIST_FOR_EACH(e, &object->lightMap[j]) {
501 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
502 light->changed = TRUE;
503 light->enabledChanged = TRUE;
506 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
507 object->contained_render_states[j - 1] = j;
509 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
510 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
511 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
512 object->contained_transform_states[j - 1] = j;
514 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
515 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
516 object->contained_vs_consts_f[j] = j;
518 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
519 for(j = 0; j < MAX_CONST_I; j++) {
520 object->contained_vs_consts_i[j] = j;
522 object->num_contained_vs_consts_i = MAX_CONST_I;
523 for(j = 0; j < MAX_CONST_B; j++) {
524 object->contained_vs_consts_b[j] = j;
526 object->num_contained_vs_consts_b = MAX_CONST_B;
527 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
528 object->contained_ps_consts_f[j] = j;
530 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
531 for(j = 0; j < MAX_CONST_I; j++) {
532 object->contained_ps_consts_i[j] = j;
534 object->num_contained_ps_consts_i = MAX_CONST_I;
535 for(j = 0; j < MAX_CONST_B; j++) {
536 object->contained_ps_consts_b[j] = j;
538 object->num_contained_ps_consts_b = MAX_CONST_B;
539 for(i = 0; i < MAX_TEXTURES; i++) {
540 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
542 object->contained_tss_states[object->num_contained_tss_states].stage = i;
543 object->contained_tss_states[object->num_contained_tss_states].state = j;
544 object->num_contained_tss_states++;
547 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
548 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
549 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
550 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
551 object->num_contained_sampler_states++;
555 for(i = 0; i < MAX_STREAMS; i++) {
556 if(object->streamSource[i]) {
557 IWineD3DBuffer_AddRef(object->streamSource[i]);
560 if(object->pIndexData) {
561 IWineD3DIndexBuffer_AddRef(object->pIndexData);
563 if(object->vertexShader) {
564 IWineD3DVertexShader_AddRef(object->vertexShader);
566 if(object->pixelShader) {
567 IWineD3DPixelShader_AddRef(object->pixelShader);
570 } else if (Type == WINED3DSBT_PIXELSTATE) {
572 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
573 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
575 object->changed.pixelShader = TRUE;
577 /* Pixel Shader Constants */
578 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
579 object->contained_ps_consts_f[i] = i;
580 object->changed.pixelShaderConstantsF[i] = TRUE;
582 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
583 for (i = 0; i < MAX_CONST_B; ++i) {
584 object->contained_ps_consts_b[i] = i;
585 object->changed.pixelShaderConstantsB |= (1 << i);
587 object->num_contained_ps_consts_b = MAX_CONST_B;
588 for (i = 0; i < MAX_CONST_I; ++i) {
589 object->contained_ps_consts_i[i] = i;
590 object->changed.pixelShaderConstantsI |= (1 << i);
592 object->num_contained_ps_consts_i = MAX_CONST_I;
594 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
595 DWORD rs = SavedPixelStates_R[i];
596 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
597 object->contained_render_states[i] = rs;
599 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
600 for (j = 0; j < MAX_TEXTURES; j++) {
601 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
602 DWORD state = SavedPixelStates_T[i];
603 object->changed.textureState[j] |= 1 << state;
604 object->contained_tss_states[object->num_contained_tss_states].stage = j;
605 object->contained_tss_states[object->num_contained_tss_states].state = state;
606 object->num_contained_tss_states++;
609 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
610 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
611 DWORD state = SavedPixelStates_S[i];
612 object->changed.samplerState[j] |= 1 << state;
613 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
614 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
615 object->num_contained_sampler_states++;
618 if(object->pixelShader) {
619 IWineD3DPixelShader_AddRef(object->pixelShader);
622 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
623 * on them. This makes releasing the buffer easier
625 for(i = 0; i < MAX_STREAMS; i++) {
626 object->streamSource[i] = NULL;
628 object->pIndexData = NULL;
629 object->vertexShader = NULL;
631 } else if (Type == WINED3DSBT_VERTEXSTATE) {
633 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
634 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
636 object->changed.vertexShader = TRUE;
638 /* Vertex Shader Constants */
639 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
640 object->changed.vertexShaderConstantsF[i] = TRUE;
641 object->contained_vs_consts_f[i] = i;
643 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
644 for (i = 0; i < MAX_CONST_B; ++i) {
645 object->contained_vs_consts_b[i] = i;
646 object->changed.vertexShaderConstantsB |= (1 << i);
648 object->num_contained_vs_consts_b = MAX_CONST_B;
649 for (i = 0; i < MAX_CONST_I; ++i) {
650 object->contained_vs_consts_i[i] = i;
651 object->changed.vertexShaderConstantsI |= (1 << i);
653 object->num_contained_vs_consts_i = MAX_CONST_I;
654 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
655 DWORD rs = SavedVertexStates_R[i];
656 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
657 object->contained_render_states[i] = rs;
659 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
660 for (j = 0; j < MAX_TEXTURES; j++) {
661 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
662 DWORD state = SavedVertexStates_T[i];
663 object->changed.textureState[j] |= 1 << state;
664 object->contained_tss_states[object->num_contained_tss_states].stage = j;
665 object->contained_tss_states[object->num_contained_tss_states].state = state;
666 object->num_contained_tss_states++;
669 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
670 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
671 DWORD state = SavedVertexStates_S[i];
672 object->changed.samplerState[j] |= 1 << state;
673 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
674 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
675 object->num_contained_sampler_states++;
679 for(j = 0; j < LIGHTMAP_SIZE; j++) {
681 LIST_FOR_EACH(e, &object->lightMap[j]) {
682 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
683 light->changed = TRUE;
684 light->enabledChanged = TRUE;
688 for(i = 0; i < MAX_STREAMS; i++) {
689 if(object->streamSource[i]) {
690 IWineD3DBuffer_AddRef(object->streamSource[i]);
693 if(object->vertexShader) {
694 IWineD3DVertexShader_AddRef(object->vertexShader);
696 object->pIndexData = NULL;
697 object->pixelShader = NULL;
699 FIXME("Unrecognized state block type %d\n", Type);
702 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
706 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) {
707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
708 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
709 unsigned int Size = 1;
710 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(Format, &GLINFO_LOCATION);
714 TRACE("(%p) Create surface\n",This);
716 if(MultisampleQuality > 0) {
717 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
718 MultisampleQuality=0;
721 /** FIXME: Check that the format is supported
723 *******************************/
725 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
726 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
728 *********************************/
729 mul_4w = (Width + 3) & ~3;
730 mul_4h = (Height + 3) & ~3;
731 if (WINED3DFMT_UNKNOWN == Format) {
733 } else if (Format == WINED3DFMT_DXT1) {
734 /* DXT1 is half byte per pixel */
735 Size = (mul_4w * glDesc->byte_count * mul_4h) >> 1;
737 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
738 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
739 Format == WINED3DFMT_ATI2N) {
740 Size = (mul_4w * glDesc->byte_count * mul_4h);
742 /* The pitch is a multiple of 4 bytes */
743 Size = ((Width * glDesc->byte_count) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
747 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
749 /** Create and initialise the surface resource **/
750 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
753 ERR("Out of memory\n");
755 return WINED3DERR_OUTOFVIDEOMEMORY;
758 /* Look at the implementation and set the correct Vtable */
762 /* Check if a 3D adapter is available when creating gl surfaces */
765 ERR("OpenGL surfaces are not available without opengl\n");
766 HeapFree(GetProcessHeap(), 0, object);
767 return WINED3DERR_NOTAVAILABLE;
769 object->lpVtbl = &IWineD3DSurface_Vtbl;
773 object->lpVtbl = &IWineGDISurface_Vtbl;
777 /* To be sure to catch this */
778 ERR("Unknown requested surface implementation %d!\n", Impl);
779 HeapFree(GetProcessHeap(), 0, object);
780 return WINED3DERR_INVALIDCALL;
783 hr = resource_init(&object->resource, WINED3DRTYPE_SURFACE, This, Size, Usage, glDesc, Pool, parent);
786 WARN("Failed to initialize resource, returning %#x\n", hr);
787 HeapFree(GetProcessHeap(), 0, object);
792 TRACE("(%p) : Created resource %p\n", This, object);
794 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
796 *ppSurface = (IWineD3DSurface *)object;
798 /* "Standalone" surface */
799 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
801 object->currentDesc.Width = Width;
802 object->currentDesc.Height = Height;
803 object->currentDesc.MultiSampleType = MultiSample;
804 object->currentDesc.MultiSampleQuality = MultisampleQuality;
805 object->glDescription.level = Level;
806 list_init(&object->overlays);
809 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
810 object->Flags |= Discard ? SFLAG_DISCARD : 0;
811 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
812 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
814 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
816 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
817 * this function is too deep to need to care about things like this.
818 * Levels need to be checked too, and possibly Type since they all affect what can be done.
819 * ****************************************/
821 case WINED3DPOOL_SCRATCH:
823 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
824 "which are mutually exclusive, setting lockable to TRUE\n");
827 case WINED3DPOOL_SYSTEMMEM:
828 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
829 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
830 case WINED3DPOOL_MANAGED:
831 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
832 "Usage of DYNAMIC which are mutually exclusive, not doing "
833 "anything just telling you.\n");
835 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
836 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
837 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
838 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
841 FIXME("(%p) Unknown pool %d\n", This, Pool);
845 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
846 FIXME("Trying to create a render target that isn't in the default pool\n");
849 /* mark the texture as dirty so that it gets loaded first time around*/
850 surface_add_dirty_rect(*ppSurface, NULL);
851 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
852 This, Width, Height, Format, debug_d3dformat(Format),
853 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
855 list_init(&object->renderbuffers);
857 /* Call the private setup routine */
858 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)object);
861 ERR("Private setup failed, returning %#x\n", hr);
862 IWineD3DSurface_Release(*ppSurface);
870 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
871 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
873 struct wined3d_rendertarget_view *object;
875 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
878 ERR("Failed to allocate memory\n");
879 return E_OUTOFMEMORY;
882 object->vtbl = &wined3d_rendertarget_view_vtbl;
883 object->refcount = 1;
884 IWineD3DResource_AddRef(resource);
885 object->resource = resource;
886 object->parent = parent;
888 *rendertarget_view = (IWineD3DRendertargetView *)object;
893 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
894 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
895 IWineD3DTexture **ppTexture, HANDLE *pSharedHandle, IUnknown *parent)
897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
898 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
899 IWineD3DTextureImpl *object;
904 unsigned int pow2Width;
905 unsigned int pow2Height;
907 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
908 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
909 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
911 /* TODO: It should only be possible to create textures for formats
912 that are reported as supported */
913 if (WINED3DFMT_UNKNOWN >= Format) {
914 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
915 return WINED3DERR_INVALIDCALL;
918 /* Non-power2 support */
919 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO))
926 /* Find the nearest pow2 match */
927 pow2Width = pow2Height = 1;
928 while (pow2Width < Width) pow2Width <<= 1;
929 while (pow2Height < Height) pow2Height <<= 1;
931 if (pow2Width != Width || pow2Height != Height)
935 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
936 return WINED3DERR_INVALIDCALL;
942 /* Calculate levels for mip mapping */
943 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
945 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
947 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
948 return WINED3DERR_INVALIDCALL;
953 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
954 return WINED3DERR_INVALIDCALL;
961 Levels = wined3d_log2i(max(Width, Height)) + 1;
962 TRACE("Calculated levels = %d\n", Levels);
965 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
968 ERR("Out of memory\n");
970 return WINED3DERR_OUTOFVIDEOMEMORY;
973 object->lpVtbl = &IWineD3DTexture_Vtbl;
974 hr = resource_init(&object->resource, WINED3DRTYPE_TEXTURE, This, 0, Usage, format_desc, Pool, parent);
977 WARN("Failed to initialize resource, returning %#x\n", hr);
978 HeapFree(GetProcessHeap(), 0, object);
983 TRACE("(%p) : Created resource %p\n", This, object);
985 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
987 *ppTexture = (IWineD3DTexture *)object;
989 basetexture_init(&object->baseTexture, Levels, Usage);
991 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
993 object->baseTexture.minMipLookup = minMipLookup;
994 object->baseTexture.magLookup = magLookup;
996 object->baseTexture.minMipLookup = minMipLookup_noFilter;
997 object->baseTexture.magLookup = magLookup_noFilter;
1000 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1001 /* Precalculated scaling for 'faked' non power of two texture coords.
1002 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
1003 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
1004 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
1006 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
1007 object->baseTexture.pow2Matrix[0] = 1.0;
1008 object->baseTexture.pow2Matrix[5] = 1.0;
1009 object->baseTexture.pow2Matrix[10] = 1.0;
1010 object->baseTexture.pow2Matrix[15] = 1.0;
1011 object->target = GL_TEXTURE_2D;
1012 object->cond_np2 = TRUE;
1013 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1014 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
1015 (Width != pow2Width || Height != pow2Height) &&
1016 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
1018 object->baseTexture.pow2Matrix[0] = (float)Width;
1019 object->baseTexture.pow2Matrix[5] = (float)Height;
1020 object->baseTexture.pow2Matrix[10] = 1.0;
1021 object->baseTexture.pow2Matrix[15] = 1.0;
1022 object->target = GL_TEXTURE_RECTANGLE_ARB;
1023 object->cond_np2 = TRUE;
1024 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1026 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
1027 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
1028 object->baseTexture.pow2Matrix[10] = 1.0;
1029 object->baseTexture.pow2Matrix[15] = 1.0;
1030 object->target = GL_TEXTURE_2D;
1031 object->cond_np2 = FALSE;
1033 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
1035 /* Generate all the surfaces */
1038 for (i = 0; i < object->baseTexture.levels; i++)
1040 /* use the callback to create the texture surface */
1041 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpH, Format,
1042 Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i]);
1043 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1044 FIXME("Failed to create surface %p\n", object);
1046 object->surfaces[i] = NULL;
1047 IWineD3DTexture_Release((IWineD3DTexture *)object);
1053 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1054 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1055 surface_set_texture_target(object->surfaces[i], object->target);
1056 /* calculate the next mipmap level */
1057 tmpW = max(1, tmpW >> 1);
1058 tmpH = max(1, tmpH >> 1);
1060 object->baseTexture.internal_preload = texture_internal_preload;
1062 TRACE("(%p) : Created texture %p\n", This, object);
1066 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1067 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1068 IWineD3DVolumeTexture **ppVolumeTexture, HANDLE *pSharedHandle, IUnknown *parent)
1070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1071 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1072 IWineD3DVolumeTextureImpl *object;
1079 /* TODO: It should only be possible to create textures for formats
1080 that are reported as supported */
1081 if (WINED3DFMT_UNKNOWN >= Format) {
1082 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1083 return WINED3DERR_INVALIDCALL;
1085 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1086 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
1087 return WINED3DERR_INVALIDCALL;
1090 /* Calculate levels for mip mapping */
1091 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1093 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1095 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1096 return WINED3DERR_INVALIDCALL;
1101 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1102 return WINED3DERR_INVALIDCALL;
1109 Levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
1110 TRACE("Calculated levels = %d\n", Levels);
1113 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1116 ERR("Out of memory\n");
1117 *ppVolumeTexture = NULL;
1118 return WINED3DERR_OUTOFVIDEOMEMORY;
1121 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1122 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUMETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1125 WARN("Failed to initialize resource, returning %#x\n", hr);
1126 HeapFree(GetProcessHeap(), 0, object);
1127 *ppVolumeTexture = NULL;
1131 TRACE("(%p) : Created resource %p\n", This, object);
1133 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1135 basetexture_init(&object->baseTexture, Levels, Usage);
1137 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1138 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1140 /* Is NP2 support for volumes needed? */
1141 object->baseTexture.pow2Matrix[ 0] = 1.0;
1142 object->baseTexture.pow2Matrix[ 5] = 1.0;
1143 object->baseTexture.pow2Matrix[10] = 1.0;
1144 object->baseTexture.pow2Matrix[15] = 1.0;
1146 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1148 object->baseTexture.minMipLookup = minMipLookup;
1149 object->baseTexture.magLookup = magLookup;
1151 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1152 object->baseTexture.magLookup = magLookup_noFilter;
1155 /* Generate all the surfaces */
1160 for (i = 0; i < object->baseTexture.levels; i++)
1163 /* Create the volume */
1164 hr = IWineD3DDeviceParent_CreateVolume(This->device_parent, parent,
1165 tmpW, tmpH, tmpD, Format, Pool, Usage, &object->volumes[i]);
1167 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1168 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1169 *ppVolumeTexture = NULL;
1173 /* Set its container to this object */
1174 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1176 /* calculate the next mipmap level */
1177 tmpW = max(1, tmpW >> 1);
1178 tmpH = max(1, tmpH >> 1);
1179 tmpD = max(1, tmpD >> 1);
1181 object->baseTexture.internal_preload = volumetexture_internal_preload;
1183 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1184 TRACE("(%p) : Created volume texture %p\n", This, object);
1188 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1189 UINT Width, UINT Height, UINT Depth,
1191 WINED3DFORMAT Format, WINED3DPOOL Pool,
1192 IWineD3DVolume** ppVolume,
1193 HANDLE* pSharedHandle, IUnknown *parent) {
1195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1196 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1197 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1200 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1201 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1202 return WINED3DERR_INVALIDCALL;
1205 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1208 ERR("Out of memory\n");
1210 return WINED3DERR_OUTOFVIDEOMEMORY;
1213 object->lpVtbl = &IWineD3DVolume_Vtbl;
1214 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUME, This,
1215 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1218 WARN("Failed to initialize resource, returning %#x\n", hr);
1219 HeapFree(GetProcessHeap(), 0, object);
1224 TRACE("(%p) : Created resource %p\n", This, object);
1226 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1228 *ppVolume = (IWineD3DVolume *)object;
1230 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1231 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1233 object->currentDesc.Width = Width;
1234 object->currentDesc.Height = Height;
1235 object->currentDesc.Depth = Depth;
1237 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1238 object->lockable = TRUE;
1239 object->locked = FALSE;
1240 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1241 object->dirty = TRUE;
1243 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1248 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1249 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1250 IWineD3DCubeTexture **ppCubeTexture, HANDLE *pSharedHandle, IUnknown *parent)
1252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1253 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1254 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1258 unsigned int pow2EdgeLength;
1260 /* TODO: It should only be possible to create textures for formats
1261 that are reported as supported */
1262 if (WINED3DFMT_UNKNOWN >= Format) {
1263 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1264 return WINED3DERR_INVALIDCALL;
1267 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1268 WARN("(%p) : Tried to create not supported cube texture\n", This);
1269 return WINED3DERR_INVALIDCALL;
1272 /* Calculate levels for mip mapping */
1273 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1275 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1277 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1278 return WINED3DERR_INVALIDCALL;
1283 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1284 return WINED3DERR_INVALIDCALL;
1291 Levels = wined3d_log2i(EdgeLength) + 1;
1292 TRACE("Calculated levels = %d\n", Levels);
1295 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1298 ERR("Out of memory\n");
1299 *ppCubeTexture = NULL;
1300 return WINED3DERR_OUTOFVIDEOMEMORY;
1303 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1304 hr = resource_init(&object->resource, WINED3DRTYPE_CUBETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1307 WARN("Failed to initialize resource, returning %#x\n", hr);
1308 HeapFree(GetProcessHeap(), 0, object);
1309 *ppCubeTexture = NULL;
1313 TRACE("(%p) : Created resource %p\n", This, object);
1315 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1317 basetexture_init(&object->baseTexture, Levels, Usage);
1319 TRACE("(%p) Create Cube Texture\n", This);
1321 /* Find the nearest pow2 match */
1323 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1325 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
1326 /* Precalculated scaling for 'faked' non power of two texture coords */
1327 object->baseTexture.pow2Matrix[ 0] = 1.0;
1328 object->baseTexture.pow2Matrix[ 5] = 1.0;
1329 object->baseTexture.pow2Matrix[10] = 1.0;
1330 object->baseTexture.pow2Matrix[15] = 1.0;
1332 /* Precalculated scaling for 'faked' non power of two texture coords */
1333 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1334 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1335 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1336 object->baseTexture.pow2Matrix[15] = 1.0;
1339 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1341 object->baseTexture.minMipLookup = minMipLookup;
1342 object->baseTexture.magLookup = magLookup;
1344 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1345 object->baseTexture.magLookup = magLookup_noFilter;
1348 /* Generate all the surfaces */
1350 for (i = 0; i < object->baseTexture.levels; i++) {
1352 /* Create the 6 faces */
1353 for (j = 0; j < 6; j++) {
1354 static const GLenum cube_targets[6] = {
1355 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1356 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1357 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1358 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1359 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1360 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1363 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpW,
1364 Format, Usage, Pool, i /* Level */, j, &object->surfaces[j][i]);
1367 FIXME("(%p) Failed to create surface\n",object);
1368 IWineD3DCubeTexture_Release((IWineD3DCubeTexture *)object);
1369 *ppCubeTexture = NULL;
1372 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1373 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1374 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1376 tmpW = max(1, tmpW >> 1);
1378 object->baseTexture.internal_preload = cubetexture_internal_preload;
1380 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1381 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1385 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1387 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1388 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1389 const IWineD3DQueryVtbl *vtable;
1391 /* Just a check to see if we support this type of query */
1393 case WINED3DQUERYTYPE_OCCLUSION:
1394 TRACE("(%p) occlusion query\n", This);
1395 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1398 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1400 vtable = &IWineD3DOcclusionQuery_Vtbl;
1403 case WINED3DQUERYTYPE_EVENT:
1404 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1405 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1406 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1408 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1410 vtable = &IWineD3DEventQuery_Vtbl;
1414 case WINED3DQUERYTYPE_VCACHE:
1415 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1416 case WINED3DQUERYTYPE_VERTEXSTATS:
1417 case WINED3DQUERYTYPE_TIMESTAMP:
1418 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1419 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1420 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1421 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1422 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1423 case WINED3DQUERYTYPE_PIXELTIMINGS:
1424 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1425 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1427 /* Use the base Query vtable until we have a special one for each query */
1428 vtable = &IWineD3DQuery_Vtbl;
1429 FIXME("(%p) Unhandled query type %d\n", This, Type);
1431 if(NULL == ppQuery || hr != WINED3D_OK) {
1435 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1438 ERR("Out of memory\n");
1440 return WINED3DERR_OUTOFVIDEOMEMORY;
1443 object->lpVtbl = vtable;
1444 object->type = Type;
1445 object->state = QUERY_CREATED;
1446 object->wineD3DDevice = This;
1447 object->parent = parent;
1450 *ppQuery = (IWineD3DQuery *)object;
1452 /* allocated the 'extended' data based on the type of query requested */
1454 case WINED3DQUERYTYPE_OCCLUSION:
1455 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1456 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1458 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1459 TRACE("(%p) Allocating data for an occlusion query\n", This);
1461 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1463 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1467 case WINED3DQUERYTYPE_EVENT:
1468 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1469 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1471 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1473 if(GL_SUPPORT(APPLE_FENCE)) {
1474 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1475 checkGLcall("glGenFencesAPPLE");
1476 } else if(GL_SUPPORT(NV_FENCE)) {
1477 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1478 checkGLcall("glGenFencesNV");
1483 case WINED3DQUERYTYPE_VCACHE:
1484 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1485 case WINED3DQUERYTYPE_VERTEXSTATS:
1486 case WINED3DQUERYTYPE_TIMESTAMP:
1487 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1488 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1489 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1490 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1491 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1492 case WINED3DQUERYTYPE_PIXELTIMINGS:
1493 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1494 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1496 object->extendedData = 0;
1497 FIXME("(%p) Unhandled query type %d\n",This , Type);
1499 TRACE("(%p) : Created Query %p\n", This, object);
1503 /*****************************************************************************
1504 * IWineD3DDeviceImpl_SetupFullscreenWindow
1506 * Helper function that modifies a HWND's Style and ExStyle for proper
1510 * iface: Pointer to the IWineD3DDevice interface
1511 * window: Window to setup
1513 *****************************************************************************/
1514 static LONG fullscreen_style(LONG orig_style) {
1515 LONG style = orig_style;
1516 style &= ~WS_CAPTION;
1517 style &= ~WS_THICKFRAME;
1519 /* Make sure the window is managed, otherwise we won't get keyboard input */
1520 style |= WS_POPUP | WS_SYSMENU;
1525 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1526 LONG exStyle = orig_exStyle;
1528 /* Filter out window decorations */
1529 exStyle &= ~WS_EX_WINDOWEDGE;
1530 exStyle &= ~WS_EX_CLIENTEDGE;
1535 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1538 LONG style, exStyle;
1539 /* Don't do anything if an original style is stored.
1540 * That shouldn't happen
1542 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1543 if (This->style || This->exStyle) {
1544 ERR("(%p): Want to change the window parameters of HWND %p, but "
1545 "another style is stored for restoration afterwards\n", This, window);
1548 /* Get the parameters and save them */
1549 style = GetWindowLongW(window, GWL_STYLE);
1550 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1551 This->style = style;
1552 This->exStyle = exStyle;
1554 style = fullscreen_style(style);
1555 exStyle = fullscreen_exStyle(exStyle);
1557 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1558 This->style, This->exStyle, style, exStyle);
1560 SetWindowLongW(window, GWL_STYLE, style);
1561 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1563 /* Inform the window about the update. */
1564 SetWindowPos(window, HWND_TOP, 0, 0,
1565 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1568 /*****************************************************************************
1569 * IWineD3DDeviceImpl_RestoreWindow
1571 * Helper function that restores a windows' properties when taking it out
1572 * of fullscreen mode
1575 * iface: Pointer to the IWineD3DDevice interface
1576 * window: Window to setup
1578 *****************************************************************************/
1579 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1581 LONG style, exStyle;
1583 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1584 * switch, do nothing
1586 if (!This->style && !This->exStyle) return;
1588 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1589 This, window, This->style, This->exStyle);
1591 style = GetWindowLongW(window, GWL_STYLE);
1592 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1594 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1595 * Some applications change it before calling Reset() when switching between windowed and
1596 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1598 if(style == fullscreen_style(This->style) &&
1599 exStyle == fullscreen_style(This->exStyle)) {
1600 SetWindowLongW(window, GWL_STYLE, This->style);
1601 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1604 /* Delete the old values */
1608 /* Inform the window about the update */
1609 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1610 0, 0, 0, 0, /* Pos, Size, ignored */
1611 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1614 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1615 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1616 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1617 IUnknown *parent, WINED3DSURFTYPE surface_type)
1619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1622 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1624 IUnknown *bufferParent;
1625 BOOL displaymode_set = FALSE;
1626 WINED3DDISPLAYMODE Mode;
1627 const struct GlPixelFormatDesc *format_desc;
1629 TRACE("(%p) : Created Additional Swap Chain\n", This);
1631 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1632 * does a device hold a reference to a swap chain giving them a lifetime of the device
1633 * or does the swap chain notify the device of its destruction.
1634 *******************************/
1636 /* Check the params */
1637 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1638 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1639 return WINED3DERR_INVALIDCALL;
1640 } else if (pPresentationParameters->BackBufferCount > 1) {
1641 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");
1644 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1647 ERR("Out of memory\n");
1648 *ppSwapChain = NULL;
1649 return WINED3DERR_OUTOFVIDEOMEMORY;
1652 switch(surface_type) {
1654 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1656 case SURFACE_OPENGL:
1657 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1659 case SURFACE_UNKNOWN:
1660 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1661 HeapFree(GetProcessHeap(), 0, object);
1662 return WINED3DERR_INVALIDCALL;
1664 object->wineD3DDevice = This;
1665 object->parent = parent;
1668 *ppSwapChain = (IWineD3DSwapChain *)object;
1670 /*********************
1671 * Lookup the window Handle and the relating X window handle
1672 ********************/
1674 /* Setup hwnd we are using, plus which display this equates to */
1675 object->win_handle = pPresentationParameters->hDeviceWindow;
1676 if (!object->win_handle) {
1677 object->win_handle = This->createParms.hFocusWindow;
1679 if(!pPresentationParameters->Windowed && object->win_handle) {
1680 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1681 pPresentationParameters->BackBufferWidth,
1682 pPresentationParameters->BackBufferHeight);
1685 hDc = GetDC(object->win_handle);
1686 TRACE("Using hDc %p\n", hDc);
1689 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1690 return WINED3DERR_NOTAVAILABLE;
1693 /* Get info on the current display setup */
1694 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1695 object->orig_width = Mode.Width;
1696 object->orig_height = Mode.Height;
1697 object->orig_fmt = Mode.Format;
1698 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1700 if (pPresentationParameters->Windowed &&
1701 ((pPresentationParameters->BackBufferWidth == 0) ||
1702 (pPresentationParameters->BackBufferHeight == 0) ||
1703 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1706 GetClientRect(object->win_handle, &Rect);
1708 if (pPresentationParameters->BackBufferWidth == 0) {
1709 pPresentationParameters->BackBufferWidth = Rect.right;
1710 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1712 if (pPresentationParameters->BackBufferHeight == 0) {
1713 pPresentationParameters->BackBufferHeight = Rect.bottom;
1714 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1716 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1717 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1718 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1722 /* Put the correct figures in the presentation parameters */
1723 TRACE("Copying across presentation parameters\n");
1724 object->presentParms = *pPresentationParameters;
1726 TRACE("calling rendertarget CB\n");
1727 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1728 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1729 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1730 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1731 if (SUCCEEDED(hr)) {
1732 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1733 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1734 if(surface_type == SURFACE_OPENGL) {
1735 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1738 ERR("Failed to create the front buffer\n");
1742 /*********************
1743 * Windowed / Fullscreen
1744 *******************/
1747 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1748 * so we should really check to see if there is a fullscreen swapchain already
1749 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1750 **************************************/
1752 if (!pPresentationParameters->Windowed) {
1753 WINED3DDISPLAYMODE mode;
1756 /* Change the display settings */
1757 mode.Width = pPresentationParameters->BackBufferWidth;
1758 mode.Height = pPresentationParameters->BackBufferHeight;
1759 mode.Format = pPresentationParameters->BackBufferFormat;
1760 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1762 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1763 displaymode_set = TRUE;
1767 * Create an opengl context for the display visual
1768 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1769 * use different properties after that point in time. FIXME: How to handle when requested format
1770 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1771 * it chooses is identical to the one already being used!
1772 **********************************/
1773 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1775 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1776 if(!object->context) {
1777 ERR("Failed to create the context array\n");
1781 object->num_contexts = 1;
1783 if(surface_type == SURFACE_OPENGL) {
1784 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1785 if (!object->context[0]) {
1786 ERR("Failed to create a new context\n");
1787 hr = WINED3DERR_NOTAVAILABLE;
1790 TRACE("Context created (HWND=%p, glContext=%p)\n",
1791 object->win_handle, object->context[0]->glCtx);
1795 /*********************
1796 * Create the back, front and stencil buffers
1797 *******************/
1798 if(object->presentParms.BackBufferCount > 0) {
1801 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1802 if(!object->backBuffer) {
1803 ERR("Out of memory\n");
1808 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1809 TRACE("calling rendertarget CB\n");
1810 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1811 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1812 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1813 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1815 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1816 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1818 ERR("Cannot create new back buffer\n");
1821 if(surface_type == SURFACE_OPENGL) {
1823 glDrawBuffer(GL_BACK);
1824 checkGLcall("glDrawBuffer(GL_BACK)");
1829 object->backBuffer = NULL;
1831 /* Single buffering - draw to front buffer */
1832 if(surface_type == SURFACE_OPENGL) {
1834 glDrawBuffer(GL_FRONT);
1835 checkGLcall("glDrawBuffer(GL_FRONT)");
1840 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1841 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1842 TRACE("Creating depth stencil buffer\n");
1843 if (This->auto_depth_stencil_buffer == NULL ) {
1844 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1845 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1846 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1847 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1848 &This->auto_depth_stencil_buffer);
1849 if (SUCCEEDED(hr)) {
1850 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1852 ERR("Failed to create the auto depth stencil\n");
1858 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1860 TRACE("Created swapchain %p\n", object);
1861 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1865 if (displaymode_set) {
1869 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1872 /* Change the display settings */
1873 memset(&devmode, 0, sizeof(devmode));
1874 devmode.dmSize = sizeof(devmode);
1875 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1876 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1877 devmode.dmPelsWidth = object->orig_width;
1878 devmode.dmPelsHeight = object->orig_height;
1879 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1882 if (object->backBuffer) {
1884 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1885 if(object->backBuffer[i]) {
1886 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1887 IUnknown_Release(bufferParent); /* once for the get parent */
1888 if (IUnknown_Release(bufferParent) > 0) {
1889 FIXME("(%p) Something's still holding the back buffer\n",This);
1893 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1894 object->backBuffer = NULL;
1896 if(object->context && object->context[0])
1897 DestroyContext(This, object->context[0]);
1898 if(object->frontBuffer) {
1899 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1900 IUnknown_Release(bufferParent); /* once for the get parent */
1901 if (IUnknown_Release(bufferParent) > 0) {
1902 FIXME("(%p) Something's still holding the front buffer\n",This);
1905 HeapFree(GetProcessHeap(), 0, object);
1909 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1910 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1912 TRACE("(%p)\n", This);
1914 return This->NumberOfSwapChains;
1917 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1919 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1921 if(iSwapChain < This->NumberOfSwapChains) {
1922 *pSwapChain = This->swapchains[iSwapChain];
1923 IWineD3DSwapChain_AddRef(*pSwapChain);
1924 TRACE("(%p) returning %p\n", This, *pSwapChain);
1927 TRACE("Swapchain out of range\n");
1929 return WINED3DERR_INVALIDCALL;
1934 * Vertex Declaration
1936 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1937 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1939 IWineD3DVertexDeclarationImpl *object = NULL;
1940 HRESULT hr = WINED3D_OK;
1942 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1943 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1945 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1948 ERR("Out of memory\n");
1949 *ppVertexDeclaration = NULL;
1950 return WINED3DERR_OUTOFVIDEOMEMORY;
1953 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
1954 object->wineD3DDevice = This;
1955 object->parent = parent;
1958 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1960 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1962 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1963 *ppVertexDeclaration = NULL;
1969 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1970 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1972 unsigned int idx, idx2;
1973 unsigned int offset;
1974 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1975 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1976 BOOL has_blend_idx = has_blend &&
1977 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1978 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1979 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1980 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1981 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1982 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1983 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1985 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1986 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1988 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1989 WINED3DVERTEXELEMENT *elements = NULL;
1992 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1993 if (has_blend_idx) num_blends--;
1995 /* Compute declaration size */
1996 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1997 has_psize + has_diffuse + has_specular + num_textures + 1;
1999 /* convert the declaration */
2000 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
2004 elements[size-1] = end_element;
2007 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
2008 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2009 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
2011 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
2012 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2013 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
2016 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2017 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
2019 elements[idx].UsageIndex = 0;
2022 if (has_blend && (num_blends > 0)) {
2023 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
2024 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2026 switch(num_blends) {
2027 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
2028 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
2029 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
2030 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
2032 ERR("Unexpected amount of blend values: %u\n", num_blends);
2035 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
2036 elements[idx].UsageIndex = 0;
2039 if (has_blend_idx) {
2040 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
2041 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
2042 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
2043 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
2044 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2046 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2047 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
2048 elements[idx].UsageIndex = 0;
2052 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2053 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
2054 elements[idx].UsageIndex = 0;
2058 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2059 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
2060 elements[idx].UsageIndex = 0;
2064 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2065 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
2066 elements[idx].UsageIndex = 0;
2070 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2071 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
2072 elements[idx].UsageIndex = 1;
2075 for (idx2 = 0; idx2 < num_textures; idx2++) {
2076 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
2077 switch (numcoords) {
2078 case WINED3DFVF_TEXTUREFORMAT1:
2079 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2081 case WINED3DFVF_TEXTUREFORMAT2:
2082 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
2084 case WINED3DFVF_TEXTUREFORMAT3:
2085 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2087 case WINED3DFVF_TEXTUREFORMAT4:
2088 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2091 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
2092 elements[idx].UsageIndex = idx2;
2096 /* Now compute offsets, and initialize the rest of the fields */
2097 for (idx = 0, offset = 0; idx < size-1; idx++) {
2098 elements[idx].Stream = 0;
2099 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
2100 elements[idx].Offset = offset;
2101 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
2104 *ppVertexElements = elements;
2108 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
2109 WINED3DVERTEXELEMENT* elements = NULL;
2110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2114 size = ConvertFvfToDeclaration(This, Fvf, &elements);
2115 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
2117 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
2118 HeapFree(GetProcessHeap(), 0, elements);
2119 if (hr != S_OK) return hr;
2124 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
2125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2126 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
2127 HRESULT hr = WINED3D_OK;
2129 if (!pFunction) return WINED3DERR_INVALIDCALL;
2131 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2134 ERR("Out of memory\n");
2135 *ppVertexShader = NULL;
2136 return WINED3DERR_OUTOFVIDEOMEMORY;
2139 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
2140 object->parent = parent;
2141 shader_init(&object->baseShader, iface, IWineD3DVertexShaderImpl_shader_ins);
2142 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2143 *ppVertexShader = (IWineD3DVertexShader *)object;
2145 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
2147 if (vertex_declaration) {
2148 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
2151 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
2154 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2155 IWineD3DVertexShader_Release(*ppVertexShader);
2156 *ppVertexShader = NULL;
2163 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
2164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2165 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2166 HRESULT hr = WINED3D_OK;
2168 if (!pFunction) return WINED3DERR_INVALIDCALL;
2170 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2173 ERR("Out of memory\n");
2174 *ppPixelShader = NULL;
2175 return WINED3DERR_OUTOFVIDEOMEMORY;
2178 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2179 object->parent = parent;
2180 shader_init(&object->baseShader, iface, IWineD3DPixelShaderImpl_shader_ins);
2181 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2182 *ppPixelShader = (IWineD3DPixelShader *)object;
2184 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2186 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
2189 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2190 IWineD3DPixelShader_Release(*ppPixelShader);
2191 *ppPixelShader = NULL;
2198 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2199 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2202 IWineD3DPaletteImpl *object;
2204 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2206 /* Create the new object */
2207 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2209 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2210 return E_OUTOFMEMORY;
2213 object->lpVtbl = &IWineD3DPalette_Vtbl;
2215 object->Flags = Flags;
2216 object->parent = Parent;
2217 object->wineD3DDevice = This;
2218 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2219 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2222 HeapFree( GetProcessHeap(), 0, object);
2223 return E_OUTOFMEMORY;
2226 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2228 IWineD3DPalette_Release((IWineD3DPalette *) object);
2232 *Palette = (IWineD3DPalette *) object;
2237 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2241 HDC dcb = NULL, dcs = NULL;
2242 WINEDDCOLORKEY colorkey;
2244 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2247 GetObjectA(hbm, sizeof(BITMAP), &bm);
2248 dcb = CreateCompatibleDC(NULL);
2250 SelectObject(dcb, hbm);
2254 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2255 * couldn't be loaded
2257 memset(&bm, 0, sizeof(bm));
2262 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2263 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2264 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
2266 ERR("Wine logo requested, but failed to create surface\n");
2271 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2272 if(FAILED(hr)) goto out;
2273 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2274 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2276 colorkey.dwColorSpaceLowValue = 0;
2277 colorkey.dwColorSpaceHighValue = 0;
2278 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2280 /* Fill the surface with a white color to show that wined3d is there */
2281 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2294 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2296 /* Under DirectX you can have texture stage operations even if no texture is
2297 bound, whereas opengl will only do texture operations when a valid texture is
2298 bound. We emulate this by creating dummy textures and binding them to each
2299 texture stage, but disable all stages by default. Hence if a stage is enabled
2300 then the default texture will kick in until replaced by a SetTexture call */
2303 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2304 /* The dummy texture does not have client storage backing */
2305 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2306 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2308 for (i = 0; i < GL_LIMITS(textures); i++) {
2309 GLubyte white = 255;
2311 /* Make appropriate texture active */
2312 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2313 checkGLcall("glActiveTextureARB");
2315 /* Generate an opengl texture name */
2316 glGenTextures(1, &This->dummyTextureName[i]);
2317 checkGLcall("glGenTextures");
2318 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2320 /* Generate a dummy 2d texture (not using 1d because they cause many
2321 * DRI drivers fall back to sw) */
2322 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2323 checkGLcall("glBindTexture");
2325 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2326 checkGLcall("glTexImage2D");
2328 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2329 /* Reenable because if supported it is enabled by default */
2330 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2331 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2337 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2338 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2341 IWineD3DSwapChainImpl *swapchain = NULL;
2346 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2348 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2349 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2351 /* TODO: Test if OpenGL is compiled in and loaded */
2353 TRACE("(%p) : Creating stateblock\n", This);
2354 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2355 hr = IWineD3DDevice_CreateStateBlock(iface,
2357 (IWineD3DStateBlock **)&This->stateBlock,
2359 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2360 WARN("Failed to create stateblock\n");
2363 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2364 This->updateStateBlock = This->stateBlock;
2365 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2367 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2368 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2370 This->NumberOfPalettes = 1;
2371 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2372 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2373 ERR("Out of memory!\n");
2376 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2377 if(!This->palettes[0]) {
2378 ERR("Out of memory!\n");
2381 for (i = 0; i < 256; ++i) {
2382 This->palettes[0][i].peRed = 0xFF;
2383 This->palettes[0][i].peGreen = 0xFF;
2384 This->palettes[0][i].peBlue = 0xFF;
2385 This->palettes[0][i].peFlags = 0xFF;
2387 This->currentPalette = 0;
2389 /* Initialize the texture unit mapping to a 1:1 mapping */
2390 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2391 if (state < GL_LIMITS(fragment_samplers)) {
2392 This->texUnitMap[state] = state;
2393 This->rev_tex_unit_map[state] = state;
2395 This->texUnitMap[state] = -1;
2396 This->rev_tex_unit_map[state] = -1;
2400 /* Setup the implicit swapchain */
2401 TRACE("Creating implicit swapchain\n");
2402 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2403 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2406 WARN("Failed to create implicit swapchain\n");
2410 This->NumberOfSwapChains = 1;
2411 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2412 if(!This->swapchains) {
2413 ERR("Out of memory!\n");
2416 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2418 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2419 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2420 This->render_targets[0] = swapchain->backBuffer[0];
2421 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2424 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2425 This->render_targets[0] = swapchain->frontBuffer;
2426 This->lastActiveRenderTarget = swapchain->frontBuffer;
2428 IWineD3DSurface_AddRef(This->render_targets[0]);
2429 This->activeContext = swapchain->context[0];
2430 This->lastThread = GetCurrentThreadId();
2432 /* Depth Stencil support */
2433 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2434 if (NULL != This->stencilBufferTarget) {
2435 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2438 hr = This->shader_backend->shader_alloc_private(iface);
2440 TRACE("Shader private data couldn't be allocated\n");
2443 hr = This->frag_pipe->alloc_private(iface);
2445 TRACE("Fragment pipeline private data couldn't be allocated\n");
2448 hr = This->blitter->alloc_private(iface);
2450 TRACE("Blitter private data couldn't be allocated\n");
2454 /* Set up some starting GL setup */
2456 /* Setup all the devices defaults */
2457 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2458 create_dummy_textures(This);
2462 /* Initialize the current view state */
2463 This->view_ident = 1;
2464 This->contexts[0]->last_was_rhw = 0;
2465 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2466 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2468 switch(wined3d_settings.offscreen_rendering_mode) {
2471 This->offscreenBuffer = GL_BACK;
2474 case ORM_BACKBUFFER:
2476 if(This->activeContext->aux_buffers > 0) {
2477 TRACE("Using auxilliary buffer for offscreen rendering\n");
2478 This->offscreenBuffer = GL_AUX0;
2480 TRACE("Using back buffer for offscreen rendering\n");
2481 This->offscreenBuffer = GL_BACK;
2486 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2489 /* Clear the screen */
2490 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2491 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2494 This->d3d_initialized = TRUE;
2496 if(wined3d_settings.logo) {
2497 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2499 This->highest_dirty_ps_const = 0;
2500 This->highest_dirty_vs_const = 0;
2504 HeapFree(GetProcessHeap(), 0, This->render_targets);
2505 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2506 HeapFree(GetProcessHeap(), 0, This->swapchains);
2507 This->NumberOfSwapChains = 0;
2508 if(This->palettes) {
2509 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2510 HeapFree(GetProcessHeap(), 0, This->palettes);
2512 This->NumberOfPalettes = 0;
2514 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2516 if(This->stateBlock) {
2517 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2518 This->stateBlock = NULL;
2520 if (This->blit_priv) {
2521 This->blitter->free_private(iface);
2523 if (This->fragment_priv) {
2524 This->frag_pipe->free_private(iface);
2526 if (This->shader_priv) {
2527 This->shader_backend->shader_free_private(iface);
2532 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2533 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2536 IWineD3DSwapChainImpl *swapchain = NULL;
2539 /* Setup the implicit swapchain */
2540 TRACE("Creating implicit swapchain\n");
2541 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2542 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2545 WARN("Failed to create implicit swapchain\n");
2549 This->NumberOfSwapChains = 1;
2550 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2551 if(!This->swapchains) {
2552 ERR("Out of memory!\n");
2555 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2559 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2563 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2565 IWineD3DResource_UnLoad(resource);
2566 IWineD3DResource_Release(resource);
2570 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2574 TRACE("(%p)\n", This);
2576 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2578 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2579 * it was created. Thus make sure a context is active for the glDelete* calls
2581 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2583 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2585 /* Unload resources */
2586 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2588 TRACE("Deleting high order patches\n");
2589 for(i = 0; i < PATCHMAP_SIZE; i++) {
2590 struct list *e1, *e2;
2591 struct WineD3DRectPatch *patch;
2592 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2593 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2594 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2598 /* Delete the palette conversion shader if it is around */
2599 if(This->paletteConversionShader) {
2601 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2603 This->paletteConversionShader = 0;
2606 /* Delete the pbuffer context if there is any */
2607 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2609 /* Delete the mouse cursor texture */
2610 if(This->cursorTexture) {
2612 glDeleteTextures(1, &This->cursorTexture);
2614 This->cursorTexture = 0;
2617 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2618 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2620 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2621 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2624 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2625 * private data, it might contain opengl pointers
2627 if(This->depth_blt_texture) {
2628 glDeleteTextures(1, &This->depth_blt_texture);
2629 This->depth_blt_texture = 0;
2631 if (This->depth_blt_rb) {
2632 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2633 This->depth_blt_rb = 0;
2634 This->depth_blt_rb_w = 0;
2635 This->depth_blt_rb_h = 0;
2638 /* Release the update stateblock */
2639 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2640 if(This->updateStateBlock != This->stateBlock)
2641 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2643 This->updateStateBlock = NULL;
2645 { /* because were not doing proper internal refcounts releasing the primary state block
2646 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2647 to set this->stateBlock = NULL; first */
2648 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2649 This->stateBlock = NULL;
2651 /* Release the stateblock */
2652 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2653 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2657 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2658 This->blitter->free_private(iface);
2659 This->frag_pipe->free_private(iface);
2660 This->shader_backend->shader_free_private(iface);
2662 /* Release the buffers (with sanity checks)*/
2663 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2664 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2665 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2666 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2668 This->stencilBufferTarget = NULL;
2670 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2671 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2672 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2674 TRACE("Setting rendertarget to NULL\n");
2675 This->render_targets[0] = NULL;
2677 if (This->auto_depth_stencil_buffer) {
2678 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2679 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2681 This->auto_depth_stencil_buffer = NULL;
2684 for(i=0; i < This->NumberOfSwapChains; i++) {
2685 TRACE("Releasing the implicit swapchain %d\n", i);
2686 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2687 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2691 HeapFree(GetProcessHeap(), 0, This->swapchains);
2692 This->swapchains = NULL;
2693 This->NumberOfSwapChains = 0;
2695 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2696 HeapFree(GetProcessHeap(), 0, This->palettes);
2697 This->palettes = NULL;
2698 This->NumberOfPalettes = 0;
2700 HeapFree(GetProcessHeap(), 0, This->render_targets);
2701 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2702 This->render_targets = NULL;
2703 This->draw_buffers = NULL;
2705 This->d3d_initialized = FALSE;
2709 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2713 for(i=0; i < This->NumberOfSwapChains; i++) {
2714 TRACE("Releasing the implicit swapchain %d\n", i);
2715 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2716 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2720 HeapFree(GetProcessHeap(), 0, This->swapchains);
2721 This->swapchains = NULL;
2722 This->NumberOfSwapChains = 0;
2726 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2727 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2728 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2730 * There is no way to deactivate thread safety once it is enabled.
2732 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2735 /*For now just store the flag(needed in case of ddraw) */
2736 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2741 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2742 const WINED3DDISPLAYMODE* pMode) {
2744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2746 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2749 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2751 /* Resize the screen even without a window:
2752 * The app could have unset it with SetCooperativeLevel, but not called
2753 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2754 * but we don't have any hwnd
2757 memset(&devmode, 0, sizeof(devmode));
2758 devmode.dmSize = sizeof(devmode);
2759 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2760 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2761 devmode.dmPelsWidth = pMode->Width;
2762 devmode.dmPelsHeight = pMode->Height;
2764 devmode.dmDisplayFrequency = pMode->RefreshRate;
2765 if (pMode->RefreshRate != 0) {
2766 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2769 /* Only change the mode if necessary */
2770 if( (This->ddraw_width == pMode->Width) &&
2771 (This->ddraw_height == pMode->Height) &&
2772 (This->ddraw_format == pMode->Format) &&
2773 (pMode->RefreshRate == 0) ) {
2777 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2778 if (ret != DISP_CHANGE_SUCCESSFUL) {
2779 if(devmode.dmDisplayFrequency != 0) {
2780 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2781 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2782 devmode.dmDisplayFrequency = 0;
2783 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2785 if(ret != DISP_CHANGE_SUCCESSFUL) {
2786 return WINED3DERR_NOTAVAILABLE;
2790 /* Store the new values */
2791 This->ddraw_width = pMode->Width;
2792 This->ddraw_height = pMode->Height;
2793 This->ddraw_format = pMode->Format;
2795 /* And finally clip mouse to our screen */
2796 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2797 ClipCursor(&clip_rc);
2802 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2804 *ppD3D= This->wineD3D;
2805 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2806 IWineD3D_AddRef(*ppD3D);
2810 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2813 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2814 (This->adapter->TextureRam/(1024*1024)),
2815 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2816 /* return simulated texture memory left */
2817 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2821 * Get / Set Stream Source
2823 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2824 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2826 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2827 IWineD3DBuffer *oldSrc;
2829 if (StreamNumber >= MAX_STREAMS) {
2830 WARN("Stream out of range %d\n", StreamNumber);
2831 return WINED3DERR_INVALIDCALL;
2832 } else if(OffsetInBytes & 0x3) {
2833 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2834 return WINED3DERR_INVALIDCALL;
2837 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2838 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2840 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2842 if(oldSrc == pStreamData &&
2843 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2844 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2845 TRACE("Application is setting the old values over, nothing to do\n");
2849 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2851 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2852 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2855 /* Handle recording of state blocks */
2856 if (This->isRecordingState) {
2857 TRACE("Recording... not performing anything\n");
2858 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2859 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2863 if (pStreamData != NULL) {
2864 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2865 IWineD3DBuffer_AddRef(pStreamData);
2867 if (oldSrc != NULL) {
2868 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2869 IWineD3DBuffer_Release(oldSrc);
2872 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2877 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2878 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2882 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2883 This->stateBlock->streamSource[StreamNumber],
2884 This->stateBlock->streamOffset[StreamNumber],
2885 This->stateBlock->streamStride[StreamNumber]);
2887 if (StreamNumber >= MAX_STREAMS) {
2888 WARN("Stream out of range %d\n", StreamNumber);
2889 return WINED3DERR_INVALIDCALL;
2891 *pStream = This->stateBlock->streamSource[StreamNumber];
2892 *pStride = This->stateBlock->streamStride[StreamNumber];
2894 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2897 if (*pStream != NULL) {
2898 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2903 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2905 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2906 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2908 /* Verify input at least in d3d9 this is invalid*/
2909 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2910 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2911 return WINED3DERR_INVALIDCALL;
2913 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2914 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2915 return WINED3DERR_INVALIDCALL;
2918 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2919 return WINED3DERR_INVALIDCALL;
2922 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2923 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2925 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2926 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2928 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2929 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2930 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2936 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2939 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2940 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2942 TRACE("(%p) : returning %d\n", This, *Divider);
2948 * Get / Set & Multiply Transform
2950 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2953 /* Most of this routine, comments included copied from ddraw tree initially: */
2954 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2956 /* Handle recording of state blocks */
2957 if (This->isRecordingState) {
2958 TRACE("Recording... not performing anything\n");
2959 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2960 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2965 * If the new matrix is the same as the current one,
2966 * we cut off any further processing. this seems to be a reasonable
2967 * optimization because as was noticed, some apps (warcraft3 for example)
2968 * tend towards setting the same matrix repeatedly for some reason.
2970 * From here on we assume that the new matrix is different, wherever it matters.
2972 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2973 TRACE("The app is setting the same matrix over again\n");
2976 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2980 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2981 where ViewMat = Camera space, WorldMat = world space.
2983 In OpenGL, camera and world space is combined into GL_MODELVIEW
2984 matrix. The Projection matrix stay projection matrix.
2987 /* Capture the times we can just ignore the change for now */
2988 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2989 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2990 /* Handled by the state manager */
2993 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2997 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2999 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
3000 *pMatrix = This->stateBlock->transforms[State];
3004 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
3005 const WINED3DMATRIX *mat = NULL;
3008 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
3009 * below means it will be recorded in a state block change, but it
3010 * works regardless where it is recorded.
3011 * If this is found to be wrong, change to StateBlock.
3013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3014 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
3016 if (State <= HIGHEST_TRANSFORMSTATE)
3018 mat = &This->updateStateBlock->transforms[State];
3020 FIXME("Unhandled transform state!!\n");
3023 multiply_matrix(&temp, mat, pMatrix);
3025 /* Apply change via set transform - will reapply to eg. lights this way */
3026 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
3032 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
3033 you can reference any indexes you want as long as that number max are enabled at any
3034 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
3035 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
3036 but when recording, just build a chain pretty much of commands to be replayed. */
3038 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
3040 PLIGHTINFOEL *object = NULL;
3041 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3045 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
3047 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
3051 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
3052 return WINED3DERR_INVALIDCALL;
3055 switch(pLight->Type) {
3056 case WINED3DLIGHT_POINT:
3057 case WINED3DLIGHT_SPOT:
3058 case WINED3DLIGHT_PARALLELPOINT:
3059 case WINED3DLIGHT_GLSPOT:
3060 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
3063 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
3064 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
3065 return WINED3DERR_INVALIDCALL;
3069 case WINED3DLIGHT_DIRECTIONAL:
3070 /* Ignores attenuation */
3074 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
3075 return WINED3DERR_INVALIDCALL;
3078 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3079 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3080 if(object->OriginalIndex == Index) break;
3085 TRACE("Adding new light\n");
3086 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
3088 ERR("Out of memory error when allocating a light\n");
3089 return E_OUTOFMEMORY;
3091 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
3092 object->glIndex = -1;
3093 object->OriginalIndex = Index;
3094 object->changed = TRUE;
3097 /* Initialize the object */
3098 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,
3099 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
3100 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
3101 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
3102 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
3103 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
3104 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
3106 /* Save away the information */
3107 object->OriginalParms = *pLight;
3109 switch (pLight->Type) {
3110 case WINED3DLIGHT_POINT:
3112 object->lightPosn[0] = pLight->Position.x;
3113 object->lightPosn[1] = pLight->Position.y;
3114 object->lightPosn[2] = pLight->Position.z;
3115 object->lightPosn[3] = 1.0f;
3116 object->cutoff = 180.0f;
3120 case WINED3DLIGHT_DIRECTIONAL:
3122 object->lightPosn[0] = -pLight->Direction.x;
3123 object->lightPosn[1] = -pLight->Direction.y;
3124 object->lightPosn[2] = -pLight->Direction.z;
3125 object->lightPosn[3] = 0.0;
3126 object->exponent = 0.0f;
3127 object->cutoff = 180.0f;
3130 case WINED3DLIGHT_SPOT:
3132 object->lightPosn[0] = pLight->Position.x;
3133 object->lightPosn[1] = pLight->Position.y;
3134 object->lightPosn[2] = pLight->Position.z;
3135 object->lightPosn[3] = 1.0;
3138 object->lightDirn[0] = pLight->Direction.x;
3139 object->lightDirn[1] = pLight->Direction.y;
3140 object->lightDirn[2] = pLight->Direction.z;
3141 object->lightDirn[3] = 1.0;
3144 * opengl-ish and d3d-ish spot lights use too different models for the
3145 * light "intensity" as a function of the angle towards the main light direction,
3146 * so we only can approximate very roughly.
3147 * however spot lights are rather rarely used in games (if ever used at all).
3148 * furthermore if still used, probably nobody pays attention to such details.
3150 if (pLight->Falloff == 0) {
3151 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3152 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3153 * will always be 1.0 for both of them, and we don't have to care for the
3154 * rest of the rather complex calculation
3156 object->exponent = 0;
3158 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3159 if (rho < 0.0001) rho = 0.0001f;
3160 object->exponent = -0.3/log(cos(rho/2));
3162 if (object->exponent > 128.0) {
3163 object->exponent = 128.0;
3165 object->cutoff = pLight->Phi*90/M_PI;
3171 FIXME("Unrecognized light type %d\n", pLight->Type);
3174 /* Update the live definitions if the light is currently assigned a glIndex */
3175 if (object->glIndex != -1 && !This->isRecordingState) {
3176 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3181 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3182 PLIGHTINFOEL *lightInfo = NULL;
3183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3184 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3186 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3188 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3189 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3190 if(lightInfo->OriginalIndex == Index) break;
3194 if (lightInfo == NULL) {
3195 TRACE("Light information requested but light not defined\n");
3196 return WINED3DERR_INVALIDCALL;
3199 *pLight = lightInfo->OriginalParms;
3204 * Get / Set Light Enable
3205 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3207 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3208 PLIGHTINFOEL *lightInfo = NULL;
3209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3210 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3212 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3214 /* Tests show true = 128...not clear why */
3215 Enable = Enable? 128: 0;
3217 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3218 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3219 if(lightInfo->OriginalIndex == Index) break;
3222 TRACE("Found light: %p\n", lightInfo);
3224 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3225 if (lightInfo == NULL) {
3227 TRACE("Light enabled requested but light not defined, so defining one!\n");
3228 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3230 /* Search for it again! Should be fairly quick as near head of list */
3231 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3232 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3233 if(lightInfo->OriginalIndex == Index) break;
3236 if (lightInfo == NULL) {
3237 FIXME("Adding default lights has failed dismally\n");
3238 return WINED3DERR_INVALIDCALL;
3242 lightInfo->enabledChanged = TRUE;
3244 if(lightInfo->glIndex != -1) {
3245 if(!This->isRecordingState) {
3246 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3249 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3250 lightInfo->glIndex = -1;
3252 TRACE("Light already disabled, nothing to do\n");
3254 lightInfo->enabled = FALSE;
3256 lightInfo->enabled = TRUE;
3257 if (lightInfo->glIndex != -1) {
3259 TRACE("Nothing to do as light was enabled\n");
3262 /* Find a free gl light */
3263 for(i = 0; i < This->maxConcurrentLights; i++) {
3264 if(This->updateStateBlock->activeLights[i] == NULL) {
3265 This->updateStateBlock->activeLights[i] = lightInfo;
3266 lightInfo->glIndex = i;
3270 if(lightInfo->glIndex == -1) {
3271 /* Our tests show that Windows returns D3D_OK in this situation, even with
3272 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3273 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3274 * as well for those lights.
3276 * TODO: Test how this affects rendering
3278 WARN("Too many concurrently active lights\n");
3282 /* i == lightInfo->glIndex */
3283 if(!This->isRecordingState) {
3284 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3292 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3294 PLIGHTINFOEL *lightInfo = NULL;
3295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3297 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3298 TRACE("(%p) : for idx(%d)\n", This, Index);
3300 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3301 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3302 if(lightInfo->OriginalIndex == Index) break;
3306 if (lightInfo == NULL) {
3307 TRACE("Light enabled state requested but light not defined\n");
3308 return WINED3DERR_INVALIDCALL;
3310 /* true is 128 according to SetLightEnable */
3311 *pEnable = lightInfo->enabled ? 128 : 0;
3316 * Get / Set Clip Planes
3318 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3320 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3322 /* Validate Index */
3323 if (Index >= GL_LIMITS(clipplanes)) {
3324 TRACE("Application has requested clipplane this device doesn't support\n");
3325 return WINED3DERR_INVALIDCALL;
3328 This->updateStateBlock->changed.clipplane |= 1 << Index;
3330 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3331 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3332 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3333 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3334 TRACE("Application is setting old values over, nothing to do\n");
3338 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3339 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3340 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3341 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3343 /* Handle recording of state blocks */
3344 if (This->isRecordingState) {
3345 TRACE("Recording... not performing anything\n");
3349 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3354 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3356 TRACE("(%p) : for idx %d\n", This, Index);
3358 /* Validate Index */
3359 if (Index >= GL_LIMITS(clipplanes)) {
3360 TRACE("Application has requested clipplane this device doesn't support\n");
3361 return WINED3DERR_INVALIDCALL;
3364 pPlane[0] = This->stateBlock->clipplane[Index][0];
3365 pPlane[1] = This->stateBlock->clipplane[Index][1];
3366 pPlane[2] = This->stateBlock->clipplane[Index][2];
3367 pPlane[3] = This->stateBlock->clipplane[Index][3];
3372 * Get / Set Clip Plane Status
3373 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3375 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3377 FIXME("(%p) : stub\n", This);
3378 if (NULL == pClipStatus) {
3379 return WINED3DERR_INVALIDCALL;
3381 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3382 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3386 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3388 FIXME("(%p) : stub\n", This);
3389 if (NULL == pClipStatus) {
3390 return WINED3DERR_INVALIDCALL;
3392 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3393 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3398 * Get / Set Material
3400 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3403 This->updateStateBlock->changed.material = TRUE;
3404 This->updateStateBlock->material = *pMaterial;
3406 /* Handle recording of state blocks */
3407 if (This->isRecordingState) {
3408 TRACE("Recording... not performing anything\n");
3412 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3416 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3418 *pMaterial = This->updateStateBlock->material;
3419 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3420 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3421 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3422 pMaterial->Ambient.b, pMaterial->Ambient.a);
3423 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3424 pMaterial->Specular.b, pMaterial->Specular.a);
3425 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3426 pMaterial->Emissive.b, pMaterial->Emissive.a);
3427 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3435 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3437 IWineD3DIndexBuffer *oldIdxs;
3439 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3440 oldIdxs = This->updateStateBlock->pIndexData;
3442 This->updateStateBlock->changed.indices = TRUE;
3443 This->updateStateBlock->pIndexData = pIndexData;
3445 /* Handle recording of state blocks */
3446 if (This->isRecordingState) {
3447 TRACE("Recording... not performing anything\n");
3448 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3449 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3453 if(oldIdxs != pIndexData) {
3454 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3455 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3456 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3461 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3464 *ppIndexData = This->stateBlock->pIndexData;
3466 /* up ref count on ppindexdata */
3468 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3469 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3471 TRACE("(%p) No index data set\n", This);
3473 TRACE("Returning %p\n", *ppIndexData);
3478 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3479 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3481 TRACE("(%p)->(%d)\n", This, BaseIndex);
3483 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3484 TRACE("Application is setting the old value over, nothing to do\n");
3488 This->updateStateBlock->baseVertexIndex = BaseIndex;
3490 if (This->isRecordingState) {
3491 TRACE("Recording... not performing anything\n");
3494 /* The base vertex index affects the stream sources */
3495 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3499 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3500 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3501 TRACE("(%p) : base_index %p\n", This, base_index);
3503 *base_index = This->stateBlock->baseVertexIndex;
3505 TRACE("Returning %u\n", *base_index);
3511 * Get / Set Viewports
3513 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3516 TRACE("(%p)\n", This);
3517 This->updateStateBlock->changed.viewport = TRUE;
3518 This->updateStateBlock->viewport = *pViewport;
3520 /* Handle recording of state blocks */
3521 if (This->isRecordingState) {
3522 TRACE("Recording... not performing anything\n");
3526 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3527 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3529 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3534 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3536 TRACE("(%p)\n", This);
3537 *pViewport = This->stateBlock->viewport;
3542 * Get / Set Render States
3543 * TODO: Verify against dx9 definitions
3545 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3548 DWORD oldValue = This->stateBlock->renderState[State];
3550 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3552 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3553 This->updateStateBlock->renderState[State] = Value;
3555 /* Handle recording of state blocks */
3556 if (This->isRecordingState) {
3557 TRACE("Recording... not performing anything\n");
3561 /* Compared here and not before the assignment to allow proper stateblock recording */
3562 if(Value == oldValue) {
3563 TRACE("Application is setting the old value over, nothing to do\n");
3565 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3571 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3573 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3574 *pValue = This->stateBlock->renderState[State];
3579 * Get / Set Sampler States
3580 * TODO: Verify against dx9 definitions
3583 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3587 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3588 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3590 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3591 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3594 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3595 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3596 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3599 * SetSampler is designed to allow for more than the standard up to 8 textures
3600 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3601 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3603 * http://developer.nvidia.com/object/General_FAQ.html#t6
3605 * There are two new settings for GForce
3607 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3608 * and the texture one:
3609 * GL_MAX_TEXTURE_COORDS_ARB.
3610 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3613 oldValue = This->stateBlock->samplerState[Sampler][Type];
3614 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3615 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3617 /* Handle recording of state blocks */
3618 if (This->isRecordingState) {
3619 TRACE("Recording... not performing anything\n");
3623 if(oldValue == Value) {
3624 TRACE("Application is setting the old value over, nothing to do\n");
3628 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3633 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3636 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3637 This, Sampler, debug_d3dsamplerstate(Type), Type);
3639 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3640 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3643 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3644 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3645 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3647 *Value = This->stateBlock->samplerState[Sampler][Type];
3648 TRACE("(%p) : Returning %#x\n", This, *Value);
3653 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3656 This->updateStateBlock->changed.scissorRect = TRUE;
3657 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3658 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3661 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3663 if(This->isRecordingState) {
3664 TRACE("Recording... not performing anything\n");
3668 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3673 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3676 *pRect = This->updateStateBlock->scissorRect;
3677 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3681 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3683 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3685 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3687 This->updateStateBlock->vertexDecl = pDecl;
3688 This->updateStateBlock->changed.vertexDecl = TRUE;
3690 if (This->isRecordingState) {
3691 TRACE("Recording... not performing anything\n");
3693 } else if(pDecl == oldDecl) {
3694 /* Checked after the assignment to allow proper stateblock recording */
3695 TRACE("Application is setting the old declaration over, nothing to do\n");
3699 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3703 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3706 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3708 *ppDecl = This->stateBlock->vertexDecl;
3709 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3713 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3715 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3717 This->updateStateBlock->vertexShader = pShader;
3718 This->updateStateBlock->changed.vertexShader = TRUE;
3720 if (This->isRecordingState) {
3721 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3722 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3723 TRACE("Recording... not performing anything\n");
3725 } else if(oldShader == pShader) {
3726 /* Checked here to allow proper stateblock recording */
3727 TRACE("App is setting the old shader over, nothing to do\n");
3731 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3732 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3733 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3735 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3740 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3743 if (NULL == ppShader) {
3744 return WINED3DERR_INVALIDCALL;
3746 *ppShader = This->stateBlock->vertexShader;
3747 if( NULL != *ppShader)
3748 IWineD3DVertexShader_AddRef(*ppShader);
3750 TRACE("(%p) : returning %p\n", This, *ppShader);
3754 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3755 IWineD3DDevice *iface,
3757 CONST BOOL *srcData,
3760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3761 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3763 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3764 iface, srcData, start, count);
3766 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3768 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3769 for (i = 0; i < cnt; i++)
3770 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3772 for (i = start; i < cnt + start; ++i) {
3773 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3776 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3781 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3782 IWineD3DDevice *iface,
3787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3788 int cnt = min(count, MAX_CONST_B - start);
3790 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3791 iface, dstData, start, count);
3793 if (dstData == NULL || cnt < 0)
3794 return WINED3DERR_INVALIDCALL;
3796 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3800 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3801 IWineD3DDevice *iface,
3806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3807 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3809 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3810 iface, srcData, start, count);
3812 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3814 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3815 for (i = 0; i < cnt; i++)
3816 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3817 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3819 for (i = start; i < cnt + start; ++i) {
3820 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3823 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3828 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3829 IWineD3DDevice *iface,
3834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3835 int cnt = min(count, MAX_CONST_I - start);
3837 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3838 iface, dstData, start, count);
3840 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3841 return WINED3DERR_INVALIDCALL;
3843 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3847 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3848 IWineD3DDevice *iface,
3850 CONST float *srcData,
3853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3856 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3857 iface, srcData, start, count);
3859 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3860 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3861 return WINED3DERR_INVALIDCALL;
3863 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3865 for (i = 0; i < count; i++)
3866 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3867 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3870 if (!This->isRecordingState)
3872 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3873 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3876 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3877 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3882 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3883 IWineD3DDevice *iface,
3888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3889 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3891 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3892 iface, dstData, start, count);
3894 if (dstData == NULL || cnt < 0)
3895 return WINED3DERR_INVALIDCALL;
3897 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3901 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3903 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3905 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3909 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3910 int i = This->rev_tex_unit_map[unit];
3911 int j = This->texUnitMap[stage];
3913 This->texUnitMap[stage] = unit;
3914 if (i != -1 && i != stage) {
3915 This->texUnitMap[i] = -1;
3918 This->rev_tex_unit_map[unit] = stage;
3919 if (j != -1 && j != unit) {
3920 This->rev_tex_unit_map[j] = -1;
3924 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3927 This->fixed_function_usage_map = 0;
3928 for (i = 0; i < MAX_TEXTURES; ++i) {
3929 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3930 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3931 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3932 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3933 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3934 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3935 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3936 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3938 if (color_op == WINED3DTOP_DISABLE) {
3939 /* Not used, and disable higher stages */
3943 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3944 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3945 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3946 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3947 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3948 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3949 This->fixed_function_usage_map |= (1 << i);
3952 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3953 This->fixed_function_usage_map |= (1 << (i + 1));
3958 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3959 unsigned int i, tex;
3962 device_update_fixed_function_usage_map(This);
3963 ffu_map = This->fixed_function_usage_map;
3965 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3966 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3967 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3969 if (!(ffu_map & 1)) continue;
3971 if (This->texUnitMap[i] != i) {
3972 device_map_stage(This, i, i);
3973 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3974 markTextureStagesDirty(This, i);
3980 /* Now work out the mapping */
3982 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3984 if (!(ffu_map & 1)) continue;
3986 if (This->texUnitMap[i] != tex) {
3987 device_map_stage(This, i, tex);
3988 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3989 markTextureStagesDirty(This, i);
3996 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3997 const DWORD *sampler_tokens =
3998 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
4001 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
4002 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
4003 device_map_stage(This, i, i);
4004 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4005 if (i < MAX_TEXTURES) {
4006 markTextureStagesDirty(This, i);
4012 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
4013 const DWORD *vshader_sampler_tokens, int unit)
4015 int current_mapping = This->rev_tex_unit_map[unit];
4017 if (current_mapping == -1) {
4018 /* Not currently used */
4022 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
4023 /* Used by a fragment sampler */
4025 if (!pshader_sampler_tokens) {
4026 /* No pixel shader, check fixed function */
4027 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
4030 /* Pixel shader, check the shader's sampler map */
4031 return !pshader_sampler_tokens[current_mapping];
4034 /* Used by a vertex sampler */
4035 return !vshader_sampler_tokens[current_mapping];
4038 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
4039 const DWORD *vshader_sampler_tokens =
4040 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
4041 const DWORD *pshader_sampler_tokens = NULL;
4042 int start = GL_LIMITS(combined_samplers) - 1;
4046 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
4048 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
4049 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
4050 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
4053 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
4054 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
4055 if (vshader_sampler_tokens[i]) {
4056 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
4058 /* Already mapped somewhere */
4062 while (start >= 0) {
4063 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
4064 device_map_stage(This, vsampler_idx, start);
4065 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
4077 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
4078 BOOL vs = use_vs(This->stateBlock);
4079 BOOL ps = use_ps(This->stateBlock);
4082 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
4083 * that would be really messy and require shader recompilation
4084 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
4085 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
4088 device_map_psamplers(This);
4090 device_map_fixed_function_samplers(This);
4094 device_map_vsamplers(This, ps);
4098 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4100 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4101 This->updateStateBlock->pixelShader = pShader;
4102 This->updateStateBlock->changed.pixelShader = TRUE;
4104 /* Handle recording of state blocks */
4105 if (This->isRecordingState) {
4106 TRACE("Recording... not performing anything\n");
4109 if (This->isRecordingState) {
4110 TRACE("Recording... not performing anything\n");
4111 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4112 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4116 if(pShader == oldShader) {
4117 TRACE("App is setting the old pixel shader over, nothing to do\n");
4121 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4122 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4124 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4125 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4130 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4133 if (NULL == ppShader) {
4134 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4135 return WINED3DERR_INVALIDCALL;
4138 *ppShader = This->stateBlock->pixelShader;
4139 if (NULL != *ppShader) {
4140 IWineD3DPixelShader_AddRef(*ppShader);
4142 TRACE("(%p) : returning %p\n", This, *ppShader);
4146 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4147 IWineD3DDevice *iface,
4149 CONST BOOL *srcData,
4152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4153 unsigned int i, cnt = min(count, MAX_CONST_B - start);
4155 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4156 iface, srcData, start, count);
4158 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
4160 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4161 for (i = 0; i < cnt; i++)
4162 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4164 for (i = start; i < cnt + start; ++i) {
4165 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4168 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4173 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4174 IWineD3DDevice *iface,
4179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4180 int cnt = min(count, MAX_CONST_B - start);
4182 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4183 iface, dstData, start, count);
4185 if (dstData == NULL || cnt < 0)
4186 return WINED3DERR_INVALIDCALL;
4188 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4192 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4193 IWineD3DDevice *iface,
4198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4199 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4201 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4202 iface, srcData, start, count);
4204 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4206 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4207 for (i = 0; i < cnt; i++)
4208 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4209 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4211 for (i = start; i < cnt + start; ++i) {
4212 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4215 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4220 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4221 IWineD3DDevice *iface,
4226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4227 int cnt = min(count, MAX_CONST_I - start);
4229 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4230 iface, dstData, start, count);
4232 if (dstData == NULL || cnt < 0)
4233 return WINED3DERR_INVALIDCALL;
4235 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4239 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4240 IWineD3DDevice *iface,
4242 CONST float *srcData,
4245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4248 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4249 iface, srcData, start, count);
4251 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4252 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4253 return WINED3DERR_INVALIDCALL;
4255 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4257 for (i = 0; i < count; i++)
4258 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4259 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4262 if (!This->isRecordingState)
4264 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4265 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4268 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4269 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4274 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4275 IWineD3DDevice *iface,
4280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4281 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4283 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4284 iface, dstData, start, count);
4286 if (dstData == NULL || cnt < 0)
4287 return WINED3DERR_INVALIDCALL;
4289 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4293 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4294 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4295 const WineDirect3DVertexStridedData *lpStrideData, struct wined3d_buffer *dest, DWORD dwFlags)
4297 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4299 DWORD DestFVF = dest->fvf;
4301 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4305 if (lpStrideData->u.s.normal.lpData) {
4306 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4309 if (lpStrideData->u.s.position.lpData == NULL) {
4310 ERR("Source has no position mask\n");
4311 return WINED3DERR_INVALIDCALL;
4314 /* We might access VBOs from this code, so hold the lock */
4317 if (dest->resource.allocatedMemory == NULL) {
4318 /* This may happen if we do direct locking into a vbo. Unlikely,
4319 * but theoretically possible(ddraw processvertices test)
4321 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4322 if(!dest->resource.allocatedMemory) {
4324 ERR("Out of memory\n");
4325 return E_OUTOFMEMORY;
4327 if (dest->buffer_object)
4330 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4331 checkGLcall("glBindBufferARB");
4332 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4334 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4336 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4337 checkGLcall("glUnmapBufferARB");
4341 /* Get a pointer into the destination vbo(create one if none exists) and
4342 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4344 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4346 dest->flags |= WINED3D_BUFFER_CREATEBO;
4347 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4350 if (dest->buffer_object)
4352 unsigned char extrabytes = 0;
4353 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4354 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4355 * this may write 4 extra bytes beyond the area that should be written
4357 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4358 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4359 if(!dest_conv_addr) {
4360 ERR("Out of memory\n");
4361 /* Continue without storing converted vertices */
4363 dest_conv = dest_conv_addr;
4367 * a) WINED3DRS_CLIPPING is enabled
4368 * b) WINED3DVOP_CLIP is passed
4370 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4371 static BOOL warned = FALSE;
4373 * The clipping code is not quite correct. Some things need
4374 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4375 * so disable clipping for now.
4376 * (The graphics in Half-Life are broken, and my processvertices
4377 * test crashes with IDirect3DDevice3)
4383 FIXME("Clipping is broken and disabled for now\n");
4385 } else doClip = FALSE;
4386 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4388 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4391 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4392 WINED3DTS_PROJECTION,
4394 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4395 WINED3DTS_WORLDMATRIX(0),
4398 TRACE("View mat:\n");
4399 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);
4400 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);
4401 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);
4402 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);
4404 TRACE("Proj mat:\n");
4405 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);
4406 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);
4407 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);
4408 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);
4410 TRACE("World mat:\n");
4411 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);
4412 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);
4413 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);
4414 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);
4416 /* Get the viewport */
4417 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4418 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4419 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4421 multiply_matrix(&mat,&view_mat,&world_mat);
4422 multiply_matrix(&mat,&proj_mat,&mat);
4424 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4426 for (i = 0; i < dwCount; i+= 1) {
4427 unsigned int tex_index;
4429 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4430 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4431 /* The position first */
4433 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4435 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4437 /* Multiplication with world, view and projection matrix */
4438 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);
4439 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);
4440 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);
4441 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);
4443 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4445 /* WARNING: The following things are taken from d3d7 and were not yet checked
4446 * against d3d8 or d3d9!
4449 /* Clipping conditions: From msdn
4451 * A vertex is clipped if it does not match the following requirements
4455 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4457 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4458 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4463 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4464 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4467 /* "Normal" viewport transformation (not clipped)
4468 * 1) The values are divided by rhw
4469 * 2) The y axis is negative, so multiply it with -1
4470 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4471 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4472 * 4) Multiply x with Width/2 and add Width/2
4473 * 5) The same for the height
4474 * 6) Add the viewpoint X and Y to the 2D coordinates and
4475 * The minimum Z value to z
4476 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4478 * Well, basically it's simply a linear transformation into viewport
4490 z *= vp.MaxZ - vp.MinZ;
4492 x += vp.Width / 2 + vp.X;
4493 y += vp.Height / 2 + vp.Y;
4498 /* That vertex got clipped
4499 * Contrary to OpenGL it is not dropped completely, it just
4500 * undergoes a different calculation.
4502 TRACE("Vertex got clipped\n");
4509 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4510 * outside of the main vertex buffer memory. That needs some more
4515 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4518 ( (float *) dest_ptr)[0] = x;
4519 ( (float *) dest_ptr)[1] = y;
4520 ( (float *) dest_ptr)[2] = z;
4521 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4523 dest_ptr += 3 * sizeof(float);
4525 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4526 dest_ptr += sizeof(float);
4531 ( (float *) dest_conv)[0] = x * w;
4532 ( (float *) dest_conv)[1] = y * w;
4533 ( (float *) dest_conv)[2] = z * w;
4534 ( (float *) dest_conv)[3] = w;
4536 dest_conv += 3 * sizeof(float);
4538 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4539 dest_conv += sizeof(float);
4543 if (DestFVF & WINED3DFVF_PSIZE) {
4544 dest_ptr += sizeof(DWORD);
4545 if(dest_conv) dest_conv += sizeof(DWORD);
4547 if (DestFVF & WINED3DFVF_NORMAL) {
4548 const float *normal =
4549 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4550 /* AFAIK this should go into the lighting information */
4551 FIXME("Didn't expect the destination to have a normal\n");
4552 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4554 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4558 if (DestFVF & WINED3DFVF_DIFFUSE) {
4559 const DWORD *color_d =
4560 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4562 static BOOL warned = FALSE;
4565 ERR("No diffuse color in source, but destination has one\n");
4569 *( (DWORD *) dest_ptr) = 0xffffffff;
4570 dest_ptr += sizeof(DWORD);
4573 *( (DWORD *) dest_conv) = 0xffffffff;
4574 dest_conv += sizeof(DWORD);
4578 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4580 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4581 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4582 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4583 dest_conv += sizeof(DWORD);
4588 if (DestFVF & WINED3DFVF_SPECULAR) {
4589 /* What's the color value in the feedback buffer? */
4590 const DWORD *color_s =
4591 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4593 static BOOL warned = FALSE;
4596 ERR("No specular color in source, but destination has one\n");
4600 *( (DWORD *) dest_ptr) = 0xFF000000;
4601 dest_ptr += sizeof(DWORD);
4604 *( (DWORD *) dest_conv) = 0xFF000000;
4605 dest_conv += sizeof(DWORD);
4609 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4611 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4612 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4613 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4614 dest_conv += sizeof(DWORD);
4619 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4620 const float *tex_coord =
4621 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4622 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4624 ERR("No source texture, but destination requests one\n");
4625 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4626 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4629 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4631 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4638 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4639 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4640 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4641 dwCount * get_flexible_vertex_size(DestFVF),
4643 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4644 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4651 #undef copy_and_next
4653 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4654 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags)
4656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4657 WineDirect3DVertexStridedData strided;
4658 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4659 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4662 ERR("Output vertex declaration not implemented yet\n");
4665 /* Need any context to write to the vbo. */
4666 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4668 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4669 * control the streamIsUP flag, thus restore it afterwards.
4671 This->stateBlock->streamIsUP = FALSE;
4672 memset(&strided, 0, sizeof(strided));
4673 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4674 This->stateBlock->streamIsUP = streamWasUP;
4676 if(vbo || SrcStartIndex) {
4678 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4679 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4681 * Also get the start index in, but only loop over all elements if there's something to add at all.
4683 #define FIXSRC(type) \
4684 if(strided.u.s.type.VBO) { \
4685 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4686 strided.u.s.type.VBO = 0; \
4687 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4689 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object)); \
4690 vb->buffer_object = 0; \
4693 if(strided.u.s.type.lpData) { \
4694 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4697 FIXSRC(blendWeights);
4698 FIXSRC(blendMatrixIndices);
4703 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4704 FIXSRC(texCoords[i]);
4717 return process_vertices_strided(This, DestIndex, VertexCount, &strided,
4718 (struct wined3d_buffer *)pDestBuffer, Flags);
4722 * Get / Set Texture Stage States
4723 * TODO: Verify against dx9 definitions
4725 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4727 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4729 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4731 if (Stage >= MAX_TEXTURES) {
4732 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4736 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4737 This->updateStateBlock->textureState[Stage][Type] = Value;
4739 if (This->isRecordingState) {
4740 TRACE("Recording... not performing anything\n");
4744 /* Checked after the assignments to allow proper stateblock recording */
4745 if(oldValue == Value) {
4746 TRACE("App is setting the old value over, nothing to do\n");
4750 if(Stage > This->stateBlock->lowest_disabled_stage &&
4751 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4752 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4753 * Changes in other states are important on disabled stages too
4758 if(Type == WINED3DTSS_COLOROP) {
4761 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4762 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4763 * they have to be disabled
4765 * The current stage is dirtified below.
4767 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4768 TRACE("Additionally dirtifying stage %u\n", i);
4769 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4771 This->stateBlock->lowest_disabled_stage = Stage;
4772 TRACE("New lowest disabled: %u\n", Stage);
4773 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4774 /* Previously disabled stage enabled. Stages above it may need enabling
4775 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4776 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4778 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4781 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4782 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4785 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4786 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4788 This->stateBlock->lowest_disabled_stage = i;
4789 TRACE("New lowest disabled: %u\n", i);
4793 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4798 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4800 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4801 *pValue = This->updateStateBlock->textureState[Stage][Type];
4808 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4810 IWineD3DBaseTexture *oldTexture;
4812 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4814 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4815 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4818 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4819 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4820 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4823 oldTexture = This->updateStateBlock->textures[Stage];
4825 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4826 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4828 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4829 return WINED3DERR_INVALIDCALL;
4832 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4833 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4835 This->updateStateBlock->changed.textures |= 1 << Stage;
4836 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4837 This->updateStateBlock->textures[Stage] = pTexture;
4839 /* Handle recording of state blocks */
4840 if (This->isRecordingState) {
4841 TRACE("Recording... not performing anything\n");
4845 if(oldTexture == pTexture) {
4846 TRACE("App is setting the same texture again, nothing to do\n");
4850 /** NOTE: MSDN says that setTexture increases the reference count,
4851 * and that the application must set the texture back to null (or have a leaky application),
4852 * This means we should pass the refcount up to the parent
4853 *******************************/
4854 if (NULL != This->updateStateBlock->textures[Stage]) {
4855 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4856 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4857 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4859 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4861 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4863 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4866 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4867 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4868 * so the COLOROP and ALPHAOP have to be dirtified.
4870 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4871 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4873 if(bindCount == 1) {
4874 new->baseTexture.sampler = Stage;
4876 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4880 if (NULL != oldTexture) {
4881 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4882 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4884 IWineD3DBaseTexture_Release(oldTexture);
4885 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4886 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4887 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4890 if(bindCount && old->baseTexture.sampler == Stage) {
4892 /* Have to do a search for the other sampler(s) where the texture is bound to
4893 * Shouldn't happen as long as apps bind a texture only to one stage
4895 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4896 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4897 if(This->updateStateBlock->textures[i] == oldTexture) {
4898 old->baseTexture.sampler = i;
4905 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4910 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4913 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4915 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4916 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4919 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4920 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4921 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4924 *ppTexture=This->stateBlock->textures[Stage];
4926 IWineD3DBaseTexture_AddRef(*ppTexture);
4928 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4936 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4937 IWineD3DSurface **ppBackBuffer) {
4938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4939 IWineD3DSwapChain *swapChain;
4942 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4944 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4945 if (hr == WINED3D_OK) {
4946 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4947 IWineD3DSwapChain_Release(swapChain);
4949 *ppBackBuffer = NULL;
4954 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4956 WARN("(%p) : stub, calling idirect3d for now\n", This);
4957 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4960 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4962 IWineD3DSwapChain *swapChain;
4965 if(iSwapChain > 0) {
4966 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4967 if (hr == WINED3D_OK) {
4968 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4969 IWineD3DSwapChain_Release(swapChain);
4971 FIXME("(%p) Error getting display mode\n", This);
4974 /* Don't read the real display mode,
4975 but return the stored mode instead. X11 can't change the color
4976 depth, and some apps are pretty angry if they SetDisplayMode from
4977 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4979 Also don't relay to the swapchain because with ddraw it's possible
4980 that there isn't a swapchain at all */
4981 pMode->Width = This->ddraw_width;
4982 pMode->Height = This->ddraw_height;
4983 pMode->Format = This->ddraw_format;
4984 pMode->RefreshRate = 0;
4992 * Stateblock related functions
4995 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4997 IWineD3DStateBlock *stateblock;
5000 TRACE("(%p)\n", This);
5002 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
5004 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
5005 if (FAILED(hr)) return hr;
5007 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5008 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
5009 This->isRecordingState = TRUE;
5011 TRACE("(%p) recording stateblock %p\n", This, stateblock);
5016 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5019 IWineD3DStateBlockImpl *object = This->updateStateBlock;
5021 if (!This->isRecordingState) {
5022 WARN("(%p) not recording! returning error\n", This);
5023 *ppStateBlock = NULL;
5024 return WINED3DERR_INVALIDCALL;
5027 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
5029 DWORD map = object->changed.renderState[i];
5030 for (j = 0; map; map >>= 1, ++j)
5032 if (!(map & 1)) continue;
5034 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
5038 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
5040 DWORD map = object->changed.transform[i];
5041 for (j = 0; map; map >>= 1, ++j)
5043 if (!(map & 1)) continue;
5045 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
5048 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
5049 if(object->changed.vertexShaderConstantsF[i]) {
5050 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
5051 object->num_contained_vs_consts_f++;
5054 for(i = 0; i < MAX_CONST_I; i++) {
5055 if (object->changed.vertexShaderConstantsI & (1 << i))
5057 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
5058 object->num_contained_vs_consts_i++;
5061 for(i = 0; i < MAX_CONST_B; i++) {
5062 if (object->changed.vertexShaderConstantsB & (1 << i))
5064 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
5065 object->num_contained_vs_consts_b++;
5068 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
5070 if (object->changed.pixelShaderConstantsF[i])
5072 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
5073 ++object->num_contained_ps_consts_f;
5076 for(i = 0; i < MAX_CONST_I; i++) {
5077 if (object->changed.pixelShaderConstantsI & (1 << i))
5079 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
5080 object->num_contained_ps_consts_i++;
5083 for(i = 0; i < MAX_CONST_B; i++) {
5084 if (object->changed.pixelShaderConstantsB & (1 << i))
5086 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
5087 object->num_contained_ps_consts_b++;
5090 for(i = 0; i < MAX_TEXTURES; i++) {
5091 DWORD map = object->changed.textureState[i];
5093 for(j = 0; map; map >>= 1, ++j)
5095 if (!(map & 1)) continue;
5097 object->contained_tss_states[object->num_contained_tss_states].stage = i;
5098 object->contained_tss_states[object->num_contained_tss_states].state = j;
5099 ++object->num_contained_tss_states;
5102 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
5103 DWORD map = object->changed.samplerState[i];
5105 for (j = 0; map; map >>= 1, ++j)
5107 if (!(map & 1)) continue;
5109 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
5110 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
5111 ++object->num_contained_sampler_states;
5115 *ppStateBlock = (IWineD3DStateBlock*) object;
5116 This->isRecordingState = FALSE;
5117 This->updateStateBlock = This->stateBlock;
5118 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5119 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5120 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5125 * Scene related functions
5127 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5128 /* At the moment we have no need for any functionality at the beginning
5130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5131 TRACE("(%p)\n", This);
5134 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
5135 return WINED3DERR_INVALIDCALL;
5137 This->inScene = TRUE;
5141 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5143 TRACE("(%p)\n", This);
5145 if(!This->inScene) {
5146 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
5147 return WINED3DERR_INVALIDCALL;
5150 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5151 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5153 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5157 This->inScene = FALSE;
5161 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5162 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5163 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5165 IWineD3DSwapChain *swapChain = NULL;
5167 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5169 TRACE("(%p) Presenting the frame\n", This);
5171 for(i = 0 ; i < swapchains ; i ++) {
5173 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5174 TRACE("presentinng chain %d, %p\n", i, swapChain);
5175 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5176 IWineD3DSwapChain_Release(swapChain);
5182 /* Not called from the VTable (internal subroutine) */
5183 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5184 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5185 float Z, DWORD Stencil) {
5186 GLbitfield glMask = 0;
5188 WINED3DRECT curRect;
5190 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5191 UINT drawable_width, drawable_height;
5192 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5193 IWineD3DSwapChainImpl *swapchain = NULL;
5195 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5196 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5197 * for the cleared parts, and the untouched parts.
5199 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5200 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5201 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5202 * checking all this if the dest surface is in the drawable anyway.
5204 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5206 if(vp->X != 0 || vp->Y != 0 ||
5207 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5208 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5211 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5212 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5213 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5214 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5215 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5218 if(Count > 0 && pRects && (
5219 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5220 pRects[0].x2 < target->currentDesc.Width ||
5221 pRects[0].y2 < target->currentDesc.Height)) {
5222 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5229 target->get_drawable_size(target, &drawable_width, &drawable_height);
5231 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5234 /* Only set the values up once, as they are not changing */
5235 if (Flags & WINED3DCLEAR_STENCIL) {
5236 glClearStencil(Stencil);
5237 checkGLcall("glClearStencil");
5238 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5239 glStencilMask(0xFFFFFFFF);
5242 if (Flags & WINED3DCLEAR_ZBUFFER) {
5243 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5244 glDepthMask(GL_TRUE);
5246 checkGLcall("glClearDepth");
5247 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5248 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5250 if (vp->X != 0 || vp->Y != 0 ||
5251 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5252 surface_load_ds_location(This->stencilBufferTarget, location);
5254 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5255 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5256 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5257 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5258 surface_load_ds_location(This->stencilBufferTarget, location);
5260 else if (Count > 0 && pRects && (
5261 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5262 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5263 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5264 surface_load_ds_location(This->stencilBufferTarget, location);
5268 if (Flags & WINED3DCLEAR_TARGET) {
5269 TRACE("Clearing screen with glClear to color %x\n", Color);
5270 glClearColor(D3DCOLOR_R(Color),
5274 checkGLcall("glClearColor");
5276 /* Clear ALL colors! */
5277 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5278 glMask = glMask | GL_COLOR_BUFFER_BIT;
5281 vp_rect.left = vp->X;
5282 vp_rect.top = vp->Y;
5283 vp_rect.right = vp->X + vp->Width;
5284 vp_rect.bottom = vp->Y + vp->Height;
5285 if (!(Count > 0 && pRects)) {
5286 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5287 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5289 if(This->render_offscreen) {
5290 glScissor(vp_rect.left, vp_rect.top,
5291 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5293 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5294 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5296 checkGLcall("glScissor");
5298 checkGLcall("glClear");
5300 /* Now process each rect in turn */
5301 for (i = 0; i < Count; i++) {
5302 /* Note gl uses lower left, width/height */
5303 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5304 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5305 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5307 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5308 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5309 curRect.x1, (target->currentDesc.Height - curRect.y2),
5310 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5312 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5313 * The rectangle is not cleared, no error is returned, but further rectanlges are
5314 * still cleared if they are valid
5316 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5317 TRACE("Rectangle with negative dimensions, ignoring\n");
5321 if(This->render_offscreen) {
5322 glScissor(curRect.x1, curRect.y1,
5323 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5325 glScissor(curRect.x1, drawable_height - curRect.y2,
5326 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5328 checkGLcall("glScissor");
5331 checkGLcall("glClear");
5335 /* Restore the old values (why..?) */
5336 if (Flags & WINED3DCLEAR_STENCIL) {
5337 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5339 if (Flags & WINED3DCLEAR_TARGET) {
5340 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5341 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5342 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5343 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5344 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5346 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5347 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5349 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5351 if (Flags & WINED3DCLEAR_ZBUFFER) {
5352 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5353 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5354 surface_modify_ds_location(This->stencilBufferTarget, location);
5359 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5360 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5363 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5369 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5370 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5371 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5372 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5374 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5375 Count, pRects, Flags, Color, Z, Stencil);
5377 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5378 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5379 /* TODO: What about depth stencil buffers without stencil bits? */
5380 return WINED3DERR_INVALIDCALL;
5383 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5390 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5391 WINED3DPRIMITIVETYPE primitive_type)
5393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5395 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5397 This->updateStateBlock->changed.primitive_type = TRUE;
5398 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5401 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5402 WINED3DPRIMITIVETYPE *primitive_type)
5404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5406 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5408 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5410 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5413 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5417 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5419 if(!This->stateBlock->vertexDecl) {
5420 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5421 return WINED3DERR_INVALIDCALL;
5424 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5425 if(This->stateBlock->streamIsUP) {
5426 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5427 This->stateBlock->streamIsUP = FALSE;
5430 if(This->stateBlock->loadBaseVertexIndex != 0) {
5431 This->stateBlock->loadBaseVertexIndex = 0;
5432 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5434 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5435 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5436 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5440 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5441 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5445 IWineD3DIndexBuffer *pIB;
5446 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5449 pIB = This->stateBlock->pIndexData;
5451 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5452 * without an index buffer set. (The first time at least...)
5453 * D3D8 simply dies, but I doubt it can do much harm to return
5454 * D3DERR_INVALIDCALL there as well. */
5455 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5456 return WINED3DERR_INVALIDCALL;
5459 if(!This->stateBlock->vertexDecl) {
5460 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5461 return WINED3DERR_INVALIDCALL;
5464 if(This->stateBlock->streamIsUP) {
5465 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5466 This->stateBlock->streamIsUP = FALSE;
5468 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5470 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5471 This, minIndex, NumVertices, startIndex, index_count);
5473 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5474 if (IdxBufDsc.Format == WINED3DFMT_R16_UINT) {
5480 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5481 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5485 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5486 vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5491 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5492 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5497 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5498 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5500 if(!This->stateBlock->vertexDecl) {
5501 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5502 return WINED3DERR_INVALIDCALL;
5505 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5506 vb = This->stateBlock->streamSource[0];
5507 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5508 if (vb) IWineD3DBuffer_Release(vb);
5509 This->stateBlock->streamOffset[0] = 0;
5510 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5511 This->stateBlock->streamIsUP = TRUE;
5512 This->stateBlock->loadBaseVertexIndex = 0;
5514 /* TODO: Only mark dirty if drawing from a different UP address */
5515 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5517 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5518 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5520 /* MSDN specifies stream zero settings must be set to NULL */
5521 This->stateBlock->streamStride[0] = 0;
5522 This->stateBlock->streamSource[0] = NULL;
5524 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5525 * the new stream sources or use UP drawing again
5530 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5531 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5532 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5537 IWineD3DIndexBuffer *ib;
5539 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5540 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5541 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5543 if(!This->stateBlock->vertexDecl) {
5544 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5545 return WINED3DERR_INVALIDCALL;
5548 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5554 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5555 vb = This->stateBlock->streamSource[0];
5556 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5557 if (vb) IWineD3DBuffer_Release(vb);
5558 This->stateBlock->streamIsUP = TRUE;
5559 This->stateBlock->streamOffset[0] = 0;
5560 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5562 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5563 This->stateBlock->baseVertexIndex = 0;
5564 This->stateBlock->loadBaseVertexIndex = 0;
5565 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5566 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5567 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5569 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5570 idxStride, pIndexData, MinVertexIndex);
5572 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5573 This->stateBlock->streamSource[0] = NULL;
5574 This->stateBlock->streamStride[0] = 0;
5575 ib = This->stateBlock->pIndexData;
5577 IWineD3DIndexBuffer_Release(ib);
5578 This->stateBlock->pIndexData = NULL;
5580 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5581 * SetStreamSource to specify a vertex buffer
5587 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5588 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5592 /* Mark the state dirty until we have nicer tracking
5593 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5596 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5597 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5598 This->stateBlock->baseVertexIndex = 0;
5599 This->up_strided = DrawPrimStrideData;
5600 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5601 This->up_strided = NULL;
5605 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5606 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5607 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5610 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5612 /* Mark the state dirty until we have nicer tracking
5613 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5616 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5617 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5618 This->stateBlock->streamIsUP = TRUE;
5619 This->stateBlock->baseVertexIndex = 0;
5620 This->up_strided = DrawPrimStrideData;
5621 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5622 This->up_strided = NULL;
5626 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5627 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5628 * not callable by the app directly no parameter validation checks are needed here.
5630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5631 WINED3DLOCKED_BOX src;
5632 WINED3DLOCKED_BOX dst;
5634 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5636 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5637 * dirtification to improve loading performance.
5639 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5640 if(FAILED(hr)) return hr;
5641 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5643 IWineD3DVolume_UnlockBox(pSourceVolume);
5647 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5649 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5651 IWineD3DVolume_UnlockBox(pSourceVolume);
5653 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5658 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5659 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5661 HRESULT hr = WINED3D_OK;
5662 WINED3DRESOURCETYPE sourceType;
5663 WINED3DRESOURCETYPE destinationType;
5666 /* TODO: think about moving the code into IWineD3DBaseTexture */
5668 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5670 /* verify that the source and destination textures aren't NULL */
5671 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5672 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5673 This, pSourceTexture, pDestinationTexture);
5674 hr = WINED3DERR_INVALIDCALL;
5677 if (pSourceTexture == pDestinationTexture) {
5678 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5679 This, pSourceTexture, pDestinationTexture);
5680 hr = WINED3DERR_INVALIDCALL;
5682 /* Verify that the source and destination textures are the same type */
5683 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5684 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5686 if (sourceType != destinationType) {
5687 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5689 hr = WINED3DERR_INVALIDCALL;
5692 /* check that both textures have the identical numbers of levels */
5693 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5694 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5695 hr = WINED3DERR_INVALIDCALL;
5698 if (WINED3D_OK == hr) {
5699 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5701 /* Make sure that the destination texture is loaded */
5702 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5704 /* Update every surface level of the texture */
5705 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5707 switch (sourceType) {
5708 case WINED3DRTYPE_TEXTURE:
5710 IWineD3DSurface *srcSurface;
5711 IWineD3DSurface *destSurface;
5713 for (i = 0 ; i < levels ; ++i) {
5714 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5715 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5716 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5717 IWineD3DSurface_Release(srcSurface);
5718 IWineD3DSurface_Release(destSurface);
5719 if (WINED3D_OK != hr) {
5720 WARN("(%p) : Call to update surface failed\n", This);
5726 case WINED3DRTYPE_CUBETEXTURE:
5728 IWineD3DSurface *srcSurface;
5729 IWineD3DSurface *destSurface;
5730 WINED3DCUBEMAP_FACES faceType;
5732 for (i = 0 ; i < levels ; ++i) {
5733 /* Update each cube face */
5734 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5735 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5736 if (WINED3D_OK != hr) {
5737 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5739 TRACE("Got srcSurface %p\n", srcSurface);
5741 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5742 if (WINED3D_OK != hr) {
5743 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5745 TRACE("Got desrSurface %p\n", destSurface);
5747 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5748 IWineD3DSurface_Release(srcSurface);
5749 IWineD3DSurface_Release(destSurface);
5750 if (WINED3D_OK != hr) {
5751 WARN("(%p) : Call to update surface failed\n", This);
5759 case WINED3DRTYPE_VOLUMETEXTURE:
5761 IWineD3DVolume *srcVolume = NULL;
5762 IWineD3DVolume *destVolume = NULL;
5764 for (i = 0 ; i < levels ; ++i) {
5765 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5766 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5767 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5768 IWineD3DVolume_Release(srcVolume);
5769 IWineD3DVolume_Release(destVolume);
5770 if (WINED3D_OK != hr) {
5771 WARN("(%p) : Call to update volume failed\n", This);
5779 FIXME("(%p) : Unsupported source and destination type\n", This);
5780 hr = WINED3DERR_INVALIDCALL;
5787 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5788 IWineD3DSwapChain *swapChain;
5790 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5791 if(hr == WINED3D_OK) {
5792 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5793 IWineD3DSwapChain_Release(swapChain);
5798 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5800 IWineD3DBaseTextureImpl *texture;
5803 TRACE("(%p) : %p\n", This, pNumPasses);
5805 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5806 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5807 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5808 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5810 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5811 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5812 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5815 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5816 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5818 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5819 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5822 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5823 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5826 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5827 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5828 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5833 /* return a sensible default */
5836 TRACE("returning D3D_OK\n");
5840 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5844 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5845 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5846 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
5847 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
5849 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5854 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5858 PALETTEENTRY **palettes;
5860 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5862 if (PaletteNumber >= MAX_PALETTES) {
5863 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5864 return WINED3DERR_INVALIDCALL;
5867 if (PaletteNumber >= This->NumberOfPalettes) {
5868 NewSize = This->NumberOfPalettes;
5871 } while(PaletteNumber >= NewSize);
5872 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5874 ERR("Out of memory!\n");
5875 return E_OUTOFMEMORY;
5877 This->palettes = palettes;
5878 This->NumberOfPalettes = NewSize;
5881 if (!This->palettes[PaletteNumber]) {
5882 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5883 if (!This->palettes[PaletteNumber]) {
5884 ERR("Out of memory!\n");
5885 return E_OUTOFMEMORY;
5889 for (j = 0; j < 256; ++j) {
5890 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5891 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5892 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5893 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5895 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5896 TRACE("(%p) : returning\n", This);
5900 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5903 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5904 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5905 /* What happens in such situation isn't documented; Native seems to silently abort
5906 on such conditions. Return Invalid Call. */
5907 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5908 return WINED3DERR_INVALIDCALL;
5910 for (j = 0; j < 256; ++j) {
5911 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5912 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5913 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5914 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5916 TRACE("(%p) : returning\n", This);
5920 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5922 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5923 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5924 (tested with reference rasterizer). Return Invalid Call. */
5925 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5926 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5927 return WINED3DERR_INVALIDCALL;
5929 /*TODO: stateblocks */
5930 if (This->currentPalette != PaletteNumber) {
5931 This->currentPalette = PaletteNumber;
5932 dirtify_p8_texture_samplers(This);
5934 TRACE("(%p) : returning\n", This);
5938 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5940 if (PaletteNumber == NULL) {
5941 WARN("(%p) : returning Invalid Call\n", This);
5942 return WINED3DERR_INVALIDCALL;
5944 /*TODO: stateblocks */
5945 *PaletteNumber = This->currentPalette;
5946 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5950 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5955 FIXME("(%p) : stub\n", This);
5959 This->softwareVertexProcessing = bSoftware;
5964 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5969 FIXME("(%p) : stub\n", This);
5972 return This->softwareVertexProcessing;
5976 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5978 IWineD3DSwapChain *swapChain;
5981 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5983 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5984 if(hr == WINED3D_OK){
5985 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5986 IWineD3DSwapChain_Release(swapChain);
5988 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5994 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5997 if(nSegments != 0.0f) {
6000 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6007 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6012 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6018 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6020 /** TODO: remove casts to IWineD3DSurfaceImpl
6021 * NOTE: move code to surface to accomplish this
6022 ****************************************/
6023 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6024 int srcWidth, srcHeight;
6025 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6026 WINED3DFORMAT destFormat, srcFormat;
6028 int srcLeft, destLeft, destTop;
6029 WINED3DPOOL srcPool, destPool;
6031 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6032 glDescriptor *glDescription = NULL;
6033 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
6037 CONVERT_TYPES convert = NO_CONVERSION;
6039 WINED3DSURFACE_DESC winedesc;
6041 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6042 memset(&winedesc, 0, sizeof(winedesc));
6043 winedesc.Width = &srcSurfaceWidth;
6044 winedesc.Height = &srcSurfaceHeight;
6045 winedesc.Pool = &srcPool;
6046 winedesc.Format = &srcFormat;
6048 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6050 winedesc.Width = &destSurfaceWidth;
6051 winedesc.Height = &destSurfaceHeight;
6052 winedesc.Pool = &destPool;
6053 winedesc.Format = &destFormat;
6054 winedesc.Size = &destSize;
6056 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6058 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6059 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6060 return WINED3DERR_INVALIDCALL;
6063 /* This call loads the opengl surface directly, instead of copying the surface to the
6064 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
6065 * copy in sysmem and use regular surface loading.
6067 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
6068 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
6069 if(convert != NO_CONVERSION) {
6070 return IWineD3DSurface_BltFast(pDestinationSurface,
6071 pDestPoint ? pDestPoint->x : 0,
6072 pDestPoint ? pDestPoint->y : 0,
6073 pSourceSurface, pSourceRect, 0);
6076 if (destFormat == WINED3DFMT_UNKNOWN) {
6077 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6078 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6080 /* Get the update surface description */
6081 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6084 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6087 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6088 checkGLcall("glActiveTextureARB");
6091 /* Make sure the surface is loaded and up to date */
6092 surface_internal_preload(pDestinationSurface, SRGB_RGB);
6093 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
6095 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6097 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
6098 dst_format_desc = ((IWineD3DSurfaceImpl *)pDestinationSurface)->resource.format_desc;
6100 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6101 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6102 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
6103 srcLeft = pSourceRect ? pSourceRect->left : 0;
6104 destLeft = pDestPoint ? pDestPoint->x : 0;
6105 destTop = pDestPoint ? pDestPoint->y : 0;
6108 /* This function doesn't support compressed textures
6109 the pitch is just bytesPerPixel * width */
6110 if(srcWidth != srcSurfaceWidth || srcLeft ){
6111 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
6112 offset += srcLeft * src_format_desc->byte_count;
6113 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6115 /* TODO DXT formats */
6117 if(pSourceRect != NULL && pSourceRect->top != 0){
6118 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
6120 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
6121 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
6122 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
6125 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6127 /* need to lock the surface to get the data */
6128 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6133 /* TODO: Cube and volume support */
6135 /* not a whole row so we have to do it a line at a time */
6138 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
6139 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6141 for (j = destTop; j < (srcHeight + destTop); ++j)
6143 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, j,
6144 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
6148 } else { /* Full width, so just write out the whole texture */
6149 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6151 if (WINED3DFMT_DXT1 == destFormat ||
6152 WINED3DFMT_DXT2 == destFormat ||
6153 WINED3DFMT_DXT3 == destFormat ||
6154 WINED3DFMT_DXT4 == destFormat ||
6155 WINED3DFMT_DXT5 == destFormat) {
6156 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6157 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6158 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6159 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6160 } if (destFormat != srcFormat) {
6161 FIXME("Updating mixed format compressed texture is not curretly support\n");
6163 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6164 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
6167 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6172 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6173 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
6176 checkGLcall("glTexSubImage2D");
6180 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6181 sampler = This->rev_tex_unit_map[0];
6182 if (sampler != -1) {
6183 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6189 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6191 struct WineD3DRectPatch *patch;
6192 GLenum old_primitive_type;
6196 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6198 if(!(Handle || pRectPatchInfo)) {
6199 /* TODO: Write a test for the return value, thus the FIXME */
6200 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6201 return WINED3DERR_INVALIDCALL;
6205 i = PATCHMAP_HASHFUNC(Handle);
6207 LIST_FOR_EACH(e, &This->patches[i]) {
6208 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6209 if(patch->Handle == Handle) {
6216 TRACE("Patch does not exist. Creating a new one\n");
6217 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6218 patch->Handle = Handle;
6219 list_add_head(&This->patches[i], &patch->entry);
6221 TRACE("Found existing patch %p\n", patch);
6224 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6225 * attributes we have to tesselate, read back, and draw. This needs a patch
6226 * management structure instance. Create one.
6228 * A possible improvement is to check if a vertex shader is used, and if not directly
6231 FIXME("Drawing an uncached patch. This is slow\n");
6232 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6235 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6236 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6237 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6239 TRACE("Tesselation density or patch info changed, retesselating\n");
6241 if(pRectPatchInfo) {
6242 patch->RectPatchInfo = *pRectPatchInfo;
6244 patch->numSegs[0] = pNumSegs[0];
6245 patch->numSegs[1] = pNumSegs[1];
6246 patch->numSegs[2] = pNumSegs[2];
6247 patch->numSegs[3] = pNumSegs[3];
6249 hr = tesselate_rectpatch(This, patch);
6251 WARN("Patch tesselation failed\n");
6253 /* Do not release the handle to store the params of the patch */
6255 HeapFree(GetProcessHeap(), 0, patch);
6261 This->currentPatch = patch;
6262 old_primitive_type = This->stateBlock->gl_primitive_type;
6263 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
6264 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6265 This->stateBlock->gl_primitive_type = old_primitive_type;
6266 This->currentPatch = NULL;
6268 /* Destroy uncached patches */
6270 HeapFree(GetProcessHeap(), 0, patch->mem);
6271 HeapFree(GetProcessHeap(), 0, patch);
6276 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6278 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6279 FIXME("(%p) : Stub\n", This);
6283 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6286 struct WineD3DRectPatch *patch;
6288 TRACE("(%p) Handle(%d)\n", This, Handle);
6290 i = PATCHMAP_HASHFUNC(Handle);
6291 LIST_FOR_EACH(e, &This->patches[i]) {
6292 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6293 if(patch->Handle == Handle) {
6294 TRACE("Deleting patch %p\n", patch);
6295 list_remove(&patch->entry);
6296 HeapFree(GetProcessHeap(), 0, patch->mem);
6297 HeapFree(GetProcessHeap(), 0, patch);
6302 /* TODO: Write a test for the return value */
6303 FIXME("Attempt to destroy nonexistent patch\n");
6304 return WINED3DERR_INVALIDCALL;
6307 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6309 IWineD3DSwapChain *swapchain;
6311 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6312 if (SUCCEEDED(hr)) {
6313 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6320 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6321 const WINED3DRECT *rect, const float color[4])
6323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6324 IWineD3DSwapChain *swapchain;
6326 swapchain = get_swapchain(surface);
6330 TRACE("Surface %p is onscreen\n", surface);
6332 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6334 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6335 buffer = surface_get_gl_buffer(surface, swapchain);
6336 glDrawBuffer(buffer);
6337 checkGLcall("glDrawBuffer()");
6339 TRACE("Surface %p is offscreen\n", surface);
6341 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6343 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6344 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6345 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6346 checkGLcall("glFramebufferRenderbufferEXT");
6350 glEnable(GL_SCISSOR_TEST);
6352 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6354 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6355 rect->x2 - rect->x1, rect->y2 - rect->y1);
6357 checkGLcall("glScissor");
6358 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6360 glDisable(GL_SCISSOR_TEST);
6362 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6364 glDisable(GL_BLEND);
6365 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6367 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6368 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6370 glClearColor(color[0], color[1], color[2], color[3]);
6371 glClear(GL_COLOR_BUFFER_BIT);
6372 checkGLcall("glClear");
6374 if (This->activeContext->current_fbo) {
6375 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6377 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6378 checkGLcall("glBindFramebuffer()");
6381 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6382 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6383 glDrawBuffer(GL_BACK);
6384 checkGLcall("glDrawBuffer()");
6390 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6391 unsigned int r, g, b, a;
6394 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6395 destfmt == WINED3DFMT_R8G8B8)
6398 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6400 a = (color & 0xff000000) >> 24;
6401 r = (color & 0x00ff0000) >> 16;
6402 g = (color & 0x0000ff00) >> 8;
6403 b = (color & 0x000000ff) >> 0;
6407 case WINED3DFMT_R5G6B5:
6408 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6415 TRACE("Returning %08x\n", ret);
6418 case WINED3DFMT_X1R5G5B5:
6419 case WINED3DFMT_A1R5G5B5:
6428 TRACE("Returning %08x\n", ret);
6431 case WINED3DFMT_A8_UNORM:
6432 TRACE("Returning %08x\n", a);
6435 case WINED3DFMT_X4R4G4B4:
6436 case WINED3DFMT_A4R4G4B4:
6445 TRACE("Returning %08x\n", ret);
6448 case WINED3DFMT_R3G3B2:
6455 TRACE("Returning %08x\n", ret);
6458 case WINED3DFMT_X8B8G8R8:
6459 case WINED3DFMT_R8G8B8A8_UNORM:
6464 TRACE("Returning %08x\n", ret);
6467 case WINED3DFMT_A2R10G10B10:
6469 r = (r * 1024) / 256;
6470 g = (g * 1024) / 256;
6471 b = (b * 1024) / 256;
6476 TRACE("Returning %08x\n", ret);
6479 case WINED3DFMT_R10G10B10A2_UNORM:
6481 r = (r * 1024) / 256;
6482 g = (g * 1024) / 256;
6483 b = (b * 1024) / 256;
6488 TRACE("Returning %08x\n", ret);
6492 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6497 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6499 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6501 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6503 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6504 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6505 return WINED3DERR_INVALIDCALL;
6508 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6509 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6510 color_fill_fbo(iface, pSurface, pRect, c);
6513 /* Just forward this to the DirectDraw blitting engine */
6514 memset(&BltFx, 0, sizeof(BltFx));
6515 BltFx.dwSize = sizeof(BltFx);
6516 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6517 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6518 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6522 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6523 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6525 IWineD3DResource *resource;
6526 IWineD3DSurface *surface;
6529 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6532 ERR("Failed to get resource, hr %#x\n", hr);
6536 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6538 FIXME("Only supported on surface resources\n");
6539 IWineD3DResource_Release(resource);
6543 surface = (IWineD3DSurface *)resource;
6545 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6547 color_fill_fbo(iface, surface, NULL, color);
6554 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6556 c = ((DWORD)(color[2] * 255.0));
6557 c |= ((DWORD)(color[1] * 255.0)) << 8;
6558 c |= ((DWORD)(color[0] * 255.0)) << 16;
6559 c |= ((DWORD)(color[3] * 255.0)) << 24;
6561 /* Just forward this to the DirectDraw blitting engine */
6562 memset(&BltFx, 0, sizeof(BltFx));
6563 BltFx.dwSize = sizeof(BltFx);
6564 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6565 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6568 ERR("Blt failed, hr %#x\n", hr);
6572 IWineD3DResource_Release(resource);
6575 /* rendertarget and depth stencil functions */
6576 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6579 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6580 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6581 return WINED3DERR_INVALIDCALL;
6584 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6585 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6586 /* Note inc ref on returned surface */
6587 if(*ppRenderTarget != NULL)
6588 IWineD3DSurface_AddRef(*ppRenderTarget);
6592 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6594 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6595 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6596 IWineD3DSwapChainImpl *Swapchain;
6599 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6601 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6602 if(hr != WINED3D_OK) {
6603 ERR("Can't get the swapchain\n");
6607 /* Make sure to release the swapchain */
6608 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6610 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6611 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6612 return WINED3DERR_INVALIDCALL;
6614 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6615 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6616 return WINED3DERR_INVALIDCALL;
6619 if(Swapchain->frontBuffer != Front) {
6620 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6622 if(Swapchain->frontBuffer)
6624 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6625 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6627 Swapchain->frontBuffer = Front;
6629 if(Swapchain->frontBuffer) {
6630 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6631 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6635 if(Back && !Swapchain->backBuffer) {
6636 /* We need memory for the back buffer array - only one back buffer this way */
6637 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6638 if(!Swapchain->backBuffer) {
6639 ERR("Out of memory\n");
6640 return E_OUTOFMEMORY;
6644 if(Swapchain->backBuffer[0] != Back) {
6645 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6647 /* What to do about the context here in the case of multithreading? Not sure.
6648 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6651 if(!Swapchain->backBuffer[0]) {
6652 /* GL was told to draw to the front buffer at creation,
6655 glDrawBuffer(GL_BACK);
6656 checkGLcall("glDrawBuffer(GL_BACK)");
6657 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6658 Swapchain->presentParms.BackBufferCount = 1;
6660 /* That makes problems - disable for now */
6661 /* glDrawBuffer(GL_FRONT); */
6662 checkGLcall("glDrawBuffer(GL_FRONT)");
6663 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6664 Swapchain->presentParms.BackBufferCount = 0;
6668 if(Swapchain->backBuffer[0])
6670 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6671 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6673 Swapchain->backBuffer[0] = Back;
6675 if(Swapchain->backBuffer[0]) {
6676 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6677 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6679 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6680 Swapchain->backBuffer = NULL;
6688 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6690 *ppZStencilSurface = This->stencilBufferTarget;
6691 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6693 if(*ppZStencilSurface != NULL) {
6694 /* Note inc ref on returned surface */
6695 IWineD3DSurface_AddRef(*ppZStencilSurface);
6698 return WINED3DERR_NOTFOUND;
6702 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6703 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6706 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6707 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6709 POINT offset = {0, 0};
6711 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6712 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6713 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6714 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6717 case WINED3DTEXF_LINEAR:
6718 gl_filter = GL_LINEAR;
6722 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6723 case WINED3DTEXF_NONE:
6724 case WINED3DTEXF_POINT:
6725 gl_filter = GL_NEAREST;
6729 /* Attach src surface to src fbo */
6730 src_swapchain = get_swapchain(src_surface);
6731 if (src_swapchain) {
6732 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6734 TRACE("Source surface %p is onscreen\n", src_surface);
6735 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6736 /* Make sure the drawable is up to date. In the offscreen case
6737 * attach_surface_fbo() implicitly takes care of this. */
6738 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6740 if(buffer == GL_FRONT) {
6743 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6744 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6745 h = windowsize.bottom - windowsize.top;
6746 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6747 src_rect->y1 = offset.y + h - src_rect->y1;
6748 src_rect->y2 = offset.y + h - src_rect->y2;
6750 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6751 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6755 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6756 glReadBuffer(buffer);
6757 checkGLcall("glReadBuffer()");
6759 TRACE("Source surface %p is offscreen\n", src_surface);
6761 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6762 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6763 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6764 checkGLcall("glReadBuffer()");
6765 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6766 checkGLcall("glFramebufferRenderbufferEXT");
6770 /* Attach dst surface to dst fbo */
6771 dst_swapchain = get_swapchain(dst_surface);
6772 if (dst_swapchain) {
6773 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6775 TRACE("Destination surface %p is onscreen\n", dst_surface);
6776 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6777 /* Make sure the drawable is up to date. In the offscreen case
6778 * attach_surface_fbo() implicitly takes care of this. */
6779 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6781 if(buffer == GL_FRONT) {
6784 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6785 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6786 h = windowsize.bottom - windowsize.top;
6787 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6788 dst_rect->y1 = offset.y + h - dst_rect->y1;
6789 dst_rect->y2 = offset.y + h - dst_rect->y2;
6791 /* Screen coords = window coords, surface height = window height */
6792 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6793 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6797 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6798 glDrawBuffer(buffer);
6799 checkGLcall("glDrawBuffer()");
6801 TRACE("Destination surface %p is offscreen\n", dst_surface);
6803 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6804 if(!src_swapchain) {
6805 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6809 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6810 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6811 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6812 checkGLcall("glDrawBuffer()");
6813 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6814 checkGLcall("glFramebufferRenderbufferEXT");
6816 glDisable(GL_SCISSOR_TEST);
6817 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6820 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6821 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6822 checkGLcall("glBlitFramebuffer()");
6824 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6825 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6826 checkGLcall("glBlitFramebuffer()");
6829 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6831 if (This->activeContext->current_fbo) {
6832 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6834 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6835 checkGLcall("glBindFramebuffer()");
6838 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6839 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6840 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6841 glDrawBuffer(GL_BACK);
6842 checkGLcall("glDrawBuffer()");
6847 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6849 WINED3DVIEWPORT viewport;
6851 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6853 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6854 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6855 This, RenderTargetIndex, GL_LIMITS(buffers));
6856 return WINED3DERR_INVALIDCALL;
6859 /* MSDN says that null disables the render target
6860 but a device must always be associated with a render target
6861 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6863 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6864 FIXME("Trying to set render target 0 to NULL\n");
6865 return WINED3DERR_INVALIDCALL;
6867 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6868 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);
6869 return WINED3DERR_INVALIDCALL;
6872 /* If we are trying to set what we already have, don't bother */
6873 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6874 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6877 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6878 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6879 This->render_targets[RenderTargetIndex] = pRenderTarget;
6881 /* Render target 0 is special */
6882 if(RenderTargetIndex == 0) {
6883 /* Finally, reset the viewport as the MSDN states. */
6884 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6885 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6888 viewport.MaxZ = 1.0f;
6889 viewport.MinZ = 0.0f;
6890 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6891 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6892 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6894 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6899 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6901 HRESULT hr = WINED3D_OK;
6902 IWineD3DSurface *tmp;
6904 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6906 if (pNewZStencil == This->stencilBufferTarget) {
6907 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6909 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6910 * depending on the renter target implementation being used.
6911 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6912 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6913 * stencil buffer and incur an extra memory overhead
6914 ******************************************************/
6916 if (This->stencilBufferTarget) {
6917 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6918 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6919 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6921 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6922 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6923 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6927 tmp = This->stencilBufferTarget;
6928 This->stencilBufferTarget = pNewZStencil;
6929 /* should we be calling the parent or the wined3d surface? */
6930 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6931 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6934 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6935 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6936 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6937 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6938 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6945 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6946 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6948 /* TODO: the use of Impl is deprecated. */
6949 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6950 WINED3DLOCKED_RECT lockedRect;
6952 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6954 /* some basic validation checks */
6955 if(This->cursorTexture) {
6956 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6958 glDeleteTextures(1, &This->cursorTexture);
6960 This->cursorTexture = 0;
6963 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6964 This->haveHardwareCursor = TRUE;
6966 This->haveHardwareCursor = FALSE;
6969 WINED3DLOCKED_RECT rect;
6971 /* MSDN: Cursor must be A8R8G8B8 */
6972 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
6974 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6975 return WINED3DERR_INVALIDCALL;
6978 /* MSDN: Cursor must be smaller than the display mode */
6979 if(pSur->currentDesc.Width > This->ddraw_width ||
6980 pSur->currentDesc.Height > This->ddraw_height) {
6981 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);
6982 return WINED3DERR_INVALIDCALL;
6985 if (!This->haveHardwareCursor) {
6986 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6988 /* Do not store the surface's pointer because the application may
6989 * release it after setting the cursor image. Windows doesn't
6990 * addref the set surface, so we can't do this either without
6991 * creating circular refcount dependencies. Copy out the gl texture
6994 This->cursorWidth = pSur->currentDesc.Width;
6995 This->cursorHeight = pSur->currentDesc.Height;
6996 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6998 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
6999 char *mem, *bits = rect.pBits;
7000 GLint intfmt = glDesc->glInternal;
7001 GLint format = glDesc->glFormat;
7002 GLint type = glDesc->glType;
7003 INT height = This->cursorHeight;
7004 INT width = This->cursorWidth;
7005 INT bpp = glDesc->byte_count;
7008 /* Reformat the texture memory (pitch and width can be
7010 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
7011 for(i = 0; i < height; i++)
7012 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
7013 IWineD3DSurface_UnlockRect(pCursorBitmap);
7016 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7017 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
7018 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
7021 /* Make sure that a proper texture unit is selected */
7022 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
7023 checkGLcall("glActiveTextureARB");
7024 sampler = This->rev_tex_unit_map[0];
7025 if (sampler != -1) {
7026 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
7028 /* Create a new cursor texture */
7029 glGenTextures(1, &This->cursorTexture);
7030 checkGLcall("glGenTextures");
7031 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
7032 checkGLcall("glBindTexture");
7033 /* Copy the bitmap memory into the cursor texture */
7034 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
7035 HeapFree(GetProcessHeap(), 0, mem);
7036 checkGLcall("glTexImage2D");
7038 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7039 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
7040 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
7047 FIXME("A cursor texture was not returned.\n");
7048 This->cursorTexture = 0;
7053 /* Draw a hardware cursor */
7054 ICONINFO cursorInfo;
7056 /* Create and clear maskBits because it is not needed for
7057 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
7059 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7060 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
7061 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
7062 WINED3DLOCK_NO_DIRTY_UPDATE |
7063 WINED3DLOCK_READONLY
7065 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
7066 pSur->currentDesc.Height);
7068 cursorInfo.fIcon = FALSE;
7069 cursorInfo.xHotspot = XHotSpot;
7070 cursorInfo.yHotspot = YHotSpot;
7071 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
7072 pSur->currentDesc.Height, 1,
7074 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
7075 pSur->currentDesc.Height, 1,
7076 32, lockedRect.pBits);
7077 IWineD3DSurface_UnlockRect(pCursorBitmap);
7078 /* Create our cursor and clean up. */
7079 cursor = CreateIconIndirect(&cursorInfo);
7081 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
7082 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
7083 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
7084 This->hardwareCursor = cursor;
7085 HeapFree(GetProcessHeap(), 0, maskBits);
7089 This->xHotSpot = XHotSpot;
7090 This->yHotSpot = YHotSpot;
7094 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7096 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7098 This->xScreenSpace = XScreenSpace;
7099 This->yScreenSpace = YScreenSpace;
7105 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7107 BOOL oldVisible = This->bCursorVisible;
7110 TRACE("(%p) : visible(%d)\n", This, bShow);
7113 * When ShowCursor is first called it should make the cursor appear at the OS's last
7114 * known cursor position. Because of this, some applications just repetitively call
7115 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7118 This->xScreenSpace = pt.x;
7119 This->yScreenSpace = pt.y;
7121 if (This->haveHardwareCursor) {
7122 This->bCursorVisible = bShow;
7124 SetCursor(This->hardwareCursor);
7130 if (This->cursorTexture)
7131 This->bCursorVisible = bShow;
7137 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7139 IWineD3DResourceImpl *resource;
7140 TRACE("(%p) : state (%u)\n", This, This->state);
7142 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7143 switch (This->state) {
7146 case WINED3DERR_DEVICELOST:
7148 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7149 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7150 return WINED3DERR_DEVICENOTRESET;
7152 return WINED3DERR_DEVICELOST;
7154 case WINED3DERR_DRIVERINTERNALERROR:
7155 return WINED3DERR_DRIVERINTERNALERROR;
7159 return WINED3DERR_DRIVERINTERNALERROR;
7163 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7165 /** FIXME: Resource tracking needs to be done,
7166 * The closes we can do to this is set the priorities of all managed textures low
7167 * and then reset them.
7168 ***********************************************************/
7169 FIXME("(%p) : stub\n", This);
7173 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
7175 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7177 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7178 if(surface->Flags & SFLAG_DIBSECTION) {
7179 /* Release the DC */
7180 SelectObject(surface->hDC, surface->dib.holdbitmap);
7181 DeleteDC(surface->hDC);
7182 /* Release the DIB section */
7183 DeleteObject(surface->dib.DIBsection);
7184 surface->dib.bitmap_data = NULL;
7185 surface->resource.allocatedMemory = NULL;
7186 surface->Flags &= ~SFLAG_DIBSECTION;
7188 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7189 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7190 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7191 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7192 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7193 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7195 surface->pow2Width = surface->pow2Height = 1;
7196 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7197 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7199 surface->glRect.left = 0;
7200 surface->glRect.top = 0;
7201 surface->glRect.right = surface->pow2Width;
7202 surface->glRect.bottom = surface->pow2Height;
7204 if(surface->glDescription.textureName) {
7205 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7207 glDeleteTextures(1, &surface->glDescription.textureName);
7209 surface->glDescription.textureName = 0;
7210 surface->Flags &= ~SFLAG_CLIENT;
7212 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7213 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7214 surface->Flags |= SFLAG_NONPOW2;
7216 surface->Flags &= ~SFLAG_NONPOW2;
7218 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7219 surface->resource.allocatedMemory = NULL;
7220 surface->resource.heapMemory = NULL;
7221 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7222 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7223 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7224 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7226 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7230 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7231 TRACE("Unloading resource %p\n", resource);
7232 IWineD3DResource_UnLoad(resource);
7233 IWineD3DResource_Release(resource);
7237 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7240 WINED3DDISPLAYMODE m;
7243 /* All Windowed modes are supported, as is leaving the current mode */
7244 if(pp->Windowed) return TRUE;
7245 if(!pp->BackBufferWidth) return TRUE;
7246 if(!pp->BackBufferHeight) return TRUE;
7248 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7249 for(i = 0; i < count; i++) {
7250 memset(&m, 0, sizeof(m));
7251 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7253 ERR("EnumAdapterModes failed\n");
7255 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7256 /* Mode found, it is supported */
7260 /* Mode not found -> not supported */
7264 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7265 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7266 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7268 IWineD3DBaseShaderImpl *shader;
7270 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7271 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7272 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7276 if(This->depth_blt_texture) {
7277 glDeleteTextures(1, &This->depth_blt_texture);
7278 This->depth_blt_texture = 0;
7280 if (This->depth_blt_rb) {
7281 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7282 This->depth_blt_rb = 0;
7283 This->depth_blt_rb_w = 0;
7284 This->depth_blt_rb_h = 0;
7288 This->blitter->free_private(iface);
7289 This->frag_pipe->free_private(iface);
7290 This->shader_backend->shader_free_private(iface);
7293 for (i = 0; i < GL_LIMITS(textures); i++) {
7294 /* Textures are recreated below */
7295 glDeleteTextures(1, &This->dummyTextureName[i]);
7296 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7297 This->dummyTextureName[i] = 0;
7301 while(This->numContexts) {
7302 DestroyContext(This, This->contexts[0]);
7304 This->activeContext = NULL;
7305 HeapFree(GetProcessHeap(), 0, swapchain->context);
7306 swapchain->context = NULL;
7307 swapchain->num_contexts = 0;
7310 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7312 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7314 IWineD3DSurfaceImpl *target;
7316 /* Recreate the primary swapchain's context */
7317 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7318 if(swapchain->backBuffer) {
7319 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7321 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7323 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7324 &swapchain->presentParms);
7325 swapchain->num_contexts = 1;
7326 This->activeContext = swapchain->context[0];
7328 create_dummy_textures(This);
7330 hr = This->shader_backend->shader_alloc_private(iface);
7332 ERR("Failed to recreate shader private data\n");
7335 hr = This->frag_pipe->alloc_private(iface);
7337 TRACE("Fragment pipeline private data couldn't be allocated\n");
7340 hr = This->blitter->alloc_private(iface);
7342 TRACE("Blitter private data couldn't be allocated\n");
7349 This->blitter->free_private(iface);
7350 This->frag_pipe->free_private(iface);
7351 This->shader_backend->shader_free_private(iface);
7355 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7357 IWineD3DSwapChainImpl *swapchain;
7359 BOOL DisplayModeChanged = FALSE;
7360 WINED3DDISPLAYMODE mode;
7361 TRACE("(%p)\n", This);
7363 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7365 ERR("Failed to get the first implicit swapchain\n");
7369 if(!is_display_mode_supported(This, pPresentationParameters)) {
7370 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7371 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7372 pPresentationParameters->BackBufferHeight);
7373 return WINED3DERR_INVALIDCALL;
7376 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7377 * on an existing gl context, so there's no real need for recreation.
7379 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7381 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7383 TRACE("New params:\n");
7384 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7385 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7386 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7387 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7388 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7389 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7390 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7391 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7392 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7393 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7394 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7395 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7396 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7398 /* No special treatment of these parameters. Just store them */
7399 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7400 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7401 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7402 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7404 /* What to do about these? */
7405 if(pPresentationParameters->BackBufferCount != 0 &&
7406 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7407 ERR("Cannot change the back buffer count yet\n");
7409 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7410 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7411 ERR("Cannot change the back buffer format yet\n");
7413 if(pPresentationParameters->hDeviceWindow != NULL &&
7414 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7415 ERR("Cannot change the device window yet\n");
7417 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7418 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7419 return WINED3DERR_INVALIDCALL;
7422 /* Reset the depth stencil */
7423 if (pPresentationParameters->EnableAutoDepthStencil)
7424 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7426 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7428 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7430 if(pPresentationParameters->Windowed) {
7431 mode.Width = swapchain->orig_width;
7432 mode.Height = swapchain->orig_height;
7433 mode.RefreshRate = 0;
7434 mode.Format = swapchain->presentParms.BackBufferFormat;
7436 mode.Width = pPresentationParameters->BackBufferWidth;
7437 mode.Height = pPresentationParameters->BackBufferHeight;
7438 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7439 mode.Format = swapchain->presentParms.BackBufferFormat;
7442 /* Should Width == 800 && Height == 0 set 800x600? */
7443 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7444 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7445 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7449 if(!pPresentationParameters->Windowed) {
7450 DisplayModeChanged = TRUE;
7452 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7453 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7455 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7456 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7457 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7459 if(This->auto_depth_stencil_buffer) {
7460 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7464 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7465 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7466 DisplayModeChanged) {
7468 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7470 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7471 if(swapchain->presentParms.Windowed) {
7472 /* switch from windowed to fs */
7473 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7474 pPresentationParameters->BackBufferWidth,
7475 pPresentationParameters->BackBufferHeight);
7477 /* Fullscreen -> fullscreen mode change */
7478 MoveWindow(swapchain->win_handle, 0, 0,
7479 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7482 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7483 /* Fullscreen -> windowed switch */
7484 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7486 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7487 } else if(!pPresentationParameters->Windowed) {
7488 DWORD style = This->style, exStyle = This->exStyle;
7489 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7490 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7491 * Reset to clear up their mess. Guild Wars also loses the device during that.
7495 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7496 pPresentationParameters->BackBufferWidth,
7497 pPresentationParameters->BackBufferHeight);
7498 This->style = style;
7499 This->exStyle = exStyle;
7502 TRACE("Resetting stateblock\n");
7503 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7504 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7506 /* Note: No parent needed for initial internal stateblock */
7507 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7508 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7509 else TRACE("Created stateblock %p\n", This->stateBlock);
7510 This->updateStateBlock = This->stateBlock;
7511 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7513 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7515 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7518 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7519 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7521 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7527 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7529 /** FIXME: always true at the moment **/
7530 if(!bEnableDialogs) {
7531 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7537 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7539 TRACE("(%p) : pParameters %p\n", This, pParameters);
7541 *pParameters = This->createParms;
7545 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7546 IWineD3DSwapChain *swapchain;
7548 TRACE("Relaying to swapchain\n");
7550 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7551 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7552 IWineD3DSwapChain_Release(swapchain);
7557 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7558 IWineD3DSwapChain *swapchain;
7560 TRACE("Relaying to swapchain\n");
7562 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7563 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7564 IWineD3DSwapChain_Release(swapchain);
7570 /** ********************************************************
7571 * Notification functions
7572 ** ********************************************************/
7573 /** This function must be called in the release of a resource when ref == 0,
7574 * the contents of resource must still be correct,
7575 * any handles to other resource held by the caller must be closed
7576 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7577 *****************************************************/
7578 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7581 TRACE("(%p) : Adding Resource %p\n", This, resource);
7582 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7585 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7588 TRACE("(%p) : Removing resource %p\n", This, resource);
7590 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7594 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7596 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7599 TRACE("(%p) : resource %p\n", This, resource);
7601 context_resource_released(iface, resource, type);
7604 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7605 case WINED3DRTYPE_SURFACE: {
7608 /* Cleanup any FBO attachments if d3d is enabled */
7609 if(This->d3d_initialized) {
7610 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7611 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7613 TRACE("Last active render target destroyed\n");
7614 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7615 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7616 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7617 * and the lastActiveRenderTarget member shouldn't matter
7620 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7621 TRACE("Activating primary back buffer\n");
7622 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7623 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7624 /* Single buffering environment */
7625 TRACE("Activating primary front buffer\n");
7626 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7628 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7629 /* Implicit render target destroyed, that means the device is being destroyed
7630 * whatever we set here, it shouldn't matter
7632 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7635 /* May happen during ddraw uninitialization */
7636 TRACE("Render target set, but swapchain does not exist!\n");
7637 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7641 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7642 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7643 This->render_targets[i] = NULL;
7646 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7647 This->stencilBufferTarget = NULL;
7653 case WINED3DRTYPE_TEXTURE:
7654 case WINED3DRTYPE_CUBETEXTURE:
7655 case WINED3DRTYPE_VOLUMETEXTURE:
7656 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7657 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7658 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7659 This->stateBlock->textures[counter] = NULL;
7661 if (This->updateStateBlock != This->stateBlock ){
7662 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7663 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7664 This->updateStateBlock->textures[counter] = NULL;
7669 case WINED3DRTYPE_VOLUME:
7670 /* TODO: nothing really? */
7672 case WINED3DRTYPE_VERTEXBUFFER:
7675 TRACE("Cleaning up stream pointers\n");
7677 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7678 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7679 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7681 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7682 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7683 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7684 This->updateStateBlock->streamSource[streamNumber] = 0;
7685 /* Set changed flag? */
7688 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) */
7689 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7690 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7691 This->stateBlock->streamSource[streamNumber] = 0;
7697 case WINED3DRTYPE_INDEXBUFFER:
7698 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7699 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7700 This->updateStateBlock->pIndexData = NULL;
7703 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7704 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7705 This->stateBlock->pIndexData = NULL;
7710 case WINED3DRTYPE_BUFFER:
7711 /* Nothing to do, yet.*/
7715 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7720 /* Remove the resource from the resourceStore */
7721 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7723 TRACE("Resource released\n");
7727 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7729 IWineD3DResourceImpl *resource, *cursor;
7731 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7733 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7734 TRACE("enumerating resource %p\n", resource);
7735 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7736 ret = pCallback((IWineD3DResource *) resource, pData);
7737 if(ret == S_FALSE) {
7738 TRACE("Canceling enumeration\n");
7745 /**********************************************************
7746 * IWineD3DDevice VTbl follows
7747 **********************************************************/
7749 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7751 /*** IUnknown methods ***/
7752 IWineD3DDeviceImpl_QueryInterface,
7753 IWineD3DDeviceImpl_AddRef,
7754 IWineD3DDeviceImpl_Release,
7755 /*** IWineD3DDevice methods ***/
7756 IWineD3DDeviceImpl_GetParent,
7757 /*** Creation methods**/
7758 IWineD3DDeviceImpl_CreateBuffer,
7759 IWineD3DDeviceImpl_CreateVertexBuffer,
7760 IWineD3DDeviceImpl_CreateIndexBuffer,
7761 IWineD3DDeviceImpl_CreateStateBlock,
7762 IWineD3DDeviceImpl_CreateSurface,
7763 IWineD3DDeviceImpl_CreateRendertargetView,
7764 IWineD3DDeviceImpl_CreateTexture,
7765 IWineD3DDeviceImpl_CreateVolumeTexture,
7766 IWineD3DDeviceImpl_CreateVolume,
7767 IWineD3DDeviceImpl_CreateCubeTexture,
7768 IWineD3DDeviceImpl_CreateQuery,
7769 IWineD3DDeviceImpl_CreateSwapChain,
7770 IWineD3DDeviceImpl_CreateVertexDeclaration,
7771 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7772 IWineD3DDeviceImpl_CreateVertexShader,
7773 IWineD3DDeviceImpl_CreatePixelShader,
7774 IWineD3DDeviceImpl_CreatePalette,
7775 /*** Odd functions **/
7776 IWineD3DDeviceImpl_Init3D,
7777 IWineD3DDeviceImpl_InitGDI,
7778 IWineD3DDeviceImpl_Uninit3D,
7779 IWineD3DDeviceImpl_UninitGDI,
7780 IWineD3DDeviceImpl_SetMultithreaded,
7781 IWineD3DDeviceImpl_EvictManagedResources,
7782 IWineD3DDeviceImpl_GetAvailableTextureMem,
7783 IWineD3DDeviceImpl_GetBackBuffer,
7784 IWineD3DDeviceImpl_GetCreationParameters,
7785 IWineD3DDeviceImpl_GetDeviceCaps,
7786 IWineD3DDeviceImpl_GetDirect3D,
7787 IWineD3DDeviceImpl_GetDisplayMode,
7788 IWineD3DDeviceImpl_SetDisplayMode,
7789 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7790 IWineD3DDeviceImpl_GetRasterStatus,
7791 IWineD3DDeviceImpl_GetSwapChain,
7792 IWineD3DDeviceImpl_Reset,
7793 IWineD3DDeviceImpl_SetDialogBoxMode,
7794 IWineD3DDeviceImpl_SetCursorProperties,
7795 IWineD3DDeviceImpl_SetCursorPosition,
7796 IWineD3DDeviceImpl_ShowCursor,
7797 IWineD3DDeviceImpl_TestCooperativeLevel,
7798 /*** Getters and setters **/
7799 IWineD3DDeviceImpl_SetClipPlane,
7800 IWineD3DDeviceImpl_GetClipPlane,
7801 IWineD3DDeviceImpl_SetClipStatus,
7802 IWineD3DDeviceImpl_GetClipStatus,
7803 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7804 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7805 IWineD3DDeviceImpl_SetDepthStencilSurface,
7806 IWineD3DDeviceImpl_GetDepthStencilSurface,
7807 IWineD3DDeviceImpl_SetGammaRamp,
7808 IWineD3DDeviceImpl_GetGammaRamp,
7809 IWineD3DDeviceImpl_SetIndices,
7810 IWineD3DDeviceImpl_GetIndices,
7811 IWineD3DDeviceImpl_SetBaseVertexIndex,
7812 IWineD3DDeviceImpl_GetBaseVertexIndex,
7813 IWineD3DDeviceImpl_SetLight,
7814 IWineD3DDeviceImpl_GetLight,
7815 IWineD3DDeviceImpl_SetLightEnable,
7816 IWineD3DDeviceImpl_GetLightEnable,
7817 IWineD3DDeviceImpl_SetMaterial,
7818 IWineD3DDeviceImpl_GetMaterial,
7819 IWineD3DDeviceImpl_SetNPatchMode,
7820 IWineD3DDeviceImpl_GetNPatchMode,
7821 IWineD3DDeviceImpl_SetPaletteEntries,
7822 IWineD3DDeviceImpl_GetPaletteEntries,
7823 IWineD3DDeviceImpl_SetPixelShader,
7824 IWineD3DDeviceImpl_GetPixelShader,
7825 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7826 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7827 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7828 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7829 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7830 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7831 IWineD3DDeviceImpl_SetRenderState,
7832 IWineD3DDeviceImpl_GetRenderState,
7833 IWineD3DDeviceImpl_SetRenderTarget,
7834 IWineD3DDeviceImpl_GetRenderTarget,
7835 IWineD3DDeviceImpl_SetFrontBackBuffers,
7836 IWineD3DDeviceImpl_SetSamplerState,
7837 IWineD3DDeviceImpl_GetSamplerState,
7838 IWineD3DDeviceImpl_SetScissorRect,
7839 IWineD3DDeviceImpl_GetScissorRect,
7840 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7841 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7842 IWineD3DDeviceImpl_SetStreamSource,
7843 IWineD3DDeviceImpl_GetStreamSource,
7844 IWineD3DDeviceImpl_SetStreamSourceFreq,
7845 IWineD3DDeviceImpl_GetStreamSourceFreq,
7846 IWineD3DDeviceImpl_SetTexture,
7847 IWineD3DDeviceImpl_GetTexture,
7848 IWineD3DDeviceImpl_SetTextureStageState,
7849 IWineD3DDeviceImpl_GetTextureStageState,
7850 IWineD3DDeviceImpl_SetTransform,
7851 IWineD3DDeviceImpl_GetTransform,
7852 IWineD3DDeviceImpl_SetVertexDeclaration,
7853 IWineD3DDeviceImpl_GetVertexDeclaration,
7854 IWineD3DDeviceImpl_SetVertexShader,
7855 IWineD3DDeviceImpl_GetVertexShader,
7856 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7857 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7858 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7859 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7860 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7861 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7862 IWineD3DDeviceImpl_SetViewport,
7863 IWineD3DDeviceImpl_GetViewport,
7864 IWineD3DDeviceImpl_MultiplyTransform,
7865 IWineD3DDeviceImpl_ValidateDevice,
7866 IWineD3DDeviceImpl_ProcessVertices,
7867 /*** State block ***/
7868 IWineD3DDeviceImpl_BeginStateBlock,
7869 IWineD3DDeviceImpl_EndStateBlock,
7870 /*** Scene management ***/
7871 IWineD3DDeviceImpl_BeginScene,
7872 IWineD3DDeviceImpl_EndScene,
7873 IWineD3DDeviceImpl_Present,
7874 IWineD3DDeviceImpl_Clear,
7875 IWineD3DDeviceImpl_ClearRendertargetView,
7877 IWineD3DDeviceImpl_SetPrimitiveType,
7878 IWineD3DDeviceImpl_GetPrimitiveType,
7879 IWineD3DDeviceImpl_DrawPrimitive,
7880 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7881 IWineD3DDeviceImpl_DrawPrimitiveUP,
7882 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7883 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7884 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7885 IWineD3DDeviceImpl_DrawRectPatch,
7886 IWineD3DDeviceImpl_DrawTriPatch,
7887 IWineD3DDeviceImpl_DeletePatch,
7888 IWineD3DDeviceImpl_ColorFill,
7889 IWineD3DDeviceImpl_UpdateTexture,
7890 IWineD3DDeviceImpl_UpdateSurface,
7891 IWineD3DDeviceImpl_GetFrontBufferData,
7892 /*** object tracking ***/
7893 IWineD3DDeviceImpl_ResourceReleased,
7894 IWineD3DDeviceImpl_EnumResources
7897 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7898 WINED3DRS_ALPHABLENDENABLE ,
7899 WINED3DRS_ALPHAFUNC ,
7900 WINED3DRS_ALPHAREF ,
7901 WINED3DRS_ALPHATESTENABLE ,
7903 WINED3DRS_COLORWRITEENABLE ,
7904 WINED3DRS_DESTBLEND ,
7905 WINED3DRS_DITHERENABLE ,
7906 WINED3DRS_FILLMODE ,
7907 WINED3DRS_FOGDENSITY ,
7909 WINED3DRS_FOGSTART ,
7910 WINED3DRS_LASTPIXEL ,
7911 WINED3DRS_SHADEMODE ,
7912 WINED3DRS_SRCBLEND ,
7913 WINED3DRS_STENCILENABLE ,
7914 WINED3DRS_STENCILFAIL ,
7915 WINED3DRS_STENCILFUNC ,
7916 WINED3DRS_STENCILMASK ,
7917 WINED3DRS_STENCILPASS ,
7918 WINED3DRS_STENCILREF ,
7919 WINED3DRS_STENCILWRITEMASK ,
7920 WINED3DRS_STENCILZFAIL ,
7921 WINED3DRS_TEXTUREFACTOR ,
7932 WINED3DRS_ZWRITEENABLE
7935 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7936 WINED3DTSS_ALPHAARG0 ,
7937 WINED3DTSS_ALPHAARG1 ,
7938 WINED3DTSS_ALPHAARG2 ,
7939 WINED3DTSS_ALPHAOP ,
7940 WINED3DTSS_BUMPENVLOFFSET ,
7941 WINED3DTSS_BUMPENVLSCALE ,
7942 WINED3DTSS_BUMPENVMAT00 ,
7943 WINED3DTSS_BUMPENVMAT01 ,
7944 WINED3DTSS_BUMPENVMAT10 ,
7945 WINED3DTSS_BUMPENVMAT11 ,
7946 WINED3DTSS_COLORARG0 ,
7947 WINED3DTSS_COLORARG1 ,
7948 WINED3DTSS_COLORARG2 ,
7949 WINED3DTSS_COLOROP ,
7950 WINED3DTSS_RESULTARG ,
7951 WINED3DTSS_TEXCOORDINDEX ,
7952 WINED3DTSS_TEXTURETRANSFORMFLAGS
7955 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7956 WINED3DSAMP_ADDRESSU ,
7957 WINED3DSAMP_ADDRESSV ,
7958 WINED3DSAMP_ADDRESSW ,
7959 WINED3DSAMP_BORDERCOLOR ,
7960 WINED3DSAMP_MAGFILTER ,
7961 WINED3DSAMP_MINFILTER ,
7962 WINED3DSAMP_MIPFILTER ,
7963 WINED3DSAMP_MIPMAPLODBIAS ,
7964 WINED3DSAMP_MAXMIPLEVEL ,
7965 WINED3DSAMP_MAXANISOTROPY ,
7966 WINED3DSAMP_SRGBTEXTURE ,
7967 WINED3DSAMP_ELEMENTINDEX
7970 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7972 WINED3DRS_AMBIENTMATERIALSOURCE ,
7973 WINED3DRS_CLIPPING ,
7974 WINED3DRS_CLIPPLANEENABLE ,
7975 WINED3DRS_COLORVERTEX ,
7976 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7977 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7978 WINED3DRS_FOGDENSITY ,
7980 WINED3DRS_FOGSTART ,
7981 WINED3DRS_FOGTABLEMODE ,
7982 WINED3DRS_FOGVERTEXMODE ,
7983 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7984 WINED3DRS_LIGHTING ,
7985 WINED3DRS_LOCALVIEWER ,
7986 WINED3DRS_MULTISAMPLEANTIALIAS ,
7987 WINED3DRS_MULTISAMPLEMASK ,
7988 WINED3DRS_NORMALIZENORMALS ,
7989 WINED3DRS_PATCHEDGESTYLE ,
7990 WINED3DRS_POINTSCALE_A ,
7991 WINED3DRS_POINTSCALE_B ,
7992 WINED3DRS_POINTSCALE_C ,
7993 WINED3DRS_POINTSCALEENABLE ,
7994 WINED3DRS_POINTSIZE ,
7995 WINED3DRS_POINTSIZE_MAX ,
7996 WINED3DRS_POINTSIZE_MIN ,
7997 WINED3DRS_POINTSPRITEENABLE ,
7998 WINED3DRS_RANGEFOGENABLE ,
7999 WINED3DRS_SPECULARMATERIALSOURCE ,
8000 WINED3DRS_TWEENFACTOR ,
8001 WINED3DRS_VERTEXBLEND ,
8002 WINED3DRS_CULLMODE ,
8006 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8007 WINED3DTSS_TEXCOORDINDEX ,
8008 WINED3DTSS_TEXTURETRANSFORMFLAGS
8011 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8012 WINED3DSAMP_DMAPOFFSET
8015 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8016 DWORD rep = This->StateTable[state].representative;
8020 WineD3DContext *context;
8023 for(i = 0; i < This->numContexts; i++) {
8024 context = This->contexts[i];
8025 if(isStateDirty(context, rep)) continue;
8027 context->dirtyArray[context->numDirtyEntries++] = rep;
8030 context->isStateDirty[idx] |= (1 << shift);
8034 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8035 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8036 /* The drawable size of a pbuffer render target is the current pbuffer size
8038 *width = dev->pbufferWidth;
8039 *height = dev->pbufferHeight;
8042 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8043 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8045 *width = This->pow2Width;
8046 *height = This->pow2Height;
8049 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8050 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8051 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8052 * current context's drawable, which is the size of the back buffer of the swapchain
8053 * the active context belongs to. The back buffer of the swapchain is stored as the
8054 * surface the context belongs to.
8056 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8057 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;