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), 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 struct wined3d_buffer *object;
266 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
267 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
272 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
273 *ppVertexBuffer = NULL;
274 return WINED3DERR_INVALIDCALL;
275 } else if(Pool == WINED3DPOOL_SCRATCH) {
276 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
277 * anyway, SCRATCH vertex buffers aren't usable anywhere
279 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
280 *ppVertexBuffer = NULL;
281 return WINED3DERR_INVALIDCALL;
284 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
287 ERR("Out of memory\n");
288 *ppVertexBuffer = NULL;
289 return WINED3DERR_OUTOFVIDEOMEMORY;
292 object->vtbl = &wined3d_buffer_vtbl;
293 hr = resource_init(&object->resource, WINED3DRTYPE_VERTEXBUFFER, This, Size, Usage, Format, Pool, parent);
296 WARN("Failed to initialize resource, returning %#x\n", hr);
297 HeapFree(GetProcessHeap(), 0, object);
298 *ppVertexBuffer = NULL;
302 TRACE("(%p) : Created resource %p\n", This, object);
304 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
306 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);
307 *ppVertexBuffer = (IWineD3DBuffer *)object;
311 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
312 * drawStridedFast (half-life 2).
314 * Basically converting the vertices in the buffer is quite expensive, and observations
315 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
316 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
318 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
319 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
320 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
321 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
323 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
324 * more. In this call we can convert dx7 buffers too.
326 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
327 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
328 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
329 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
330 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
331 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
332 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
333 } else if(dxVersion <= 7 && conv) {
334 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
336 object->flags |= WINED3D_BUFFER_CREATEBO;
341 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
342 GLenum error, glUsage;
343 TRACE("Creating VBO for Index Buffer %p\n", object);
345 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
346 * restored on the next draw
348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
350 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
351 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
356 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
357 error = glGetError();
358 if(error != GL_NO_ERROR || object->vbo == 0) {
359 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
363 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
364 error = glGetError();
365 if(error != GL_NO_ERROR) {
366 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
370 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
371 * copy no readback will be needed
373 glUsage = GL_STATIC_DRAW_ARB;
374 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
375 error = glGetError();
376 if(error != GL_NO_ERROR) {
377 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
381 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
385 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
386 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
391 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
392 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
393 HANDLE *sharedHandle, IUnknown *parent) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 IWineD3DIndexBufferImpl *object;
398 TRACE("(%p) Creating index buffer\n", This);
400 /* Allocate the storage for the device */
401 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
404 ERR("Out of memory\n");
405 *ppIndexBuffer = NULL;
406 return WINED3DERR_OUTOFVIDEOMEMORY;
409 object->lpVtbl = &IWineD3DIndexBuffer_Vtbl;
410 hr = resource_init(&object->resource, WINED3DRTYPE_INDEXBUFFER, This, Length, Usage, Format, Pool, parent);
413 WARN("Failed to initialize resource, returning %#x\n", hr);
414 HeapFree(GetProcessHeap(), 0, object);
415 *ppIndexBuffer = NULL;
419 TRACE("(%p) : Created resource %p\n", This, object);
421 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
423 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
424 CreateIndexBufferVBO(This, object);
427 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
428 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
429 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
434 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
437 IWineD3DStateBlockImpl *object;
441 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
444 ERR("Out of memory\n");
445 *ppStateBlock = NULL;
446 return WINED3DERR_OUTOFVIDEOMEMORY;
449 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
450 object->wineD3DDevice = This;
451 object->parent = parent;
453 object->blockType = Type;
455 *ppStateBlock = (IWineD3DStateBlock *)object;
457 for(i = 0; i < LIGHTMAP_SIZE; i++) {
458 list_init(&object->lightMap[i]);
461 temp_result = allocate_shader_constants(object);
462 if (FAILED(temp_result))
464 HeapFree(GetProcessHeap(), 0, object);
468 /* Special case - Used during initialization to produce a placeholder stateblock
469 so other functions called can update a state block */
470 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
472 /* Don't bother increasing the reference count otherwise a device will never
473 be freed due to circular dependencies */
477 /* Otherwise, might as well set the whole state block to the appropriate values */
478 if (This->stateBlock != NULL)
479 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
481 memset(object->streamFreq, 1, sizeof(object->streamFreq));
483 /* Reset the ref and type after kludging it */
484 object->wineD3DDevice = This;
486 object->blockType = Type;
488 TRACE("Updating changed flags appropriate for type %d\n", Type);
490 if (Type == WINED3DSBT_ALL) {
492 TRACE("ALL => Pretend everything has changed\n");
493 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
495 /* Lights are not part of the changed / set structure */
496 for(j = 0; j < LIGHTMAP_SIZE; j++) {
498 LIST_FOR_EACH(e, &object->lightMap[j]) {
499 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
500 light->changed = TRUE;
501 light->enabledChanged = TRUE;
504 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
505 object->contained_render_states[j - 1] = j;
507 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
508 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
509 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
510 object->contained_transform_states[j - 1] = j;
512 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
513 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
514 object->contained_vs_consts_f[j] = j;
516 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
517 for(j = 0; j < MAX_CONST_I; j++) {
518 object->contained_vs_consts_i[j] = j;
520 object->num_contained_vs_consts_i = MAX_CONST_I;
521 for(j = 0; j < MAX_CONST_B; j++) {
522 object->contained_vs_consts_b[j] = j;
524 object->num_contained_vs_consts_b = MAX_CONST_B;
525 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
526 object->contained_ps_consts_f[j] = j;
528 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
529 for(j = 0; j < MAX_CONST_I; j++) {
530 object->contained_ps_consts_i[j] = j;
532 object->num_contained_ps_consts_i = MAX_CONST_I;
533 for(j = 0; j < MAX_CONST_B; j++) {
534 object->contained_ps_consts_b[j] = j;
536 object->num_contained_ps_consts_b = MAX_CONST_B;
537 for(i = 0; i < MAX_TEXTURES; i++) {
538 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
540 object->contained_tss_states[object->num_contained_tss_states].stage = i;
541 object->contained_tss_states[object->num_contained_tss_states].state = j;
542 object->num_contained_tss_states++;
545 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
546 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
547 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
548 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
549 object->num_contained_sampler_states++;
553 for(i = 0; i < MAX_STREAMS; i++) {
554 if(object->streamSource[i]) {
555 IWineD3DBuffer_AddRef(object->streamSource[i]);
558 if(object->pIndexData) {
559 IWineD3DIndexBuffer_AddRef(object->pIndexData);
561 if(object->vertexShader) {
562 IWineD3DVertexShader_AddRef(object->vertexShader);
564 if(object->pixelShader) {
565 IWineD3DPixelShader_AddRef(object->pixelShader);
568 } else if (Type == WINED3DSBT_PIXELSTATE) {
570 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
571 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
573 object->changed.pixelShader = TRUE;
575 /* Pixel Shader Constants */
576 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
577 object->contained_ps_consts_f[i] = i;
578 object->changed.pixelShaderConstantsF[i] = TRUE;
580 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
581 for (i = 0; i < MAX_CONST_B; ++i) {
582 object->contained_ps_consts_b[i] = i;
583 object->changed.pixelShaderConstantsB |= (1 << i);
585 object->num_contained_ps_consts_b = MAX_CONST_B;
586 for (i = 0; i < MAX_CONST_I; ++i) {
587 object->contained_ps_consts_i[i] = i;
588 object->changed.pixelShaderConstantsI |= (1 << i);
590 object->num_contained_ps_consts_i = MAX_CONST_I;
592 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
593 DWORD rs = SavedPixelStates_R[i];
594 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
595 object->contained_render_states[i] = rs;
597 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
598 for (j = 0; j < MAX_TEXTURES; j++) {
599 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
600 DWORD state = SavedPixelStates_T[i];
601 object->changed.textureState[j] |= 1 << state;
602 object->contained_tss_states[object->num_contained_tss_states].stage = j;
603 object->contained_tss_states[object->num_contained_tss_states].state = state;
604 object->num_contained_tss_states++;
607 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
608 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
609 DWORD state = SavedPixelStates_S[i];
610 object->changed.samplerState[j] |= 1 << state;
611 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
612 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
613 object->num_contained_sampler_states++;
616 if(object->pixelShader) {
617 IWineD3DPixelShader_AddRef(object->pixelShader);
620 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
621 * on them. This makes releasing the buffer easier
623 for(i = 0; i < MAX_STREAMS; i++) {
624 object->streamSource[i] = NULL;
626 object->pIndexData = NULL;
627 object->vertexShader = NULL;
629 } else if (Type == WINED3DSBT_VERTEXSTATE) {
631 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
632 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
634 object->changed.vertexShader = TRUE;
636 /* Vertex Shader Constants */
637 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
638 object->changed.vertexShaderConstantsF[i] = TRUE;
639 object->contained_vs_consts_f[i] = i;
641 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
642 for (i = 0; i < MAX_CONST_B; ++i) {
643 object->contained_vs_consts_b[i] = i;
644 object->changed.vertexShaderConstantsB |= (1 << i);
646 object->num_contained_vs_consts_b = MAX_CONST_B;
647 for (i = 0; i < MAX_CONST_I; ++i) {
648 object->contained_vs_consts_i[i] = i;
649 object->changed.vertexShaderConstantsI |= (1 << i);
651 object->num_contained_vs_consts_i = MAX_CONST_I;
652 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
653 DWORD rs = SavedVertexStates_R[i];
654 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
655 object->contained_render_states[i] = rs;
657 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
658 for (j = 0; j < MAX_TEXTURES; j++) {
659 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
660 DWORD state = SavedVertexStates_T[i];
661 object->changed.textureState[j] |= 1 << state;
662 object->contained_tss_states[object->num_contained_tss_states].stage = j;
663 object->contained_tss_states[object->num_contained_tss_states].state = state;
664 object->num_contained_tss_states++;
667 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
668 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
669 DWORD state = SavedVertexStates_S[i];
670 object->changed.samplerState[j] |= 1 << state;
671 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
672 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
673 object->num_contained_sampler_states++;
677 for(j = 0; j < LIGHTMAP_SIZE; j++) {
679 LIST_FOR_EACH(e, &object->lightMap[j]) {
680 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
681 light->changed = TRUE;
682 light->enabledChanged = TRUE;
686 for(i = 0; i < MAX_STREAMS; i++) {
687 if(object->streamSource[i]) {
688 IWineD3DBuffer_AddRef(object->streamSource[i]);
691 if(object->vertexShader) {
692 IWineD3DVertexShader_AddRef(object->vertexShader);
694 object->pIndexData = NULL;
695 object->pixelShader = NULL;
697 FIXME("Unrecognized state block type %d\n", Type);
700 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
704 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) {
705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
706 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
707 unsigned int Size = 1;
708 const struct GlPixelFormatDesc *glDesc;
709 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
713 TRACE("(%p) Create surface\n",This);
715 if(MultisampleQuality > 0) {
716 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
717 MultisampleQuality=0;
720 /** FIXME: Check that the format is supported
722 *******************************/
724 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
725 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
727 *********************************/
728 mul_4w = (Width + 3) & ~3;
729 mul_4h = (Height + 3) & ~3;
730 if (WINED3DFMT_UNKNOWN == Format) {
732 } else if (Format == WINED3DFMT_DXT1) {
733 /* DXT1 is half byte per pixel */
734 Size = (mul_4w * tableEntry->bpp * mul_4h) >> 1;
736 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
737 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
738 Format == WINED3DFMT_ATI2N) {
739 Size = (mul_4w * tableEntry->bpp * mul_4h);
741 /* The pitch is a multiple of 4 bytes */
742 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
746 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
748 /** Create and initialise the surface resource **/
749 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
752 ERR("Out of memory\n");
754 return WINED3DERR_OUTOFVIDEOMEMORY;
757 /* Look at the implementation and set the correct Vtable */
761 /* Check if a 3D adapter is available when creating gl surfaces */
764 ERR("OpenGL surfaces are not available without opengl\n");
765 HeapFree(GetProcessHeap(), 0, object);
766 return WINED3DERR_NOTAVAILABLE;
768 object->lpVtbl = &IWineD3DSurface_Vtbl;
772 object->lpVtbl = &IWineGDISurface_Vtbl;
776 /* To be sure to catch this */
777 ERR("Unknown requested surface implementation %d!\n", Impl);
778 HeapFree(GetProcessHeap(), 0, object);
779 return WINED3DERR_INVALIDCALL;
782 hr = resource_init(&object->resource, WINED3DRTYPE_SURFACE, This, Size, Usage, Format, Pool, parent);
785 WARN("Failed to initialize resource, returning %#x\n", hr);
786 HeapFree(GetProcessHeap(), 0, object);
791 TRACE("(%p) : Created resource %p\n", This, object);
793 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
795 *ppSurface = (IWineD3DSurface *)object;
797 /* "Standalone" surface */
798 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
800 object->currentDesc.Width = Width;
801 object->currentDesc.Height = Height;
802 object->currentDesc.MultiSampleType = MultiSample;
803 object->currentDesc.MultiSampleQuality = MultisampleQuality;
804 object->glDescription.level = Level;
805 object->heightscale = glDesc->heightscale != 0.0 ? glDesc->heightscale : 1.0;
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;
815 if (WINED3DFMT_UNKNOWN != Format) {
816 object->bytesPerPixel = tableEntry->bpp;
818 object->bytesPerPixel = 0;
821 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
823 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
825 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
826 * this function is too deep to need to care about things like this.
827 * Levels need to be checked too, and possibly Type since they all affect what can be done.
828 * ****************************************/
830 case WINED3DPOOL_SCRATCH:
832 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
833 "which are mutually exclusive, setting lockable to TRUE\n");
836 case WINED3DPOOL_SYSTEMMEM:
837 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
838 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
839 case WINED3DPOOL_MANAGED:
840 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
841 "Usage of DYNAMIC which are mutually exclusive, not doing "
842 "anything just telling you.\n");
844 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
845 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
846 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
847 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
850 FIXME("(%p) Unknown pool %d\n", This, Pool);
854 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
855 FIXME("Trying to create a render target that isn't in the default pool\n");
858 /* mark the texture as dirty so that it gets loaded first time around*/
859 surface_add_dirty_rect(*ppSurface, NULL);
860 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
861 This, Width, Height, Format, debug_d3dformat(Format),
862 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
864 list_init(&object->renderbuffers);
866 /* Call the private setup routine */
867 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)object);
870 ERR("Private setup failed, returning %#x\n", hr);
871 IWineD3DSurface_Release(*ppSurface);
879 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
880 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
882 struct wined3d_rendertarget_view *object;
884 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
887 ERR("Failed to allocate memory\n");
888 return E_OUTOFMEMORY;
891 object->vtbl = &wined3d_rendertarget_view_vtbl;
892 object->refcount = 1;
893 IWineD3DResource_AddRef(resource);
894 object->resource = resource;
895 object->parent = parent;
897 *rendertarget_view = (IWineD3DRendertargetView *)object;
902 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
903 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
904 IWineD3DTexture **ppTexture, HANDLE *pSharedHandle, IUnknown *parent)
906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
907 IWineD3DTextureImpl *object;
912 unsigned int pow2Width;
913 unsigned int pow2Height;
915 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
916 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
917 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
919 /* TODO: It should only be possible to create textures for formats
920 that are reported as supported */
921 if (WINED3DFMT_UNKNOWN >= Format) {
922 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
923 return WINED3DERR_INVALIDCALL;
926 /* Non-power2 support */
927 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO))
934 /* Find the nearest pow2 match */
935 pow2Width = pow2Height = 1;
936 while (pow2Width < Width) pow2Width <<= 1;
937 while (pow2Height < Height) pow2Height <<= 1;
939 if (pow2Width != Width || pow2Height != Height)
943 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
944 return WINED3DERR_INVALIDCALL;
950 /* Calculate levels for mip mapping */
951 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
953 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
955 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
956 return WINED3DERR_INVALIDCALL;
961 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
962 return WINED3DERR_INVALIDCALL;
969 Levels = wined3d_log2i(max(Width, Height)) + 1;
970 TRACE("Calculated levels = %d\n", Levels);
973 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
976 ERR("Out of memory\n");
978 return WINED3DERR_OUTOFVIDEOMEMORY;
981 object->lpVtbl = &IWineD3DTexture_Vtbl;
982 hr = resource_init(&object->resource, WINED3DRTYPE_TEXTURE, This, 0, Usage, Format, Pool, parent);
985 WARN("Failed to initialize resource, returning %#x\n", hr);
986 HeapFree(GetProcessHeap(), 0, object);
991 TRACE("(%p) : Created resource %p\n", This, object);
993 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
995 *ppTexture = (IWineD3DTexture *)object;
997 basetexture_init(&object->baseTexture, Levels, Usage);
998 object->width = Width;
999 object->height = Height;
1001 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1003 object->baseTexture.minMipLookup = minMipLookup;
1004 object->baseTexture.magLookup = magLookup;
1006 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1007 object->baseTexture.magLookup = magLookup_noFilter;
1010 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1011 /* Precalculated scaling for 'faked' non power of two texture coords.
1012 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
1013 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
1014 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
1016 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
1017 object->baseTexture.pow2Matrix[0] = 1.0;
1018 object->baseTexture.pow2Matrix[5] = 1.0;
1019 object->baseTexture.pow2Matrix[10] = 1.0;
1020 object->baseTexture.pow2Matrix[15] = 1.0;
1021 object->target = GL_TEXTURE_2D;
1022 object->cond_np2 = TRUE;
1023 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1024 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
1025 (Width != pow2Width || Height != pow2Height) &&
1026 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
1028 object->baseTexture.pow2Matrix[0] = (float)Width;
1029 object->baseTexture.pow2Matrix[5] = (float)Height;
1030 object->baseTexture.pow2Matrix[10] = 1.0;
1031 object->baseTexture.pow2Matrix[15] = 1.0;
1032 object->target = GL_TEXTURE_RECTANGLE_ARB;
1033 object->cond_np2 = TRUE;
1034 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1036 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
1037 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
1038 object->baseTexture.pow2Matrix[10] = 1.0;
1039 object->baseTexture.pow2Matrix[15] = 1.0;
1040 object->target = GL_TEXTURE_2D;
1041 object->cond_np2 = FALSE;
1043 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
1045 /* Generate all the surfaces */
1048 for (i = 0; i < object->baseTexture.levels; i++)
1050 /* use the callback to create the texture surface */
1051 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpH, Format,
1052 Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i]);
1053 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1054 FIXME("Failed to create surface %p\n", object);
1056 object->surfaces[i] = NULL;
1057 IWineD3DTexture_Release((IWineD3DTexture *)object);
1063 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1064 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1065 surface_set_texture_target(object->surfaces[i], object->target);
1066 /* calculate the next mipmap level */
1067 tmpW = max(1, tmpW >> 1);
1068 tmpH = max(1, tmpH >> 1);
1070 object->baseTexture.internal_preload = texture_internal_preload;
1072 TRACE("(%p) : Created texture %p\n", This, object);
1076 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1077 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1078 IWineD3DVolumeTexture **ppVolumeTexture, HANDLE *pSharedHandle, IUnknown *parent)
1080 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1081 IWineD3DVolumeTextureImpl *object;
1088 /* TODO: It should only be possible to create textures for formats
1089 that are reported as supported */
1090 if (WINED3DFMT_UNKNOWN >= Format) {
1091 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1092 return WINED3DERR_INVALIDCALL;
1094 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1095 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
1096 return WINED3DERR_INVALIDCALL;
1099 /* Calculate levels for mip mapping */
1100 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1102 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1104 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1105 return WINED3DERR_INVALIDCALL;
1110 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1111 return WINED3DERR_INVALIDCALL;
1118 Levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
1119 TRACE("Calculated levels = %d\n", Levels);
1122 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1125 ERR("Out of memory\n");
1126 *ppVolumeTexture = NULL;
1127 return WINED3DERR_OUTOFVIDEOMEMORY;
1130 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1131 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUMETEXTURE, This, 0, Usage, Format, Pool, parent);
1134 WARN("Failed to initialize resource, returning %#x\n", hr);
1135 HeapFree(GetProcessHeap(), 0, object);
1136 *ppVolumeTexture = NULL;
1140 TRACE("(%p) : Created resource %p\n", This, object);
1142 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1144 basetexture_init(&object->baseTexture, Levels, Usage);
1146 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1147 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1149 /* Is NP2 support for volumes needed? */
1150 object->baseTexture.pow2Matrix[ 0] = 1.0;
1151 object->baseTexture.pow2Matrix[ 5] = 1.0;
1152 object->baseTexture.pow2Matrix[10] = 1.0;
1153 object->baseTexture.pow2Matrix[15] = 1.0;
1155 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1157 object->baseTexture.minMipLookup = minMipLookup;
1158 object->baseTexture.magLookup = magLookup;
1160 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1161 object->baseTexture.magLookup = magLookup_noFilter;
1164 /* Generate all the surfaces */
1169 for (i = 0; i < object->baseTexture.levels; i++)
1172 /* Create the volume */
1173 hr = IWineD3DDeviceParent_CreateVolume(This->device_parent, parent,
1174 tmpW, tmpH, tmpD, Format, Pool, Usage, &object->volumes[i]);
1176 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1177 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1178 *ppVolumeTexture = NULL;
1182 /* Set its container to this object */
1183 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1185 /* calculate the next mipmap level */
1186 tmpW = max(1, tmpW >> 1);
1187 tmpH = max(1, tmpH >> 1);
1188 tmpD = max(1, tmpD >> 1);
1190 object->baseTexture.internal_preload = volumetexture_internal_preload;
1192 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1193 TRACE("(%p) : Created volume texture %p\n", This, object);
1197 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1198 UINT Width, UINT Height, UINT Depth,
1200 WINED3DFORMAT Format, WINED3DPOOL Pool,
1201 IWineD3DVolume** ppVolume,
1202 HANDLE* pSharedHandle, IUnknown *parent) {
1204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1205 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1206 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1209 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1210 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1211 return WINED3DERR_INVALIDCALL;
1214 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1217 ERR("Out of memory\n");
1219 return WINED3DERR_OUTOFVIDEOMEMORY;
1222 object->lpVtbl = &IWineD3DVolume_Vtbl;
1223 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUME, This,
1224 Width * Height * Depth * formatDesc->bpp, Usage, Format, Pool, parent);
1227 WARN("Failed to initialize resource, returning %#x\n", hr);
1228 HeapFree(GetProcessHeap(), 0, object);
1233 TRACE("(%p) : Created resource %p\n", This, object);
1235 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1237 *ppVolume = (IWineD3DVolume *)object;
1239 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1240 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1242 object->currentDesc.Width = Width;
1243 object->currentDesc.Height = Height;
1244 object->currentDesc.Depth = Depth;
1245 object->bytesPerPixel = formatDesc->bpp;
1247 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1248 object->lockable = TRUE;
1249 object->locked = FALSE;
1250 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1251 object->dirty = TRUE;
1253 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1258 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1259 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1260 IWineD3DCubeTexture **ppCubeTexture, HANDLE *pSharedHandle, IUnknown *parent)
1262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1263 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1267 unsigned int pow2EdgeLength;
1269 /* TODO: It should only be possible to create textures for formats
1270 that are reported as supported */
1271 if (WINED3DFMT_UNKNOWN >= Format) {
1272 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1273 return WINED3DERR_INVALIDCALL;
1276 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1277 WARN("(%p) : Tried to create not supported cube texture\n", This);
1278 return WINED3DERR_INVALIDCALL;
1281 /* Calculate levels for mip mapping */
1282 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1284 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1286 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1287 return WINED3DERR_INVALIDCALL;
1292 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1293 return WINED3DERR_INVALIDCALL;
1300 Levels = wined3d_log2i(EdgeLength) + 1;
1301 TRACE("Calculated levels = %d\n", Levels);
1304 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1307 ERR("Out of memory\n");
1308 *ppCubeTexture = NULL;
1309 return WINED3DERR_OUTOFVIDEOMEMORY;
1312 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1313 hr = resource_init(&object->resource, WINED3DRTYPE_CUBETEXTURE, This, 0, Usage, Format, Pool, parent);
1316 WARN("Failed to initialize resource, returning %#x\n", hr);
1317 HeapFree(GetProcessHeap(), 0, object);
1318 *ppCubeTexture = NULL;
1322 TRACE("(%p) : Created resource %p\n", This, object);
1324 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1326 basetexture_init(&object->baseTexture, Levels, Usage);
1328 TRACE("(%p) Create Cube Texture\n", This);
1330 /* Find the nearest pow2 match */
1332 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1334 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
1335 /* Precalculated scaling for 'faked' non power of two texture coords */
1336 object->baseTexture.pow2Matrix[ 0] = 1.0;
1337 object->baseTexture.pow2Matrix[ 5] = 1.0;
1338 object->baseTexture.pow2Matrix[10] = 1.0;
1339 object->baseTexture.pow2Matrix[15] = 1.0;
1341 /* Precalculated scaling for 'faked' non power of two texture coords */
1342 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1343 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1344 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1345 object->baseTexture.pow2Matrix[15] = 1.0;
1348 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1350 object->baseTexture.minMipLookup = minMipLookup;
1351 object->baseTexture.magLookup = magLookup;
1353 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1354 object->baseTexture.magLookup = magLookup_noFilter;
1357 /* Generate all the surfaces */
1359 for (i = 0; i < object->baseTexture.levels; i++) {
1361 /* Create the 6 faces */
1362 for (j = 0; j < 6; j++) {
1363 static const GLenum cube_targets[6] = {
1364 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1365 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1366 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1367 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1368 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1369 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1372 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpW,
1373 Format, Usage, Pool, i /* Level */, j, &object->surfaces[j][i]);
1376 FIXME("(%p) Failed to create surface\n",object);
1377 IWineD3DCubeTexture_Release((IWineD3DCubeTexture *)object);
1378 *ppCubeTexture = NULL;
1381 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1382 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1383 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1385 tmpW = max(1, tmpW >> 1);
1387 object->baseTexture.internal_preload = cubetexture_internal_preload;
1389 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1390 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1394 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1396 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1397 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1398 const IWineD3DQueryVtbl *vtable;
1400 /* Just a check to see if we support this type of query */
1402 case WINED3DQUERYTYPE_OCCLUSION:
1403 TRACE("(%p) occlusion query\n", This);
1404 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1407 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1409 vtable = &IWineD3DOcclusionQuery_Vtbl;
1412 case WINED3DQUERYTYPE_EVENT:
1413 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1414 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1415 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1417 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1419 vtable = &IWineD3DEventQuery_Vtbl;
1423 case WINED3DQUERYTYPE_VCACHE:
1424 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1425 case WINED3DQUERYTYPE_VERTEXSTATS:
1426 case WINED3DQUERYTYPE_TIMESTAMP:
1427 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1428 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1429 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1430 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1431 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1432 case WINED3DQUERYTYPE_PIXELTIMINGS:
1433 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1434 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1436 /* Use the base Query vtable until we have a special one for each query */
1437 vtable = &IWineD3DQuery_Vtbl;
1438 FIXME("(%p) Unhandled query type %d\n", This, Type);
1440 if(NULL == ppQuery || hr != WINED3D_OK) {
1444 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1447 ERR("Out of memory\n");
1449 return WINED3DERR_OUTOFVIDEOMEMORY;
1452 object->lpVtbl = vtable;
1453 object->type = Type;
1454 object->state = QUERY_CREATED;
1455 object->wineD3DDevice = This;
1456 object->parent = parent;
1459 *ppQuery = (IWineD3DQuery *)object;
1461 /* allocated the 'extended' data based on the type of query requested */
1463 case WINED3DQUERYTYPE_OCCLUSION:
1464 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1465 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1467 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1468 TRACE("(%p) Allocating data for an occlusion query\n", This);
1470 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1472 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1476 case WINED3DQUERYTYPE_EVENT:
1477 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1478 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1480 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1482 if(GL_SUPPORT(APPLE_FENCE)) {
1483 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1484 checkGLcall("glGenFencesAPPLE");
1485 } else if(GL_SUPPORT(NV_FENCE)) {
1486 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1487 checkGLcall("glGenFencesNV");
1492 case WINED3DQUERYTYPE_VCACHE:
1493 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1494 case WINED3DQUERYTYPE_VERTEXSTATS:
1495 case WINED3DQUERYTYPE_TIMESTAMP:
1496 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1497 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1498 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1499 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1500 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1501 case WINED3DQUERYTYPE_PIXELTIMINGS:
1502 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1503 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1505 object->extendedData = 0;
1506 FIXME("(%p) Unhandled query type %d\n",This , Type);
1508 TRACE("(%p) : Created Query %p\n", This, object);
1512 /*****************************************************************************
1513 * IWineD3DDeviceImpl_SetupFullscreenWindow
1515 * Helper function that modifies a HWND's Style and ExStyle for proper
1519 * iface: Pointer to the IWineD3DDevice interface
1520 * window: Window to setup
1522 *****************************************************************************/
1523 static LONG fullscreen_style(LONG orig_style) {
1524 LONG style = orig_style;
1525 style &= ~WS_CAPTION;
1526 style &= ~WS_THICKFRAME;
1528 /* Make sure the window is managed, otherwise we won't get keyboard input */
1529 style |= WS_POPUP | WS_SYSMENU;
1534 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1535 LONG exStyle = orig_exStyle;
1537 /* Filter out window decorations */
1538 exStyle &= ~WS_EX_WINDOWEDGE;
1539 exStyle &= ~WS_EX_CLIENTEDGE;
1544 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1547 LONG style, exStyle;
1548 /* Don't do anything if an original style is stored.
1549 * That shouldn't happen
1551 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1552 if (This->style || This->exStyle) {
1553 ERR("(%p): Want to change the window parameters of HWND %p, but "
1554 "another style is stored for restoration afterwards\n", This, window);
1557 /* Get the parameters and save them */
1558 style = GetWindowLongW(window, GWL_STYLE);
1559 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1560 This->style = style;
1561 This->exStyle = exStyle;
1563 style = fullscreen_style(style);
1564 exStyle = fullscreen_exStyle(exStyle);
1566 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1567 This->style, This->exStyle, style, exStyle);
1569 SetWindowLongW(window, GWL_STYLE, style);
1570 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1572 /* Inform the window about the update. */
1573 SetWindowPos(window, HWND_TOP, 0, 0,
1574 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1577 /*****************************************************************************
1578 * IWineD3DDeviceImpl_RestoreWindow
1580 * Helper function that restores a windows' properties when taking it out
1581 * of fullscreen mode
1584 * iface: Pointer to the IWineD3DDevice interface
1585 * window: Window to setup
1587 *****************************************************************************/
1588 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1590 LONG style, exStyle;
1592 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1593 * switch, do nothing
1595 if (!This->style && !This->exStyle) return;
1597 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1598 This, window, This->style, This->exStyle);
1600 style = GetWindowLongW(window, GWL_STYLE);
1601 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1603 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1604 * Some applications change it before calling Reset() when switching between windowed and
1605 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1607 if(style == fullscreen_style(This->style) &&
1608 exStyle == fullscreen_style(This->exStyle)) {
1609 SetWindowLongW(window, GWL_STYLE, This->style);
1610 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1613 /* Delete the old values */
1617 /* Inform the window about the update */
1618 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1619 0, 0, 0, 0, /* Pos, Size, ignored */
1620 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1623 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1624 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1625 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1626 IUnknown *parent, WINED3DSURFTYPE surface_type)
1628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1631 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1633 IUnknown *bufferParent;
1634 BOOL displaymode_set = FALSE;
1635 WINED3DDISPLAYMODE Mode;
1636 const StaticPixelFormatDesc *formatDesc;
1638 TRACE("(%p) : Created Additional Swap Chain\n", This);
1640 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1641 * does a device hold a reference to a swap chain giving them a lifetime of the device
1642 * or does the swap chain notify the device of its destruction.
1643 *******************************/
1645 /* Check the params */
1646 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1647 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1648 return WINED3DERR_INVALIDCALL;
1649 } else if (pPresentationParameters->BackBufferCount > 1) {
1650 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");
1653 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1656 ERR("Out of memory\n");
1657 *ppSwapChain = NULL;
1658 return WINED3DERR_OUTOFVIDEOMEMORY;
1661 switch(surface_type) {
1663 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1665 case SURFACE_OPENGL:
1666 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1668 case SURFACE_UNKNOWN:
1669 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1670 HeapFree(GetProcessHeap(), 0, object);
1671 return WINED3DERR_INVALIDCALL;
1673 object->wineD3DDevice = This;
1674 object->parent = parent;
1677 *ppSwapChain = (IWineD3DSwapChain *)object;
1679 /*********************
1680 * Lookup the window Handle and the relating X window handle
1681 ********************/
1683 /* Setup hwnd we are using, plus which display this equates to */
1684 object->win_handle = pPresentationParameters->hDeviceWindow;
1685 if (!object->win_handle) {
1686 object->win_handle = This->createParms.hFocusWindow;
1688 if(!pPresentationParameters->Windowed && object->win_handle) {
1689 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1690 pPresentationParameters->BackBufferWidth,
1691 pPresentationParameters->BackBufferHeight);
1694 hDc = GetDC(object->win_handle);
1695 TRACE("Using hDc %p\n", hDc);
1698 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1699 return WINED3DERR_NOTAVAILABLE;
1702 /* Get info on the current display setup */
1703 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1704 object->orig_width = Mode.Width;
1705 object->orig_height = Mode.Height;
1706 object->orig_fmt = Mode.Format;
1707 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1709 if (pPresentationParameters->Windowed &&
1710 ((pPresentationParameters->BackBufferWidth == 0) ||
1711 (pPresentationParameters->BackBufferHeight == 0) ||
1712 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1715 GetClientRect(object->win_handle, &Rect);
1717 if (pPresentationParameters->BackBufferWidth == 0) {
1718 pPresentationParameters->BackBufferWidth = Rect.right;
1719 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1721 if (pPresentationParameters->BackBufferHeight == 0) {
1722 pPresentationParameters->BackBufferHeight = Rect.bottom;
1723 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1725 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1726 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1727 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1731 /* Put the correct figures in the presentation parameters */
1732 TRACE("Copying across presentation parameters\n");
1733 object->presentParms = *pPresentationParameters;
1735 TRACE("calling rendertarget CB\n");
1736 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1737 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1738 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1739 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1740 if (SUCCEEDED(hr)) {
1741 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1742 if(surface_type == SURFACE_OPENGL) {
1743 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1746 ERR("Failed to create the front buffer\n");
1750 /*********************
1751 * Windowed / Fullscreen
1752 *******************/
1755 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1756 * so we should really check to see if there is a fullscreen swapchain already
1757 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1758 **************************************/
1760 if (!pPresentationParameters->Windowed) {
1761 WINED3DDISPLAYMODE mode;
1764 /* Change the display settings */
1765 mode.Width = pPresentationParameters->BackBufferWidth;
1766 mode.Height = pPresentationParameters->BackBufferHeight;
1767 mode.Format = pPresentationParameters->BackBufferFormat;
1768 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1770 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1771 displaymode_set = TRUE;
1775 * Create an opengl context for the display visual
1776 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1777 * use different properties after that point in time. FIXME: How to handle when requested format
1778 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1779 * it chooses is identical to the one already being used!
1780 **********************************/
1781 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1783 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1784 if(!object->context) {
1785 ERR("Failed to create the context array\n");
1789 object->num_contexts = 1;
1791 if(surface_type == SURFACE_OPENGL) {
1792 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1793 if (!object->context[0]) {
1794 ERR("Failed to create a new context\n");
1795 hr = WINED3DERR_NOTAVAILABLE;
1798 TRACE("Context created (HWND=%p, glContext=%p)\n",
1799 object->win_handle, object->context[0]->glCtx);
1803 /*********************
1804 * Create the back, front and stencil buffers
1805 *******************/
1806 if(object->presentParms.BackBufferCount > 0) {
1809 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1810 if(!object->backBuffer) {
1811 ERR("Out of memory\n");
1816 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1817 TRACE("calling rendertarget CB\n");
1818 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1819 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1820 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1821 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1823 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1825 ERR("Cannot create new back buffer\n");
1828 if(surface_type == SURFACE_OPENGL) {
1830 glDrawBuffer(GL_BACK);
1831 checkGLcall("glDrawBuffer(GL_BACK)");
1836 object->backBuffer = NULL;
1838 /* Single buffering - draw to front buffer */
1839 if(surface_type == SURFACE_OPENGL) {
1841 glDrawBuffer(GL_FRONT);
1842 checkGLcall("glDrawBuffer(GL_FRONT)");
1847 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1848 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1849 TRACE("Creating depth stencil buffer\n");
1850 if (This->auto_depth_stencil_buffer == NULL ) {
1851 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1852 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1853 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1854 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1855 &This->auto_depth_stencil_buffer);
1856 if (SUCCEEDED(hr)) {
1857 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1859 ERR("Failed to create the auto depth stencil\n");
1865 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1867 TRACE("Created swapchain %p\n", object);
1868 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1872 if (displaymode_set) {
1876 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1879 /* Change the display settings */
1880 memset(&devmode, 0, sizeof(devmode));
1881 devmode.dmSize = sizeof(devmode);
1882 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1883 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1884 devmode.dmPelsWidth = object->orig_width;
1885 devmode.dmPelsHeight = object->orig_height;
1886 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1889 if (object->backBuffer) {
1891 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1892 if(object->backBuffer[i]) {
1893 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1894 IUnknown_Release(bufferParent); /* once for the get parent */
1895 if (IUnknown_Release(bufferParent) > 0) {
1896 FIXME("(%p) Something's still holding the back buffer\n",This);
1900 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1901 object->backBuffer = NULL;
1903 if(object->context && object->context[0])
1904 DestroyContext(This, object->context[0]);
1905 if(object->frontBuffer) {
1906 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1907 IUnknown_Release(bufferParent); /* once for the get parent */
1908 if (IUnknown_Release(bufferParent) > 0) {
1909 FIXME("(%p) Something's still holding the front buffer\n",This);
1912 HeapFree(GetProcessHeap(), 0, object);
1916 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1917 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1919 TRACE("(%p)\n", This);
1921 return This->NumberOfSwapChains;
1924 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1926 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1928 if(iSwapChain < This->NumberOfSwapChains) {
1929 *pSwapChain = This->swapchains[iSwapChain];
1930 IWineD3DSwapChain_AddRef(*pSwapChain);
1931 TRACE("(%p) returning %p\n", This, *pSwapChain);
1934 TRACE("Swapchain out of range\n");
1936 return WINED3DERR_INVALIDCALL;
1941 * Vertex Declaration
1943 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1944 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1946 IWineD3DVertexDeclarationImpl *object = NULL;
1947 HRESULT hr = WINED3D_OK;
1949 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1950 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1952 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1955 ERR("Out of memory\n");
1956 *ppVertexDeclaration = NULL;
1957 return WINED3DERR_OUTOFVIDEOMEMORY;
1960 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
1961 object->wineD3DDevice = This;
1962 object->parent = parent;
1965 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1967 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1969 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1970 *ppVertexDeclaration = NULL;
1976 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1977 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1979 unsigned int idx, idx2;
1980 unsigned int offset;
1981 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1982 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1983 BOOL has_blend_idx = has_blend &&
1984 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1985 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1986 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1987 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1988 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1989 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1990 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1992 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1993 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1995 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1996 WINED3DVERTEXELEMENT *elements = NULL;
1999 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
2000 if (has_blend_idx) num_blends--;
2002 /* Compute declaration size */
2003 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
2004 has_psize + has_diffuse + has_specular + num_textures + 1;
2006 /* convert the declaration */
2007 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
2011 elements[size-1] = end_element;
2014 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
2015 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2016 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
2018 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
2019 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2020 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
2023 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2024 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
2026 elements[idx].UsageIndex = 0;
2029 if (has_blend && (num_blends > 0)) {
2030 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
2031 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2033 switch(num_blends) {
2034 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
2035 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
2036 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
2037 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
2039 ERR("Unexpected amount of blend values: %u\n", num_blends);
2042 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
2043 elements[idx].UsageIndex = 0;
2046 if (has_blend_idx) {
2047 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
2048 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
2049 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
2050 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
2051 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2053 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2054 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
2055 elements[idx].UsageIndex = 0;
2059 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2060 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
2061 elements[idx].UsageIndex = 0;
2065 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2066 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
2067 elements[idx].UsageIndex = 0;
2071 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2072 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
2073 elements[idx].UsageIndex = 0;
2077 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2078 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
2079 elements[idx].UsageIndex = 1;
2082 for (idx2 = 0; idx2 < num_textures; idx2++) {
2083 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
2084 switch (numcoords) {
2085 case WINED3DFVF_TEXTUREFORMAT1:
2086 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2088 case WINED3DFVF_TEXTUREFORMAT2:
2089 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
2091 case WINED3DFVF_TEXTUREFORMAT3:
2092 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2094 case WINED3DFVF_TEXTUREFORMAT4:
2095 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2098 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
2099 elements[idx].UsageIndex = idx2;
2103 /* Now compute offsets, and initialize the rest of the fields */
2104 for (idx = 0, offset = 0; idx < size-1; idx++) {
2105 elements[idx].Stream = 0;
2106 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
2107 elements[idx].Offset = offset;
2108 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
2111 *ppVertexElements = elements;
2115 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
2116 WINED3DVERTEXELEMENT* elements = NULL;
2117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2121 size = ConvertFvfToDeclaration(This, Fvf, &elements);
2122 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
2124 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
2125 HeapFree(GetProcessHeap(), 0, elements);
2126 if (hr != S_OK) return hr;
2131 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
2132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2133 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
2134 HRESULT hr = WINED3D_OK;
2136 if (!pFunction) return WINED3DERR_INVALIDCALL;
2138 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2141 ERR("Out of memory\n");
2142 *ppVertexShader = NULL;
2143 return WINED3DERR_OUTOFVIDEOMEMORY;
2146 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
2147 object->parent = parent;
2148 shader_init(&object->baseShader, iface, IWineD3DVertexShaderImpl_shader_ins);
2149 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2150 *ppVertexShader = (IWineD3DVertexShader *)object;
2152 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
2154 if (vertex_declaration) {
2155 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
2158 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
2161 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2162 IWineD3DVertexShader_Release(*ppVertexShader);
2163 *ppVertexShader = NULL;
2170 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
2171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2172 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2173 HRESULT hr = WINED3D_OK;
2175 if (!pFunction) return WINED3DERR_INVALIDCALL;
2177 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2180 ERR("Out of memory\n");
2181 *ppPixelShader = NULL;
2182 return WINED3DERR_OUTOFVIDEOMEMORY;
2185 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2186 object->parent = parent;
2187 shader_init(&object->baseShader, iface, IWineD3DPixelShaderImpl_shader_ins);
2188 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2189 *ppPixelShader = (IWineD3DPixelShader *)object;
2191 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2193 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
2196 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2197 IWineD3DPixelShader_Release(*ppPixelShader);
2198 *ppPixelShader = NULL;
2205 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2206 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2209 IWineD3DPaletteImpl *object;
2211 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2213 /* Create the new object */
2214 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2216 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2217 return E_OUTOFMEMORY;
2220 object->lpVtbl = &IWineD3DPalette_Vtbl;
2222 object->Flags = Flags;
2223 object->parent = Parent;
2224 object->wineD3DDevice = This;
2225 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2226 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2229 HeapFree( GetProcessHeap(), 0, object);
2230 return E_OUTOFMEMORY;
2233 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2235 IWineD3DPalette_Release((IWineD3DPalette *) object);
2239 *Palette = (IWineD3DPalette *) object;
2244 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2248 HDC dcb = NULL, dcs = NULL;
2249 WINEDDCOLORKEY colorkey;
2251 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2254 GetObjectA(hbm, sizeof(BITMAP), &bm);
2255 dcb = CreateCompatibleDC(NULL);
2257 SelectObject(dcb, hbm);
2261 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2262 * couldn't be loaded
2264 memset(&bm, 0, sizeof(bm));
2269 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2270 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2271 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
2273 ERR("Wine logo requested, but failed to create surface\n");
2278 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2279 if(FAILED(hr)) goto out;
2280 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2281 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2283 colorkey.dwColorSpaceLowValue = 0;
2284 colorkey.dwColorSpaceHighValue = 0;
2285 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2287 /* Fill the surface with a white color to show that wined3d is there */
2288 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2301 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2303 /* Under DirectX you can have texture stage operations even if no texture is
2304 bound, whereas opengl will only do texture operations when a valid texture is
2305 bound. We emulate this by creating dummy textures and binding them to each
2306 texture stage, but disable all stages by default. Hence if a stage is enabled
2307 then the default texture will kick in until replaced by a SetTexture call */
2310 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2311 /* The dummy texture does not have client storage backing */
2312 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2313 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2315 for (i = 0; i < GL_LIMITS(textures); i++) {
2316 GLubyte white = 255;
2318 /* Make appropriate texture active */
2319 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2320 checkGLcall("glActiveTextureARB");
2322 /* Generate an opengl texture name */
2323 glGenTextures(1, &This->dummyTextureName[i]);
2324 checkGLcall("glGenTextures");
2325 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2327 /* Generate a dummy 2d texture (not using 1d because they cause many
2328 * DRI drivers fall back to sw) */
2329 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2330 checkGLcall("glBindTexture");
2332 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2333 checkGLcall("glTexImage2D");
2335 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2336 /* Reenable because if supported it is enabled by default */
2337 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2338 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2344 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2345 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2348 IWineD3DSwapChainImpl *swapchain = NULL;
2353 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2355 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2356 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2358 /* TODO: Test if OpenGL is compiled in and loaded */
2360 TRACE("(%p) : Creating stateblock\n", This);
2361 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2362 hr = IWineD3DDevice_CreateStateBlock(iface,
2364 (IWineD3DStateBlock **)&This->stateBlock,
2366 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2367 WARN("Failed to create stateblock\n");
2370 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2371 This->updateStateBlock = This->stateBlock;
2372 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2374 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2375 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2377 This->NumberOfPalettes = 1;
2378 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2379 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2380 ERR("Out of memory!\n");
2383 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2384 if(!This->palettes[0]) {
2385 ERR("Out of memory!\n");
2388 for (i = 0; i < 256; ++i) {
2389 This->palettes[0][i].peRed = 0xFF;
2390 This->palettes[0][i].peGreen = 0xFF;
2391 This->palettes[0][i].peBlue = 0xFF;
2392 This->palettes[0][i].peFlags = 0xFF;
2394 This->currentPalette = 0;
2396 /* Initialize the texture unit mapping to a 1:1 mapping */
2397 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2398 if (state < GL_LIMITS(fragment_samplers)) {
2399 This->texUnitMap[state] = state;
2400 This->rev_tex_unit_map[state] = state;
2402 This->texUnitMap[state] = -1;
2403 This->rev_tex_unit_map[state] = -1;
2407 /* Setup the implicit swapchain */
2408 TRACE("Creating implicit swapchain\n");
2409 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2410 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2413 WARN("Failed to create implicit swapchain\n");
2417 This->NumberOfSwapChains = 1;
2418 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2419 if(!This->swapchains) {
2420 ERR("Out of memory!\n");
2423 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2425 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2426 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2427 This->render_targets[0] = swapchain->backBuffer[0];
2428 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2431 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2432 This->render_targets[0] = swapchain->frontBuffer;
2433 This->lastActiveRenderTarget = swapchain->frontBuffer;
2435 IWineD3DSurface_AddRef(This->render_targets[0]);
2436 This->activeContext = swapchain->context[0];
2437 This->lastThread = GetCurrentThreadId();
2439 /* Depth Stencil support */
2440 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2441 if (NULL != This->stencilBufferTarget) {
2442 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2445 hr = This->shader_backend->shader_alloc_private(iface);
2447 TRACE("Shader private data couldn't be allocated\n");
2450 hr = This->frag_pipe->alloc_private(iface);
2452 TRACE("Fragment pipeline private data couldn't be allocated\n");
2455 hr = This->blitter->alloc_private(iface);
2457 TRACE("Blitter private data couldn't be allocated\n");
2461 /* Set up some starting GL setup */
2463 /* Setup all the devices defaults */
2464 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2465 create_dummy_textures(This);
2469 /* Initialize the current view state */
2470 This->view_ident = 1;
2471 This->contexts[0]->last_was_rhw = 0;
2472 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2473 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2475 switch(wined3d_settings.offscreen_rendering_mode) {
2478 This->offscreenBuffer = GL_BACK;
2481 case ORM_BACKBUFFER:
2483 if(This->activeContext->aux_buffers > 0) {
2484 TRACE("Using auxilliary buffer for offscreen rendering\n");
2485 This->offscreenBuffer = GL_AUX0;
2487 TRACE("Using back buffer for offscreen rendering\n");
2488 This->offscreenBuffer = GL_BACK;
2493 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2496 /* Clear the screen */
2497 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2498 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2501 This->d3d_initialized = TRUE;
2503 if(wined3d_settings.logo) {
2504 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2506 This->highest_dirty_ps_const = 0;
2507 This->highest_dirty_vs_const = 0;
2511 HeapFree(GetProcessHeap(), 0, This->render_targets);
2512 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2513 HeapFree(GetProcessHeap(), 0, This->swapchains);
2514 This->NumberOfSwapChains = 0;
2515 if(This->palettes) {
2516 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2517 HeapFree(GetProcessHeap(), 0, This->palettes);
2519 This->NumberOfPalettes = 0;
2521 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2523 if(This->stateBlock) {
2524 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2525 This->stateBlock = NULL;
2527 if (This->blit_priv) {
2528 This->blitter->free_private(iface);
2530 if (This->fragment_priv) {
2531 This->frag_pipe->free_private(iface);
2533 if (This->shader_priv) {
2534 This->shader_backend->shader_free_private(iface);
2539 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2540 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2543 IWineD3DSwapChainImpl *swapchain = NULL;
2546 /* Setup the implicit swapchain */
2547 TRACE("Creating implicit swapchain\n");
2548 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2549 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2552 WARN("Failed to create implicit swapchain\n");
2556 This->NumberOfSwapChains = 1;
2557 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2558 if(!This->swapchains) {
2559 ERR("Out of memory!\n");
2562 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2566 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
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 TRACE("Deleting high order patches\n");
2586 for(i = 0; i < PATCHMAP_SIZE; i++) {
2587 struct list *e1, *e2;
2588 struct WineD3DRectPatch *patch;
2589 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2590 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2591 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2595 /* Delete the palette conversion shader if it is around */
2596 if(This->paletteConversionShader) {
2598 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2600 This->paletteConversionShader = 0;
2603 /* Delete the pbuffer context if there is any */
2604 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2606 /* Delete the mouse cursor texture */
2607 if(This->cursorTexture) {
2609 glDeleteTextures(1, &This->cursorTexture);
2611 This->cursorTexture = 0;
2614 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2615 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2617 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2618 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2621 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2622 * private data, it might contain opengl pointers
2624 if(This->depth_blt_texture) {
2625 glDeleteTextures(1, &This->depth_blt_texture);
2626 This->depth_blt_texture = 0;
2628 if (This->depth_blt_rb) {
2629 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2630 This->depth_blt_rb = 0;
2631 This->depth_blt_rb_w = 0;
2632 This->depth_blt_rb_h = 0;
2635 /* Release the update stateblock */
2636 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2637 if(This->updateStateBlock != This->stateBlock)
2638 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2640 This->updateStateBlock = NULL;
2642 { /* because were not doing proper internal refcounts releasing the primary state block
2643 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2644 to set this->stateBlock = NULL; first */
2645 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2646 This->stateBlock = NULL;
2648 /* Release the stateblock */
2649 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2650 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2654 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2655 This->blitter->free_private(iface);
2656 This->frag_pipe->free_private(iface);
2657 This->shader_backend->shader_free_private(iface);
2659 /* Release the buffers (with sanity checks)*/
2660 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2661 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2662 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2663 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2665 This->stencilBufferTarget = NULL;
2667 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2668 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2669 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2671 TRACE("Setting rendertarget to NULL\n");
2672 This->render_targets[0] = NULL;
2674 if (This->auto_depth_stencil_buffer) {
2675 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2676 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2678 This->auto_depth_stencil_buffer = NULL;
2681 for(i=0; i < This->NumberOfSwapChains; i++) {
2682 TRACE("Releasing the implicit swapchain %d\n", i);
2683 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2684 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2688 HeapFree(GetProcessHeap(), 0, This->swapchains);
2689 This->swapchains = NULL;
2690 This->NumberOfSwapChains = 0;
2692 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2693 HeapFree(GetProcessHeap(), 0, This->palettes);
2694 This->palettes = NULL;
2695 This->NumberOfPalettes = 0;
2697 HeapFree(GetProcessHeap(), 0, This->render_targets);
2698 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2699 This->render_targets = NULL;
2700 This->draw_buffers = NULL;
2702 This->d3d_initialized = FALSE;
2706 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2710 for(i=0; i < This->NumberOfSwapChains; i++) {
2711 TRACE("Releasing the implicit swapchain %d\n", i);
2712 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2713 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2717 HeapFree(GetProcessHeap(), 0, This->swapchains);
2718 This->swapchains = NULL;
2719 This->NumberOfSwapChains = 0;
2723 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2724 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2725 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2727 * There is no way to deactivate thread safety once it is enabled.
2729 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2732 /*For now just store the flag(needed in case of ddraw) */
2733 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2738 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2739 const WINED3DDISPLAYMODE* pMode) {
2741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2743 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2746 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2748 /* Resize the screen even without a window:
2749 * The app could have unset it with SetCooperativeLevel, but not called
2750 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2751 * but we don't have any hwnd
2754 memset(&devmode, 0, sizeof(devmode));
2755 devmode.dmSize = sizeof(devmode);
2756 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2757 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2758 devmode.dmPelsWidth = pMode->Width;
2759 devmode.dmPelsHeight = pMode->Height;
2761 devmode.dmDisplayFrequency = pMode->RefreshRate;
2762 if (pMode->RefreshRate != 0) {
2763 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2766 /* Only change the mode if necessary */
2767 if( (This->ddraw_width == pMode->Width) &&
2768 (This->ddraw_height == pMode->Height) &&
2769 (This->ddraw_format == pMode->Format) &&
2770 (pMode->RefreshRate == 0) ) {
2774 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2775 if (ret != DISP_CHANGE_SUCCESSFUL) {
2776 if(devmode.dmDisplayFrequency != 0) {
2777 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2778 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2779 devmode.dmDisplayFrequency = 0;
2780 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2782 if(ret != DISP_CHANGE_SUCCESSFUL) {
2783 return WINED3DERR_NOTAVAILABLE;
2787 /* Store the new values */
2788 This->ddraw_width = pMode->Width;
2789 This->ddraw_height = pMode->Height;
2790 This->ddraw_format = pMode->Format;
2792 /* And finally clip mouse to our screen */
2793 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2794 ClipCursor(&clip_rc);
2799 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2801 *ppD3D= This->wineD3D;
2802 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2803 IWineD3D_AddRef(*ppD3D);
2807 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2810 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2811 (This->adapter->TextureRam/(1024*1024)),
2812 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2813 /* return simulated texture memory left */
2814 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2818 * Get / Set Stream Source
2820 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2821 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2824 IWineD3DBuffer *oldSrc;
2826 if (StreamNumber >= MAX_STREAMS) {
2827 WARN("Stream out of range %d\n", StreamNumber);
2828 return WINED3DERR_INVALIDCALL;
2829 } else if(OffsetInBytes & 0x3) {
2830 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2831 return WINED3DERR_INVALIDCALL;
2834 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2835 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2837 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2839 if(oldSrc == pStreamData &&
2840 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2841 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2842 TRACE("Application is setting the old values over, nothing to do\n");
2846 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2848 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2849 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2852 /* Handle recording of state blocks */
2853 if (This->isRecordingState) {
2854 TRACE("Recording... not performing anything\n");
2855 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2856 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2860 if (pStreamData != NULL) {
2861 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2862 IWineD3DBuffer_AddRef(pStreamData);
2864 if (oldSrc != NULL) {
2865 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2866 IWineD3DBuffer_Release(oldSrc);
2869 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2874 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2875 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2879 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2880 This->stateBlock->streamSource[StreamNumber],
2881 This->stateBlock->streamOffset[StreamNumber],
2882 This->stateBlock->streamStride[StreamNumber]);
2884 if (StreamNumber >= MAX_STREAMS) {
2885 WARN("Stream out of range %d\n", StreamNumber);
2886 return WINED3DERR_INVALIDCALL;
2888 *pStream = This->stateBlock->streamSource[StreamNumber];
2889 *pStride = This->stateBlock->streamStride[StreamNumber];
2891 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2894 if (*pStream != NULL) {
2895 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2900 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2902 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2903 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2905 /* Verify input at least in d3d9 this is invalid*/
2906 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2907 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2908 return WINED3DERR_INVALIDCALL;
2910 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2911 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2912 return WINED3DERR_INVALIDCALL;
2915 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2916 return WINED3DERR_INVALIDCALL;
2919 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2920 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2922 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2923 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2925 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2926 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2927 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2933 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2936 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2937 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2939 TRACE("(%p) : returning %d\n", This, *Divider);
2945 * Get / Set & Multiply Transform
2947 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2950 /* Most of this routine, comments included copied from ddraw tree initially: */
2951 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2953 /* Handle recording of state blocks */
2954 if (This->isRecordingState) {
2955 TRACE("Recording... not performing anything\n");
2956 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2957 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2962 * If the new matrix is the same as the current one,
2963 * we cut off any further processing. this seems to be a reasonable
2964 * optimization because as was noticed, some apps (warcraft3 for example)
2965 * tend towards setting the same matrix repeatedly for some reason.
2967 * From here on we assume that the new matrix is different, wherever it matters.
2969 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2970 TRACE("The app is setting the same matrix over again\n");
2973 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2977 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2978 where ViewMat = Camera space, WorldMat = world space.
2980 In OpenGL, camera and world space is combined into GL_MODELVIEW
2981 matrix. The Projection matrix stay projection matrix.
2984 /* Capture the times we can just ignore the change for now */
2985 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2986 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2987 /* Handled by the state manager */
2990 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2994 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2996 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2997 *pMatrix = This->stateBlock->transforms[State];
3001 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
3002 const WINED3DMATRIX *mat = NULL;
3005 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
3006 * below means it will be recorded in a state block change, but it
3007 * works regardless where it is recorded.
3008 * If this is found to be wrong, change to StateBlock.
3010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3011 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
3013 if (State <= HIGHEST_TRANSFORMSTATE)
3015 mat = &This->updateStateBlock->transforms[State];
3017 FIXME("Unhandled transform state!!\n");
3020 multiply_matrix(&temp, mat, pMatrix);
3022 /* Apply change via set transform - will reapply to eg. lights this way */
3023 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
3029 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
3030 you can reference any indexes you want as long as that number max are enabled at any
3031 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
3032 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
3033 but when recording, just build a chain pretty much of commands to be replayed. */
3035 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
3037 PLIGHTINFOEL *object = NULL;
3038 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3042 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
3044 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
3048 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
3049 return WINED3DERR_INVALIDCALL;
3052 switch(pLight->Type) {
3053 case WINED3DLIGHT_POINT:
3054 case WINED3DLIGHT_SPOT:
3055 case WINED3DLIGHT_PARALLELPOINT:
3056 case WINED3DLIGHT_GLSPOT:
3057 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
3060 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
3061 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
3062 return WINED3DERR_INVALIDCALL;
3066 case WINED3DLIGHT_DIRECTIONAL:
3067 /* Ignores attenuation */
3071 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
3072 return WINED3DERR_INVALIDCALL;
3075 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3076 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3077 if(object->OriginalIndex == Index) break;
3082 TRACE("Adding new light\n");
3083 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
3085 ERR("Out of memory error when allocating a light\n");
3086 return E_OUTOFMEMORY;
3088 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
3089 object->glIndex = -1;
3090 object->OriginalIndex = Index;
3091 object->changed = TRUE;
3094 /* Initialize the object */
3095 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,
3096 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
3097 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
3098 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
3099 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
3100 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
3101 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
3103 /* Save away the information */
3104 object->OriginalParms = *pLight;
3106 switch (pLight->Type) {
3107 case WINED3DLIGHT_POINT:
3109 object->lightPosn[0] = pLight->Position.x;
3110 object->lightPosn[1] = pLight->Position.y;
3111 object->lightPosn[2] = pLight->Position.z;
3112 object->lightPosn[3] = 1.0f;
3113 object->cutoff = 180.0f;
3117 case WINED3DLIGHT_DIRECTIONAL:
3119 object->lightPosn[0] = -pLight->Direction.x;
3120 object->lightPosn[1] = -pLight->Direction.y;
3121 object->lightPosn[2] = -pLight->Direction.z;
3122 object->lightPosn[3] = 0.0;
3123 object->exponent = 0.0f;
3124 object->cutoff = 180.0f;
3127 case WINED3DLIGHT_SPOT:
3129 object->lightPosn[0] = pLight->Position.x;
3130 object->lightPosn[1] = pLight->Position.y;
3131 object->lightPosn[2] = pLight->Position.z;
3132 object->lightPosn[3] = 1.0;
3135 object->lightDirn[0] = pLight->Direction.x;
3136 object->lightDirn[1] = pLight->Direction.y;
3137 object->lightDirn[2] = pLight->Direction.z;
3138 object->lightDirn[3] = 1.0;
3141 * opengl-ish and d3d-ish spot lights use too different models for the
3142 * light "intensity" as a function of the angle towards the main light direction,
3143 * so we only can approximate very roughly.
3144 * however spot lights are rather rarely used in games (if ever used at all).
3145 * furthermore if still used, probably nobody pays attention to such details.
3147 if (pLight->Falloff == 0) {
3148 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3149 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3150 * will always be 1.0 for both of them, and we don't have to care for the
3151 * rest of the rather complex calculation
3153 object->exponent = 0;
3155 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3156 if (rho < 0.0001) rho = 0.0001f;
3157 object->exponent = -0.3/log(cos(rho/2));
3159 if (object->exponent > 128.0) {
3160 object->exponent = 128.0;
3162 object->cutoff = pLight->Phi*90/M_PI;
3168 FIXME("Unrecognized light type %d\n", pLight->Type);
3171 /* Update the live definitions if the light is currently assigned a glIndex */
3172 if (object->glIndex != -1 && !This->isRecordingState) {
3173 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3178 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3179 PLIGHTINFOEL *lightInfo = NULL;
3180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3181 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3183 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3185 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3186 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3187 if(lightInfo->OriginalIndex == Index) break;
3191 if (lightInfo == NULL) {
3192 TRACE("Light information requested but light not defined\n");
3193 return WINED3DERR_INVALIDCALL;
3196 *pLight = lightInfo->OriginalParms;
3201 * Get / Set Light Enable
3202 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3204 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3205 PLIGHTINFOEL *lightInfo = NULL;
3206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3207 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3209 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3211 /* Tests show true = 128...not clear why */
3212 Enable = Enable? 128: 0;
3214 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3215 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3216 if(lightInfo->OriginalIndex == Index) break;
3219 TRACE("Found light: %p\n", lightInfo);
3221 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3222 if (lightInfo == NULL) {
3224 TRACE("Light enabled requested but light not defined, so defining one!\n");
3225 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3227 /* Search for it again! Should be fairly quick as near head of list */
3228 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3229 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3230 if(lightInfo->OriginalIndex == Index) break;
3233 if (lightInfo == NULL) {
3234 FIXME("Adding default lights has failed dismally\n");
3235 return WINED3DERR_INVALIDCALL;
3239 lightInfo->enabledChanged = TRUE;
3241 if(lightInfo->glIndex != -1) {
3242 if(!This->isRecordingState) {
3243 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3246 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3247 lightInfo->glIndex = -1;
3249 TRACE("Light already disabled, nothing to do\n");
3251 lightInfo->enabled = FALSE;
3253 lightInfo->enabled = TRUE;
3254 if (lightInfo->glIndex != -1) {
3256 TRACE("Nothing to do as light was enabled\n");
3259 /* Find a free gl light */
3260 for(i = 0; i < This->maxConcurrentLights; i++) {
3261 if(This->updateStateBlock->activeLights[i] == NULL) {
3262 This->updateStateBlock->activeLights[i] = lightInfo;
3263 lightInfo->glIndex = i;
3267 if(lightInfo->glIndex == -1) {
3268 /* Our tests show that Windows returns D3D_OK in this situation, even with
3269 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3270 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3271 * as well for those lights.
3273 * TODO: Test how this affects rendering
3275 WARN("Too many concurrently active lights\n");
3279 /* i == lightInfo->glIndex */
3280 if(!This->isRecordingState) {
3281 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3289 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3291 PLIGHTINFOEL *lightInfo = NULL;
3292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3294 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3295 TRACE("(%p) : for idx(%d)\n", This, Index);
3297 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3298 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3299 if(lightInfo->OriginalIndex == Index) break;
3303 if (lightInfo == NULL) {
3304 TRACE("Light enabled state requested but light not defined\n");
3305 return WINED3DERR_INVALIDCALL;
3307 /* true is 128 according to SetLightEnable */
3308 *pEnable = lightInfo->enabled ? 128 : 0;
3313 * Get / Set Clip Planes
3315 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3317 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3319 /* Validate Index */
3320 if (Index >= GL_LIMITS(clipplanes)) {
3321 TRACE("Application has requested clipplane this device doesn't support\n");
3322 return WINED3DERR_INVALIDCALL;
3325 This->updateStateBlock->changed.clipplane |= 1 << Index;
3327 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3328 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3329 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3330 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3331 TRACE("Application is setting old values over, nothing to do\n");
3335 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3336 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3337 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3338 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3340 /* Handle recording of state blocks */
3341 if (This->isRecordingState) {
3342 TRACE("Recording... not performing anything\n");
3346 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3351 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3353 TRACE("(%p) : for idx %d\n", This, Index);
3355 /* Validate Index */
3356 if (Index >= GL_LIMITS(clipplanes)) {
3357 TRACE("Application has requested clipplane this device doesn't support\n");
3358 return WINED3DERR_INVALIDCALL;
3361 pPlane[0] = This->stateBlock->clipplane[Index][0];
3362 pPlane[1] = This->stateBlock->clipplane[Index][1];
3363 pPlane[2] = This->stateBlock->clipplane[Index][2];
3364 pPlane[3] = This->stateBlock->clipplane[Index][3];
3369 * Get / Set Clip Plane Status
3370 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3372 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3374 FIXME("(%p) : stub\n", This);
3375 if (NULL == pClipStatus) {
3376 return WINED3DERR_INVALIDCALL;
3378 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3379 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3383 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3385 FIXME("(%p) : stub\n", This);
3386 if (NULL == pClipStatus) {
3387 return WINED3DERR_INVALIDCALL;
3389 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3390 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3395 * Get / Set Material
3397 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3400 This->updateStateBlock->changed.material = TRUE;
3401 This->updateStateBlock->material = *pMaterial;
3403 /* Handle recording of state blocks */
3404 if (This->isRecordingState) {
3405 TRACE("Recording... not performing anything\n");
3409 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3413 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3414 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3415 *pMaterial = This->updateStateBlock->material;
3416 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3417 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3418 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3419 pMaterial->Ambient.b, pMaterial->Ambient.a);
3420 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3421 pMaterial->Specular.b, pMaterial->Specular.a);
3422 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3423 pMaterial->Emissive.b, pMaterial->Emissive.a);
3424 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3432 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3434 IWineD3DIndexBuffer *oldIdxs;
3436 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3437 oldIdxs = This->updateStateBlock->pIndexData;
3439 This->updateStateBlock->changed.indices = TRUE;
3440 This->updateStateBlock->pIndexData = pIndexData;
3442 /* Handle recording of state blocks */
3443 if (This->isRecordingState) {
3444 TRACE("Recording... not performing anything\n");
3445 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3446 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3450 if(oldIdxs != pIndexData) {
3451 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3452 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3453 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3458 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3461 *ppIndexData = This->stateBlock->pIndexData;
3463 /* up ref count on ppindexdata */
3465 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3466 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3468 TRACE("(%p) No index data set\n", This);
3470 TRACE("Returning %p\n", *ppIndexData);
3475 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3476 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3478 TRACE("(%p)->(%d)\n", This, BaseIndex);
3480 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3481 TRACE("Application is setting the old value over, nothing to do\n");
3485 This->updateStateBlock->baseVertexIndex = BaseIndex;
3487 if (This->isRecordingState) {
3488 TRACE("Recording... not performing anything\n");
3491 /* The base vertex index affects the stream sources */
3492 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3496 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3498 TRACE("(%p) : base_index %p\n", This, base_index);
3500 *base_index = This->stateBlock->baseVertexIndex;
3502 TRACE("Returning %u\n", *base_index);
3508 * Get / Set Viewports
3510 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3511 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3513 TRACE("(%p)\n", This);
3514 This->updateStateBlock->changed.viewport = TRUE;
3515 This->updateStateBlock->viewport = *pViewport;
3517 /* Handle recording of state blocks */
3518 if (This->isRecordingState) {
3519 TRACE("Recording... not performing anything\n");
3523 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3524 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3526 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3531 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3533 TRACE("(%p)\n", This);
3534 *pViewport = This->stateBlock->viewport;
3539 * Get / Set Render States
3540 * TODO: Verify against dx9 definitions
3542 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3545 DWORD oldValue = This->stateBlock->renderState[State];
3547 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3549 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3550 This->updateStateBlock->renderState[State] = Value;
3552 /* Handle recording of state blocks */
3553 if (This->isRecordingState) {
3554 TRACE("Recording... not performing anything\n");
3558 /* Compared here and not before the assignment to allow proper stateblock recording */
3559 if(Value == oldValue) {
3560 TRACE("Application is setting the old value over, nothing to do\n");
3562 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3568 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3570 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3571 *pValue = This->stateBlock->renderState[State];
3576 * Get / Set Sampler States
3577 * TODO: Verify against dx9 definitions
3580 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3584 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3585 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3587 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3588 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3591 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3592 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3593 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3596 * SetSampler is designed to allow for more than the standard up to 8 textures
3597 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3598 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3600 * http://developer.nvidia.com/object/General_FAQ.html#t6
3602 * There are two new settings for GForce
3604 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3605 * and the texture one:
3606 * GL_MAX_TEXTURE_COORDS_ARB.
3607 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3610 oldValue = This->stateBlock->samplerState[Sampler][Type];
3611 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3612 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3614 /* Handle recording of state blocks */
3615 if (This->isRecordingState) {
3616 TRACE("Recording... not performing anything\n");
3620 if(oldValue == Value) {
3621 TRACE("Application is setting the old value over, nothing to do\n");
3625 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3630 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3633 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3634 This, Sampler, debug_d3dsamplerstate(Type), Type);
3636 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3637 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3640 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3641 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3642 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3644 *Value = This->stateBlock->samplerState[Sampler][Type];
3645 TRACE("(%p) : Returning %#x\n", This, *Value);
3650 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3653 This->updateStateBlock->changed.scissorRect = TRUE;
3654 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3655 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3658 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3660 if(This->isRecordingState) {
3661 TRACE("Recording... not performing anything\n");
3665 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3670 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3673 *pRect = This->updateStateBlock->scissorRect;
3674 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3678 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3680 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3682 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3684 This->updateStateBlock->vertexDecl = pDecl;
3685 This->updateStateBlock->changed.vertexDecl = TRUE;
3687 if (This->isRecordingState) {
3688 TRACE("Recording... not performing anything\n");
3690 } else if(pDecl == oldDecl) {
3691 /* Checked after the assignment to allow proper stateblock recording */
3692 TRACE("Application is setting the old declaration over, nothing to do\n");
3696 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3700 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3703 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3705 *ppDecl = This->stateBlock->vertexDecl;
3706 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3710 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3712 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3714 This->updateStateBlock->vertexShader = pShader;
3715 This->updateStateBlock->changed.vertexShader = TRUE;
3717 if (This->isRecordingState) {
3718 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3719 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3720 TRACE("Recording... not performing anything\n");
3722 } else if(oldShader == pShader) {
3723 /* Checked here to allow proper stateblock recording */
3724 TRACE("App is setting the old shader over, nothing to do\n");
3728 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3729 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3730 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3732 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3737 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3740 if (NULL == ppShader) {
3741 return WINED3DERR_INVALIDCALL;
3743 *ppShader = This->stateBlock->vertexShader;
3744 if( NULL != *ppShader)
3745 IWineD3DVertexShader_AddRef(*ppShader);
3747 TRACE("(%p) : returning %p\n", This, *ppShader);
3751 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3752 IWineD3DDevice *iface,
3754 CONST BOOL *srcData,
3757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3758 int i, cnt = min(count, MAX_CONST_B - start);
3760 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3761 iface, srcData, start, count);
3763 if (srcData == NULL || cnt < 0)
3764 return WINED3DERR_INVALIDCALL;
3766 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3767 for (i = 0; i < cnt; i++)
3768 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3770 for (i = start; i < cnt + start; ++i) {
3771 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3774 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3779 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3780 IWineD3DDevice *iface,
3785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3786 int cnt = min(count, MAX_CONST_B - start);
3788 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3789 iface, dstData, start, count);
3791 if (dstData == NULL || cnt < 0)
3792 return WINED3DERR_INVALIDCALL;
3794 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3798 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3799 IWineD3DDevice *iface,
3804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3805 int i, cnt = min(count, MAX_CONST_I - start);
3807 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3808 iface, srcData, start, count);
3810 if (srcData == NULL || cnt < 0)
3811 return WINED3DERR_INVALIDCALL;
3813 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3814 for (i = 0; i < cnt; i++)
3815 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3816 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3818 for (i = start; i < cnt + start; ++i) {
3819 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3822 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3827 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3828 IWineD3DDevice *iface,
3833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3834 int cnt = min(count, MAX_CONST_I - start);
3836 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3837 iface, dstData, start, count);
3839 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3840 return WINED3DERR_INVALIDCALL;
3842 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3846 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3847 IWineD3DDevice *iface,
3849 CONST float *srcData,
3852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3855 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3856 iface, srcData, start, count);
3858 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3859 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3860 return WINED3DERR_INVALIDCALL;
3862 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3864 for (i = 0; i < count; i++)
3865 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3866 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3869 if (!This->isRecordingState)
3871 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3872 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3875 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3876 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3881 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3882 IWineD3DDevice *iface,
3887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3888 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3890 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3891 iface, dstData, start, count);
3893 if (dstData == NULL || cnt < 0)
3894 return WINED3DERR_INVALIDCALL;
3896 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3900 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3902 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3904 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3908 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3909 int i = This->rev_tex_unit_map[unit];
3910 int j = This->texUnitMap[stage];
3912 This->texUnitMap[stage] = unit;
3913 if (i != -1 && i != stage) {
3914 This->texUnitMap[i] = -1;
3917 This->rev_tex_unit_map[unit] = stage;
3918 if (j != -1 && j != unit) {
3919 This->rev_tex_unit_map[j] = -1;
3923 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3926 This->fixed_function_usage_map = 0;
3927 for (i = 0; i < MAX_TEXTURES; ++i) {
3928 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3929 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3930 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3931 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3932 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3933 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3934 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3935 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3937 if (color_op == WINED3DTOP_DISABLE) {
3938 /* Not used, and disable higher stages */
3942 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3943 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3944 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3945 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3946 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3947 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3948 This->fixed_function_usage_map |= (1 << i);
3951 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3952 This->fixed_function_usage_map |= (1 << (i + 1));
3957 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3961 device_update_fixed_function_usage_map(This);
3962 ffu_map = This->fixed_function_usage_map;
3964 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3965 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3966 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3968 if (!(ffu_map & 1)) continue;
3970 if (This->texUnitMap[i] != i) {
3971 device_map_stage(This, i, i);
3972 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3973 markTextureStagesDirty(This, i);
3979 /* Now work out the mapping */
3981 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3983 if (!(ffu_map & 1)) continue;
3985 if (This->texUnitMap[i] != tex) {
3986 device_map_stage(This, i, tex);
3987 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3988 markTextureStagesDirty(This, i);
3995 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3996 const DWORD *sampler_tokens =
3997 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
4000 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
4001 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
4002 device_map_stage(This, i, i);
4003 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4004 if (i < MAX_TEXTURES) {
4005 markTextureStagesDirty(This, i);
4011 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
4012 const DWORD *vshader_sampler_tokens, int unit)
4014 int current_mapping = This->rev_tex_unit_map[unit];
4016 if (current_mapping == -1) {
4017 /* Not currently used */
4021 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
4022 /* Used by a fragment sampler */
4024 if (!pshader_sampler_tokens) {
4025 /* No pixel shader, check fixed function */
4026 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
4029 /* Pixel shader, check the shader's sampler map */
4030 return !pshader_sampler_tokens[current_mapping];
4033 /* Used by a vertex sampler */
4034 return !vshader_sampler_tokens[current_mapping];
4037 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
4038 const DWORD *vshader_sampler_tokens =
4039 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
4040 const DWORD *pshader_sampler_tokens = NULL;
4041 int start = GL_LIMITS(combined_samplers) - 1;
4045 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
4047 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
4048 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
4049 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
4052 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
4053 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
4054 if (vshader_sampler_tokens[i]) {
4055 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
4057 /* Already mapped somewhere */
4061 while (start >= 0) {
4062 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
4063 device_map_stage(This, vsampler_idx, start);
4064 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
4076 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
4077 BOOL vs = use_vs(This->stateBlock);
4078 BOOL ps = use_ps(This->stateBlock);
4081 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
4082 * that would be really messy and require shader recompilation
4083 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
4084 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
4087 device_map_psamplers(This);
4089 device_map_fixed_function_samplers(This);
4093 device_map_vsamplers(This, ps);
4097 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4098 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4099 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4100 This->updateStateBlock->pixelShader = pShader;
4101 This->updateStateBlock->changed.pixelShader = TRUE;
4103 /* Handle recording of state blocks */
4104 if (This->isRecordingState) {
4105 TRACE("Recording... not performing anything\n");
4108 if (This->isRecordingState) {
4109 TRACE("Recording... not performing anything\n");
4110 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4111 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4115 if(pShader == oldShader) {
4116 TRACE("App is setting the old pixel shader over, nothing to do\n");
4120 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4121 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4123 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4124 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4129 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4132 if (NULL == ppShader) {
4133 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4134 return WINED3DERR_INVALIDCALL;
4137 *ppShader = This->stateBlock->pixelShader;
4138 if (NULL != *ppShader) {
4139 IWineD3DPixelShader_AddRef(*ppShader);
4141 TRACE("(%p) : returning %p\n", This, *ppShader);
4145 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4146 IWineD3DDevice *iface,
4148 CONST BOOL *srcData,
4151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4152 int i, cnt = min(count, MAX_CONST_B - start);
4154 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4155 iface, srcData, start, count);
4157 if (srcData == NULL || cnt < 0)
4158 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 int i, cnt = min(count, MAX_CONST_I - start);
4201 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4202 iface, srcData, start, count);
4204 if (srcData == NULL || cnt < 0)
4205 return WINED3DERR_INVALIDCALL;
4207 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4208 for (i = 0; i < cnt; i++)
4209 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4210 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4212 for (i = start; i < cnt + start; ++i) {
4213 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4216 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4221 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4222 IWineD3DDevice *iface,
4227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4228 int cnt = min(count, MAX_CONST_I - start);
4230 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4231 iface, dstData, start, count);
4233 if (dstData == NULL || cnt < 0)
4234 return WINED3DERR_INVALIDCALL;
4236 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4240 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4241 IWineD3DDevice *iface,
4243 CONST float *srcData,
4246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4249 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4250 iface, srcData, start, count);
4252 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4253 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4254 return WINED3DERR_INVALIDCALL;
4256 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4258 for (i = 0; i < count; i++)
4259 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4260 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4263 if (!This->isRecordingState)
4265 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4266 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4269 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4270 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4275 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4276 IWineD3DDevice *iface,
4281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4282 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4284 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4285 iface, dstData, start, count);
4287 if (dstData == NULL || cnt < 0)
4288 return WINED3DERR_INVALIDCALL;
4290 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4294 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4295 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4296 const WineDirect3DVertexStridedData *lpStrideData, struct wined3d_buffer *dest, DWORD dwFlags)
4298 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4300 DWORD DestFVF = dest->fvf;
4302 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4306 if (lpStrideData->u.s.normal.lpData) {
4307 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4310 if (lpStrideData->u.s.position.lpData == NULL) {
4311 ERR("Source has no position mask\n");
4312 return WINED3DERR_INVALIDCALL;
4315 /* We might access VBOs from this code, so hold the lock */
4318 if (dest->resource.allocatedMemory == NULL) {
4319 /* This may happen if we do direct locking into a vbo. Unlikely,
4320 * but theoretically possible(ddraw processvertices test)
4322 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4323 if(!dest->resource.allocatedMemory) {
4325 ERR("Out of memory\n");
4326 return E_OUTOFMEMORY;
4328 if (dest->buffer_object)
4331 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4332 checkGLcall("glBindBufferARB");
4333 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4335 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4337 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4338 checkGLcall("glUnmapBufferARB");
4342 /* Get a pointer into the destination vbo(create one if none exists) and
4343 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4345 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4347 dest->flags |= WINED3D_BUFFER_CREATEBO;
4348 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4351 if (dest->buffer_object)
4353 unsigned char extrabytes = 0;
4354 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4355 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4356 * this may write 4 extra bytes beyond the area that should be written
4358 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4359 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4360 if(!dest_conv_addr) {
4361 ERR("Out of memory\n");
4362 /* Continue without storing converted vertices */
4364 dest_conv = dest_conv_addr;
4368 * a) WINED3DRS_CLIPPING is enabled
4369 * b) WINED3DVOP_CLIP is passed
4371 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4372 static BOOL warned = FALSE;
4374 * The clipping code is not quite correct. Some things need
4375 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4376 * so disable clipping for now.
4377 * (The graphics in Half-Life are broken, and my processvertices
4378 * test crashes with IDirect3DDevice3)
4384 FIXME("Clipping is broken and disabled for now\n");
4386 } else doClip = FALSE;
4387 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4389 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4392 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4393 WINED3DTS_PROJECTION,
4395 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4396 WINED3DTS_WORLDMATRIX(0),
4399 TRACE("View mat:\n");
4400 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);
4401 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);
4402 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);
4403 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);
4405 TRACE("Proj mat:\n");
4406 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);
4407 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);
4408 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);
4409 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);
4411 TRACE("World mat:\n");
4412 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);
4413 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);
4414 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);
4415 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);
4417 /* Get the viewport */
4418 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4419 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4420 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4422 multiply_matrix(&mat,&view_mat,&world_mat);
4423 multiply_matrix(&mat,&proj_mat,&mat);
4425 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4427 for (i = 0; i < dwCount; i+= 1) {
4428 unsigned int tex_index;
4430 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4431 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4432 /* The position first */
4434 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4436 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4438 /* Multiplication with world, view and projection matrix */
4439 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);
4440 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);
4441 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);
4442 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);
4444 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4446 /* WARNING: The following things are taken from d3d7 and were not yet checked
4447 * against d3d8 or d3d9!
4450 /* Clipping conditions: From msdn
4452 * A vertex is clipped if it does not match the following requirements
4456 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4458 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4459 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4464 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4465 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4468 /* "Normal" viewport transformation (not clipped)
4469 * 1) The values are divided by rhw
4470 * 2) The y axis is negative, so multiply it with -1
4471 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4472 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4473 * 4) Multiply x with Width/2 and add Width/2
4474 * 5) The same for the height
4475 * 6) Add the viewpoint X and Y to the 2D coordinates and
4476 * The minimum Z value to z
4477 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4479 * Well, basically it's simply a linear transformation into viewport
4491 z *= vp.MaxZ - vp.MinZ;
4493 x += vp.Width / 2 + vp.X;
4494 y += vp.Height / 2 + vp.Y;
4499 /* That vertex got clipped
4500 * Contrary to OpenGL it is not dropped completely, it just
4501 * undergoes a different calculation.
4503 TRACE("Vertex got clipped\n");
4510 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4511 * outside of the main vertex buffer memory. That needs some more
4516 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4519 ( (float *) dest_ptr)[0] = x;
4520 ( (float *) dest_ptr)[1] = y;
4521 ( (float *) dest_ptr)[2] = z;
4522 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4524 dest_ptr += 3 * sizeof(float);
4526 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4527 dest_ptr += sizeof(float);
4532 ( (float *) dest_conv)[0] = x * w;
4533 ( (float *) dest_conv)[1] = y * w;
4534 ( (float *) dest_conv)[2] = z * w;
4535 ( (float *) dest_conv)[3] = w;
4537 dest_conv += 3 * sizeof(float);
4539 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4540 dest_conv += sizeof(float);
4544 if (DestFVF & WINED3DFVF_PSIZE) {
4545 dest_ptr += sizeof(DWORD);
4546 if(dest_conv) dest_conv += sizeof(DWORD);
4548 if (DestFVF & WINED3DFVF_NORMAL) {
4549 const float *normal =
4550 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4551 /* AFAIK this should go into the lighting information */
4552 FIXME("Didn't expect the destination to have a normal\n");
4553 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4555 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4559 if (DestFVF & WINED3DFVF_DIFFUSE) {
4560 const DWORD *color_d =
4561 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4563 static BOOL warned = FALSE;
4566 ERR("No diffuse color in source, but destination has one\n");
4570 *( (DWORD *) dest_ptr) = 0xffffffff;
4571 dest_ptr += sizeof(DWORD);
4574 *( (DWORD *) dest_conv) = 0xffffffff;
4575 dest_conv += sizeof(DWORD);
4579 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4581 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4582 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4583 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4584 dest_conv += sizeof(DWORD);
4589 if (DestFVF & WINED3DFVF_SPECULAR) {
4590 /* What's the color value in the feedback buffer? */
4591 const DWORD *color_s =
4592 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4594 static BOOL warned = FALSE;
4597 ERR("No specular color in source, but destination has one\n");
4601 *( (DWORD *) dest_ptr) = 0xFF000000;
4602 dest_ptr += sizeof(DWORD);
4605 *( (DWORD *) dest_conv) = 0xFF000000;
4606 dest_conv += sizeof(DWORD);
4610 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4612 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4613 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4614 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4615 dest_conv += sizeof(DWORD);
4620 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4621 const float *tex_coord =
4622 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4623 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4625 ERR("No source texture, but destination requests one\n");
4626 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4627 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4630 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4632 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4639 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4640 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4641 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4642 dwCount * get_flexible_vertex_size(DestFVF),
4644 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4645 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4652 #undef copy_and_next
4654 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4655 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags)
4657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4658 WineDirect3DVertexStridedData strided;
4659 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4660 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4663 ERR("Output vertex declaration not implemented yet\n");
4666 /* Need any context to write to the vbo. */
4667 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4669 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4670 * control the streamIsUP flag, thus restore it afterwards.
4672 This->stateBlock->streamIsUP = FALSE;
4673 memset(&strided, 0, sizeof(strided));
4674 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4675 This->stateBlock->streamIsUP = streamWasUP;
4677 if(vbo || SrcStartIndex) {
4679 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4680 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4682 * Also get the start index in, but only loop over all elements if there's something to add at all.
4684 #define FIXSRC(type) \
4685 if(strided.u.s.type.VBO) { \
4686 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4687 strided.u.s.type.VBO = 0; \
4688 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4690 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object)); \
4691 vb->buffer_object = 0; \
4694 if(strided.u.s.type.lpData) { \
4695 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4698 FIXSRC(blendWeights);
4699 FIXSRC(blendMatrixIndices);
4704 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4705 FIXSRC(texCoords[i]);
4718 return process_vertices_strided(This, DestIndex, VertexCount, &strided,
4719 (struct wined3d_buffer *)pDestBuffer, Flags);
4723 * Get / Set Texture Stage States
4724 * TODO: Verify against dx9 definitions
4726 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4728 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4730 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4732 if (Stage >= MAX_TEXTURES) {
4733 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4737 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4738 This->updateStateBlock->textureState[Stage][Type] = Value;
4740 if (This->isRecordingState) {
4741 TRACE("Recording... not performing anything\n");
4745 /* Checked after the assignments to allow proper stateblock recording */
4746 if(oldValue == Value) {
4747 TRACE("App is setting the old value over, nothing to do\n");
4751 if(Stage > This->stateBlock->lowest_disabled_stage &&
4752 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4753 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4754 * Changes in other states are important on disabled stages too
4759 if(Type == WINED3DTSS_COLOROP) {
4762 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4763 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4764 * they have to be disabled
4766 * The current stage is dirtified below.
4768 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4769 TRACE("Additionally dirtifying stage %d\n", i);
4770 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4772 This->stateBlock->lowest_disabled_stage = Stage;
4773 TRACE("New lowest disabled: %d\n", Stage);
4774 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4775 /* Previously disabled stage enabled. Stages above it may need enabling
4776 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4777 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4779 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4782 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4783 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4786 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4787 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4789 This->stateBlock->lowest_disabled_stage = i;
4790 TRACE("New lowest disabled: %d\n", i);
4794 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4799 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4801 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4802 *pValue = This->updateStateBlock->textureState[Stage][Type];
4809 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4811 IWineD3DBaseTexture *oldTexture;
4813 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4815 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4816 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4819 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4820 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4821 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4824 oldTexture = This->updateStateBlock->textures[Stage];
4826 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4827 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4829 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4830 return WINED3DERR_INVALIDCALL;
4833 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4834 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4836 This->updateStateBlock->changed.textures |= 1 << Stage;
4837 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4838 This->updateStateBlock->textures[Stage] = pTexture;
4840 /* Handle recording of state blocks */
4841 if (This->isRecordingState) {
4842 TRACE("Recording... not performing anything\n");
4846 if(oldTexture == pTexture) {
4847 TRACE("App is setting the same texture again, nothing to do\n");
4851 /** NOTE: MSDN says that setTexture increases the reference count,
4852 * and that the application must set the texture back to null (or have a leaky application),
4853 * This means we should pass the refcount up to the parent
4854 *******************************/
4855 if (NULL != This->updateStateBlock->textures[Stage]) {
4856 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4857 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4858 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4860 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4862 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4864 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4867 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4868 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4869 * so the COLOROP and ALPHAOP have to be dirtified.
4871 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4872 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4874 if(bindCount == 1) {
4875 new->baseTexture.sampler = Stage;
4877 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4881 if (NULL != oldTexture) {
4882 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4883 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4885 IWineD3DBaseTexture_Release(oldTexture);
4886 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4887 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4888 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4891 if(bindCount && old->baseTexture.sampler == Stage) {
4893 /* Have to do a search for the other sampler(s) where the texture is bound to
4894 * Shouldn't happen as long as apps bind a texture only to one stage
4896 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4897 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4898 if(This->updateStateBlock->textures[i] == oldTexture) {
4899 old->baseTexture.sampler = i;
4906 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4911 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4914 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4916 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4917 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4920 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4921 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4922 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4925 *ppTexture=This->stateBlock->textures[Stage];
4927 IWineD3DBaseTexture_AddRef(*ppTexture);
4929 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4937 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4938 IWineD3DSurface **ppBackBuffer) {
4939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4940 IWineD3DSwapChain *swapChain;
4943 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4945 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4946 if (hr == WINED3D_OK) {
4947 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4948 IWineD3DSwapChain_Release(swapChain);
4950 *ppBackBuffer = NULL;
4955 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4957 WARN("(%p) : stub, calling idirect3d for now\n", This);
4958 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4961 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4963 IWineD3DSwapChain *swapChain;
4966 if(iSwapChain > 0) {
4967 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4968 if (hr == WINED3D_OK) {
4969 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4970 IWineD3DSwapChain_Release(swapChain);
4972 FIXME("(%p) Error getting display mode\n", This);
4975 /* Don't read the real display mode,
4976 but return the stored mode instead. X11 can't change the color
4977 depth, and some apps are pretty angry if they SetDisplayMode from
4978 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4980 Also don't relay to the swapchain because with ddraw it's possible
4981 that there isn't a swapchain at all */
4982 pMode->Width = This->ddraw_width;
4983 pMode->Height = This->ddraw_height;
4984 pMode->Format = This->ddraw_format;
4985 pMode->RefreshRate = 0;
4993 * Stateblock related functions
4996 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4998 IWineD3DStateBlock *stateblock;
5001 TRACE("(%p)\n", This);
5003 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
5005 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
5006 if (FAILED(hr)) return hr;
5008 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5009 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
5010 This->isRecordingState = TRUE;
5012 TRACE("(%p) recording stateblock %p\n", This, stateblock);
5017 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5020 IWineD3DStateBlockImpl *object = This->updateStateBlock;
5022 if (!This->isRecordingState) {
5023 WARN("(%p) not recording! returning error\n", This);
5024 *ppStateBlock = NULL;
5025 return WINED3DERR_INVALIDCALL;
5028 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
5030 DWORD map = object->changed.renderState[i];
5031 for (j = 0; map; map >>= 1, ++j)
5033 if (!(map & 1)) continue;
5035 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
5039 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
5041 DWORD map = object->changed.transform[i];
5042 for (j = 0; map; map >>= 1, ++j)
5044 if (!(map & 1)) continue;
5046 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
5049 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
5050 if(object->changed.vertexShaderConstantsF[i]) {
5051 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
5052 object->num_contained_vs_consts_f++;
5055 for(i = 0; i < MAX_CONST_I; i++) {
5056 if (object->changed.vertexShaderConstantsI & (1 << i))
5058 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
5059 object->num_contained_vs_consts_i++;
5062 for(i = 0; i < MAX_CONST_B; i++) {
5063 if (object->changed.vertexShaderConstantsB & (1 << i))
5065 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
5066 object->num_contained_vs_consts_b++;
5069 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
5071 if (object->changed.pixelShaderConstantsF[i])
5073 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
5074 ++object->num_contained_ps_consts_f;
5077 for(i = 0; i < MAX_CONST_I; i++) {
5078 if (object->changed.pixelShaderConstantsI & (1 << i))
5080 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
5081 object->num_contained_ps_consts_i++;
5084 for(i = 0; i < MAX_CONST_B; i++) {
5085 if (object->changed.pixelShaderConstantsB & (1 << i))
5087 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
5088 object->num_contained_ps_consts_b++;
5091 for(i = 0; i < MAX_TEXTURES; i++) {
5092 DWORD map = object->changed.textureState[i];
5094 for(j = 0; map; map >>= 1, ++j)
5096 if (!(map & 1)) continue;
5098 object->contained_tss_states[object->num_contained_tss_states].stage = i;
5099 object->contained_tss_states[object->num_contained_tss_states].state = j;
5100 ++object->num_contained_tss_states;
5103 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
5104 DWORD map = object->changed.samplerState[i];
5106 for (j = 0; map; map >>= 1, ++j)
5108 if (!(map & 1)) continue;
5110 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
5111 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
5112 ++object->num_contained_sampler_states;
5116 *ppStateBlock = (IWineD3DStateBlock*) object;
5117 This->isRecordingState = FALSE;
5118 This->updateStateBlock = This->stateBlock;
5119 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5120 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5121 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5126 * Scene related functions
5128 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5129 /* At the moment we have no need for any functionality at the beginning
5131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5132 TRACE("(%p)\n", This);
5135 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
5136 return WINED3DERR_INVALIDCALL;
5138 This->inScene = TRUE;
5142 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5144 TRACE("(%p)\n", This);
5146 if(!This->inScene) {
5147 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
5148 return WINED3DERR_INVALIDCALL;
5151 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5152 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5154 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5158 This->inScene = FALSE;
5162 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5163 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5164 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5166 IWineD3DSwapChain *swapChain = NULL;
5168 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5170 TRACE("(%p) Presenting the frame\n", This);
5172 for(i = 0 ; i < swapchains ; i ++) {
5174 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5175 TRACE("presentinng chain %d, %p\n", i, swapChain);
5176 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5177 IWineD3DSwapChain_Release(swapChain);
5183 /* Not called from the VTable (internal subroutine) */
5184 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5185 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5186 float Z, DWORD Stencil) {
5187 GLbitfield glMask = 0;
5189 WINED3DRECT curRect;
5191 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5192 UINT drawable_width, drawable_height;
5193 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5194 IWineD3DSwapChainImpl *swapchain = NULL;
5196 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5197 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5198 * for the cleared parts, and the untouched parts.
5200 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5201 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5202 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5203 * checking all this if the dest surface is in the drawable anyway.
5205 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5207 if(vp->X != 0 || vp->Y != 0 ||
5208 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5209 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5212 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5213 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5214 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5215 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5216 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5219 if(Count > 0 && pRects && (
5220 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5221 pRects[0].x2 < target->currentDesc.Width ||
5222 pRects[0].y2 < target->currentDesc.Height)) {
5223 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5230 target->get_drawable_size(target, &drawable_width, &drawable_height);
5232 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5235 /* Only set the values up once, as they are not changing */
5236 if (Flags & WINED3DCLEAR_STENCIL) {
5237 glClearStencil(Stencil);
5238 checkGLcall("glClearStencil");
5239 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5240 glStencilMask(0xFFFFFFFF);
5243 if (Flags & WINED3DCLEAR_ZBUFFER) {
5244 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5245 glDepthMask(GL_TRUE);
5247 checkGLcall("glClearDepth");
5248 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5249 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5251 if (vp->X != 0 || vp->Y != 0 ||
5252 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5253 surface_load_ds_location(This->stencilBufferTarget, location);
5255 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5256 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5257 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5258 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5259 surface_load_ds_location(This->stencilBufferTarget, location);
5261 else if (Count > 0 && pRects && (
5262 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5263 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5264 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5265 surface_load_ds_location(This->stencilBufferTarget, location);
5269 if (Flags & WINED3DCLEAR_TARGET) {
5270 TRACE("Clearing screen with glClear to color %x\n", Color);
5271 glClearColor(D3DCOLOR_R(Color),
5275 checkGLcall("glClearColor");
5277 /* Clear ALL colors! */
5278 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5279 glMask = glMask | GL_COLOR_BUFFER_BIT;
5282 vp_rect.left = vp->X;
5283 vp_rect.top = vp->Y;
5284 vp_rect.right = vp->X + vp->Width;
5285 vp_rect.bottom = vp->Y + vp->Height;
5286 if (!(Count > 0 && pRects)) {
5287 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5288 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5290 if(This->render_offscreen) {
5291 glScissor(vp_rect.left, vp_rect.top,
5292 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5294 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5295 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5297 checkGLcall("glScissor");
5299 checkGLcall("glClear");
5301 /* Now process each rect in turn */
5302 for (i = 0; i < Count; i++) {
5303 /* Note gl uses lower left, width/height */
5304 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5305 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5306 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5308 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5309 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5310 curRect.x1, (target->currentDesc.Height - curRect.y2),
5311 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5313 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5314 * The rectangle is not cleared, no error is returned, but further rectanlges are
5315 * still cleared if they are valid
5317 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5318 TRACE("Rectangle with negative dimensions, ignoring\n");
5322 if(This->render_offscreen) {
5323 glScissor(curRect.x1, curRect.y1,
5324 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5326 glScissor(curRect.x1, drawable_height - curRect.y2,
5327 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5329 checkGLcall("glScissor");
5332 checkGLcall("glClear");
5336 /* Restore the old values (why..?) */
5337 if (Flags & WINED3DCLEAR_STENCIL) {
5338 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5340 if (Flags & WINED3DCLEAR_TARGET) {
5341 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5342 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5343 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5344 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5345 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5347 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5348 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5350 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5352 if (Flags & WINED3DCLEAR_ZBUFFER) {
5353 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5354 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5355 surface_modify_ds_location(This->stencilBufferTarget, location);
5360 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5361 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5364 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5370 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5371 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5373 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5375 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5376 Count, pRects, Flags, Color, Z, Stencil);
5378 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5379 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5380 /* TODO: What about depth stencil buffers without stencil bits? */
5381 return WINED3DERR_INVALIDCALL;
5384 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5391 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5392 WINED3DPRIMITIVETYPE primitive_type)
5394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5396 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5398 This->updateStateBlock->changed.primitive_type = TRUE;
5399 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5402 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5403 WINED3DPRIMITIVETYPE *primitive_type)
5405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5407 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5409 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5411 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5414 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5418 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5420 if(!This->stateBlock->vertexDecl) {
5421 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5422 return WINED3DERR_INVALIDCALL;
5425 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5426 if(This->stateBlock->streamIsUP) {
5427 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5428 This->stateBlock->streamIsUP = FALSE;
5431 if(This->stateBlock->loadBaseVertexIndex != 0) {
5432 This->stateBlock->loadBaseVertexIndex = 0;
5433 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5435 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5436 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5437 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5441 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5442 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5446 IWineD3DIndexBuffer *pIB;
5447 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5450 pIB = This->stateBlock->pIndexData;
5452 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5453 * without an index buffer set. (The first time at least...)
5454 * D3D8 simply dies, but I doubt it can do much harm to return
5455 * D3DERR_INVALIDCALL there as well. */
5456 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5457 return WINED3DERR_INVALIDCALL;
5460 if(!This->stateBlock->vertexDecl) {
5461 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5462 return WINED3DERR_INVALIDCALL;
5465 if(This->stateBlock->streamIsUP) {
5466 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5467 This->stateBlock->streamIsUP = FALSE;
5469 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5471 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5472 This, minIndex, NumVertices, startIndex, index_count);
5474 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5475 if (IdxBufDsc.Format == WINED3DFMT_R16_UINT) {
5481 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5482 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5483 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5486 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5487 vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5492 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5493 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5498 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5499 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5501 if(!This->stateBlock->vertexDecl) {
5502 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5503 return WINED3DERR_INVALIDCALL;
5506 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5507 vb = This->stateBlock->streamSource[0];
5508 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5509 if (vb) IWineD3DBuffer_Release(vb);
5510 This->stateBlock->streamOffset[0] = 0;
5511 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5512 This->stateBlock->streamIsUP = TRUE;
5513 This->stateBlock->loadBaseVertexIndex = 0;
5515 /* TODO: Only mark dirty if drawing from a different UP address */
5516 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5518 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5519 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5521 /* MSDN specifies stream zero settings must be set to NULL */
5522 This->stateBlock->streamStride[0] = 0;
5523 This->stateBlock->streamSource[0] = NULL;
5525 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5526 * the new stream sources or use UP drawing again
5531 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5532 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5533 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5538 IWineD3DIndexBuffer *ib;
5540 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5541 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5542 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5544 if(!This->stateBlock->vertexDecl) {
5545 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5546 return WINED3DERR_INVALIDCALL;
5549 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5555 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5556 vb = This->stateBlock->streamSource[0];
5557 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5558 if (vb) IWineD3DBuffer_Release(vb);
5559 This->stateBlock->streamIsUP = TRUE;
5560 This->stateBlock->streamOffset[0] = 0;
5561 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5563 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5564 This->stateBlock->baseVertexIndex = 0;
5565 This->stateBlock->loadBaseVertexIndex = 0;
5566 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5567 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5568 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5570 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5571 idxStride, pIndexData, MinVertexIndex);
5573 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5574 This->stateBlock->streamSource[0] = NULL;
5575 This->stateBlock->streamStride[0] = 0;
5576 ib = This->stateBlock->pIndexData;
5578 IWineD3DIndexBuffer_Release(ib);
5579 This->stateBlock->pIndexData = NULL;
5581 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5582 * SetStreamSource to specify a vertex buffer
5588 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5589 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5593 /* Mark the state dirty until we have nicer tracking
5594 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5597 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5598 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5599 This->stateBlock->baseVertexIndex = 0;
5600 This->up_strided = DrawPrimStrideData;
5601 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5602 This->up_strided = NULL;
5606 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5607 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5608 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5611 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5613 /* Mark the state dirty until we have nicer tracking
5614 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5617 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5618 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5619 This->stateBlock->streamIsUP = TRUE;
5620 This->stateBlock->baseVertexIndex = 0;
5621 This->up_strided = DrawPrimStrideData;
5622 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5623 This->up_strided = NULL;
5627 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5628 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5629 * not callable by the app directly no parameter validation checks are needed here.
5631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5632 WINED3DLOCKED_BOX src;
5633 WINED3DLOCKED_BOX dst;
5635 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5637 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5638 * dirtification to improve loading performance.
5640 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5641 if(FAILED(hr)) return hr;
5642 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5644 IWineD3DVolume_UnlockBox(pSourceVolume);
5648 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5650 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5652 IWineD3DVolume_UnlockBox(pSourceVolume);
5654 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5659 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5660 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5662 HRESULT hr = WINED3D_OK;
5663 WINED3DRESOURCETYPE sourceType;
5664 WINED3DRESOURCETYPE destinationType;
5667 /* TODO: think about moving the code into IWineD3DBaseTexture */
5669 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5671 /* verify that the source and destination textures aren't NULL */
5672 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5673 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5674 This, pSourceTexture, pDestinationTexture);
5675 hr = WINED3DERR_INVALIDCALL;
5678 if (pSourceTexture == pDestinationTexture) {
5679 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5680 This, pSourceTexture, pDestinationTexture);
5681 hr = WINED3DERR_INVALIDCALL;
5683 /* Verify that the source and destination textures are the same type */
5684 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5685 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5687 if (sourceType != destinationType) {
5688 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5690 hr = WINED3DERR_INVALIDCALL;
5693 /* check that both textures have the identical numbers of levels */
5694 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5695 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5696 hr = WINED3DERR_INVALIDCALL;
5699 if (WINED3D_OK == hr) {
5700 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5702 /* Make sure that the destination texture is loaded */
5703 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5705 /* Update every surface level of the texture */
5706 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5708 switch (sourceType) {
5709 case WINED3DRTYPE_TEXTURE:
5711 IWineD3DSurface *srcSurface;
5712 IWineD3DSurface *destSurface;
5714 for (i = 0 ; i < levels ; ++i) {
5715 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5716 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5717 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5718 IWineD3DSurface_Release(srcSurface);
5719 IWineD3DSurface_Release(destSurface);
5720 if (WINED3D_OK != hr) {
5721 WARN("(%p) : Call to update surface failed\n", This);
5727 case WINED3DRTYPE_CUBETEXTURE:
5729 IWineD3DSurface *srcSurface;
5730 IWineD3DSurface *destSurface;
5731 WINED3DCUBEMAP_FACES faceType;
5733 for (i = 0 ; i < levels ; ++i) {
5734 /* Update each cube face */
5735 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5736 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5737 if (WINED3D_OK != hr) {
5738 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5740 TRACE("Got srcSurface %p\n", srcSurface);
5742 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5743 if (WINED3D_OK != hr) {
5744 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5746 TRACE("Got desrSurface %p\n", destSurface);
5748 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5749 IWineD3DSurface_Release(srcSurface);
5750 IWineD3DSurface_Release(destSurface);
5751 if (WINED3D_OK != hr) {
5752 WARN("(%p) : Call to update surface failed\n", This);
5760 case WINED3DRTYPE_VOLUMETEXTURE:
5762 IWineD3DVolume *srcVolume = NULL;
5763 IWineD3DVolume *destVolume = NULL;
5765 for (i = 0 ; i < levels ; ++i) {
5766 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5767 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5768 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5769 IWineD3DVolume_Release(srcVolume);
5770 IWineD3DVolume_Release(destVolume);
5771 if (WINED3D_OK != hr) {
5772 WARN("(%p) : Call to update volume failed\n", This);
5780 FIXME("(%p) : Unsupported source and destination type\n", This);
5781 hr = WINED3DERR_INVALIDCALL;
5788 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5789 IWineD3DSwapChain *swapChain;
5791 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5792 if(hr == WINED3D_OK) {
5793 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5794 IWineD3DSwapChain_Release(swapChain);
5799 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5801 IWineD3DBaseTextureImpl *texture;
5804 TRACE("(%p) : %p\n", This, pNumPasses);
5806 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5807 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5808 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5809 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5811 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5812 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5813 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5816 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5817 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5819 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5820 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5823 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5824 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5827 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5828 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5829 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5834 /* return a sensible default */
5837 TRACE("returning D3D_OK\n");
5841 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5845 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5846 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5847 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5848 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5853 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5854 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5857 PALETTEENTRY **palettes;
5859 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5861 if (PaletteNumber >= MAX_PALETTES) {
5862 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5863 return WINED3DERR_INVALIDCALL;
5866 if (PaletteNumber >= This->NumberOfPalettes) {
5867 NewSize = This->NumberOfPalettes;
5870 } while(PaletteNumber >= NewSize);
5871 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5873 ERR("Out of memory!\n");
5874 return E_OUTOFMEMORY;
5876 This->palettes = palettes;
5877 This->NumberOfPalettes = NewSize;
5880 if (!This->palettes[PaletteNumber]) {
5881 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5882 if (!This->palettes[PaletteNumber]) {
5883 ERR("Out of memory!\n");
5884 return E_OUTOFMEMORY;
5888 for (j = 0; j < 256; ++j) {
5889 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5890 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5891 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5892 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5894 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5895 TRACE("(%p) : returning\n", This);
5899 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5902 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5903 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5904 /* What happens in such situation isn't documented; Native seems to silently abort
5905 on such conditions. Return Invalid Call. */
5906 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5907 return WINED3DERR_INVALIDCALL;
5909 for (j = 0; j < 256; ++j) {
5910 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5911 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5912 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5913 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5915 TRACE("(%p) : returning\n", This);
5919 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5920 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5921 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5922 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5923 (tested with reference rasterizer). Return Invalid Call. */
5924 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5925 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5926 return WINED3DERR_INVALIDCALL;
5928 /*TODO: stateblocks */
5929 if (This->currentPalette != PaletteNumber) {
5930 This->currentPalette = PaletteNumber;
5931 dirtify_p8_texture_samplers(This);
5933 TRACE("(%p) : returning\n", This);
5937 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5939 if (PaletteNumber == NULL) {
5940 WARN("(%p) : returning Invalid Call\n", This);
5941 return WINED3DERR_INVALIDCALL;
5943 /*TODO: stateblocks */
5944 *PaletteNumber = This->currentPalette;
5945 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5949 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5954 FIXME("(%p) : stub\n", This);
5958 This->softwareVertexProcessing = bSoftware;
5963 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5968 FIXME("(%p) : stub\n", This);
5971 return This->softwareVertexProcessing;
5975 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5977 IWineD3DSwapChain *swapChain;
5980 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5982 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5983 if(hr == WINED3D_OK){
5984 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5985 IWineD3DSwapChain_Release(swapChain);
5987 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5993 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5996 if(nSegments != 0.0f) {
5999 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6006 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6011 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6017 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6019 /** TODO: remove casts to IWineD3DSurfaceImpl
6020 * NOTE: move code to surface to accomplish this
6021 ****************************************/
6022 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6023 int srcWidth, srcHeight;
6024 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6025 WINED3DFORMAT destFormat, srcFormat;
6027 int srcLeft, destLeft, destTop;
6028 WINED3DPOOL srcPool, destPool;
6030 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6031 glDescriptor *glDescription = NULL;
6035 CONVERT_TYPES convert = NO_CONVERSION;
6037 WINED3DSURFACE_DESC winedesc;
6039 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6040 memset(&winedesc, 0, sizeof(winedesc));
6041 winedesc.Width = &srcSurfaceWidth;
6042 winedesc.Height = &srcSurfaceHeight;
6043 winedesc.Pool = &srcPool;
6044 winedesc.Format = &srcFormat;
6046 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6048 winedesc.Width = &destSurfaceWidth;
6049 winedesc.Height = &destSurfaceHeight;
6050 winedesc.Pool = &destPool;
6051 winedesc.Format = &destFormat;
6052 winedesc.Size = &destSize;
6054 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6056 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6057 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6058 return WINED3DERR_INVALIDCALL;
6061 /* This call loads the opengl surface directly, instead of copying the surface to the
6062 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
6063 * copy in sysmem and use regular surface loading.
6065 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
6066 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
6067 if(convert != NO_CONVERSION) {
6068 return IWineD3DSurface_BltFast(pDestinationSurface,
6069 pDestPoint ? pDestPoint->x : 0,
6070 pDestPoint ? pDestPoint->y : 0,
6071 pSourceSurface, pSourceRect, 0);
6074 if (destFormat == WINED3DFMT_UNKNOWN) {
6075 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6076 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6078 /* Get the update surface description */
6079 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6082 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6085 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6086 checkGLcall("glActiveTextureARB");
6089 /* Make sure the surface is loaded and up to date */
6090 surface_internal_preload(pDestinationSurface, SRGB_RGB);
6091 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
6093 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6095 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6096 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6097 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
6098 srcLeft = pSourceRect ? pSourceRect->left : 0;
6099 destLeft = pDestPoint ? pDestPoint->x : 0;
6100 destTop = pDestPoint ? pDestPoint->y : 0;
6103 /* This function doesn't support compressed textures
6104 the pitch is just bytesPerPixel * width */
6105 if(srcWidth != srcSurfaceWidth || srcLeft ){
6106 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
6107 offset += srcLeft * pSrcSurface->bytesPerPixel;
6108 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6110 /* TODO DXT formats */
6112 if(pSourceRect != NULL && pSourceRect->top != 0){
6113 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
6115 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
6116 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
6117 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
6120 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6122 /* need to lock the surface to get the data */
6123 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6128 /* TODO: Cube and volume support */
6130 /* not a whole row so we have to do it a line at a time */
6133 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
6134 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6136 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6138 glTexSubImage2D(glDescription->target
6139 ,glDescription->level
6144 ,glDescription->glFormat
6145 ,glDescription->glType
6146 ,data /* could be quicker using */
6151 } else { /* Full width, so just write out the whole texture */
6152 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6154 if (WINED3DFMT_DXT1 == destFormat ||
6155 WINED3DFMT_DXT2 == destFormat ||
6156 WINED3DFMT_DXT3 == destFormat ||
6157 WINED3DFMT_DXT4 == destFormat ||
6158 WINED3DFMT_DXT5 == destFormat) {
6159 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6160 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6161 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6162 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6163 } if (destFormat != srcFormat) {
6164 FIXME("Updating mixed format compressed texture is not curretly support\n");
6166 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6167 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
6170 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6175 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6176 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
6179 checkGLcall("glTexSubImage2D");
6183 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6184 sampler = This->rev_tex_unit_map[0];
6185 if (sampler != -1) {
6186 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6192 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6194 struct WineD3DRectPatch *patch;
6195 GLenum old_primitive_type;
6199 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6201 if(!(Handle || pRectPatchInfo)) {
6202 /* TODO: Write a test for the return value, thus the FIXME */
6203 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6204 return WINED3DERR_INVALIDCALL;
6208 i = PATCHMAP_HASHFUNC(Handle);
6210 LIST_FOR_EACH(e, &This->patches[i]) {
6211 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6212 if(patch->Handle == Handle) {
6219 TRACE("Patch does not exist. Creating a new one\n");
6220 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6221 patch->Handle = Handle;
6222 list_add_head(&This->patches[i], &patch->entry);
6224 TRACE("Found existing patch %p\n", patch);
6227 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6228 * attributes we have to tesselate, read back, and draw. This needs a patch
6229 * management structure instance. Create one.
6231 * A possible improvement is to check if a vertex shader is used, and if not directly
6234 FIXME("Drawing an uncached patch. This is slow\n");
6235 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6238 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6239 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6240 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6242 TRACE("Tesselation density or patch info changed, retesselating\n");
6244 if(pRectPatchInfo) {
6245 patch->RectPatchInfo = *pRectPatchInfo;
6247 patch->numSegs[0] = pNumSegs[0];
6248 patch->numSegs[1] = pNumSegs[1];
6249 patch->numSegs[2] = pNumSegs[2];
6250 patch->numSegs[3] = pNumSegs[3];
6252 hr = tesselate_rectpatch(This, patch);
6254 WARN("Patch tesselation failed\n");
6256 /* Do not release the handle to store the params of the patch */
6258 HeapFree(GetProcessHeap(), 0, patch);
6264 This->currentPatch = patch;
6265 old_primitive_type = This->stateBlock->gl_primitive_type;
6266 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
6267 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6268 This->stateBlock->gl_primitive_type = old_primitive_type;
6269 This->currentPatch = NULL;
6271 /* Destroy uncached patches */
6273 HeapFree(GetProcessHeap(), 0, patch->mem);
6274 HeapFree(GetProcessHeap(), 0, patch);
6279 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6281 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6282 FIXME("(%p) : Stub\n", This);
6286 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6289 struct WineD3DRectPatch *patch;
6291 TRACE("(%p) Handle(%d)\n", This, Handle);
6293 i = PATCHMAP_HASHFUNC(Handle);
6294 LIST_FOR_EACH(e, &This->patches[i]) {
6295 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6296 if(patch->Handle == Handle) {
6297 TRACE("Deleting patch %p\n", patch);
6298 list_remove(&patch->entry);
6299 HeapFree(GetProcessHeap(), 0, patch->mem);
6300 HeapFree(GetProcessHeap(), 0, patch);
6305 /* TODO: Write a test for the return value */
6306 FIXME("Attempt to destroy nonexistent patch\n");
6307 return WINED3DERR_INVALIDCALL;
6310 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6312 IWineD3DSwapChain *swapchain;
6314 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6315 if (SUCCEEDED(hr)) {
6316 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6323 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6324 const WINED3DRECT *rect, const float color[4])
6326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6327 IWineD3DSwapChain *swapchain;
6329 swapchain = get_swapchain(surface);
6333 TRACE("Surface %p is onscreen\n", surface);
6335 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6337 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6338 buffer = surface_get_gl_buffer(surface, swapchain);
6339 glDrawBuffer(buffer);
6340 checkGLcall("glDrawBuffer()");
6342 TRACE("Surface %p is offscreen\n", surface);
6344 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6346 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6347 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6348 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6349 checkGLcall("glFramebufferRenderbufferEXT");
6353 glEnable(GL_SCISSOR_TEST);
6355 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6357 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6358 rect->x2 - rect->x1, rect->y2 - rect->y1);
6360 checkGLcall("glScissor");
6361 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6363 glDisable(GL_SCISSOR_TEST);
6365 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6367 glDisable(GL_BLEND);
6368 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6370 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6373 glClearColor(color[0], color[1], color[2], color[3]);
6374 glClear(GL_COLOR_BUFFER_BIT);
6375 checkGLcall("glClear");
6377 if (This->activeContext->current_fbo) {
6378 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6380 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6381 checkGLcall("glBindFramebuffer()");
6384 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6385 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6386 glDrawBuffer(GL_BACK);
6387 checkGLcall("glDrawBuffer()");
6393 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6394 unsigned int r, g, b, a;
6397 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6398 destfmt == WINED3DFMT_R8G8B8)
6401 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6403 a = (color & 0xff000000) >> 24;
6404 r = (color & 0x00ff0000) >> 16;
6405 g = (color & 0x0000ff00) >> 8;
6406 b = (color & 0x000000ff) >> 0;
6410 case WINED3DFMT_R5G6B5:
6411 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6418 TRACE("Returning %08x\n", ret);
6421 case WINED3DFMT_X1R5G5B5:
6422 case WINED3DFMT_A1R5G5B5:
6431 TRACE("Returning %08x\n", ret);
6434 case WINED3DFMT_A8_UNORM:
6435 TRACE("Returning %08x\n", a);
6438 case WINED3DFMT_X4R4G4B4:
6439 case WINED3DFMT_A4R4G4B4:
6448 TRACE("Returning %08x\n", ret);
6451 case WINED3DFMT_R3G3B2:
6458 TRACE("Returning %08x\n", ret);
6461 case WINED3DFMT_X8B8G8R8:
6462 case WINED3DFMT_R8G8B8A8_UNORM:
6467 TRACE("Returning %08x\n", ret);
6470 case WINED3DFMT_A2R10G10B10:
6472 r = (r * 1024) / 256;
6473 g = (g * 1024) / 256;
6474 b = (b * 1024) / 256;
6479 TRACE("Returning %08x\n", ret);
6482 case WINED3DFMT_R10G10B10A2_UNORM:
6484 r = (r * 1024) / 256;
6485 g = (g * 1024) / 256;
6486 b = (b * 1024) / 256;
6491 TRACE("Returning %08x\n", ret);
6495 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6500 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6502 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6504 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6506 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6507 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6508 return WINED3DERR_INVALIDCALL;
6511 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6512 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6513 color_fill_fbo(iface, pSurface, pRect, c);
6516 /* Just forward this to the DirectDraw blitting engine */
6517 memset(&BltFx, 0, sizeof(BltFx));
6518 BltFx.dwSize = sizeof(BltFx);
6519 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6520 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6521 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6525 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6526 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6528 IWineD3DResource *resource;
6529 IWineD3DSurface *surface;
6532 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6535 ERR("Failed to get resource, hr %#x\n", hr);
6539 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6541 FIXME("Only supported on surface resources\n");
6542 IWineD3DResource_Release(resource);
6546 surface = (IWineD3DSurface *)resource;
6548 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6550 color_fill_fbo(iface, surface, NULL, color);
6557 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6559 c = ((DWORD)(color[2] * 255.0));
6560 c |= ((DWORD)(color[1] * 255.0)) << 8;
6561 c |= ((DWORD)(color[0] * 255.0)) << 16;
6562 c |= ((DWORD)(color[3] * 255.0)) << 24;
6564 /* Just forward this to the DirectDraw blitting engine */
6565 memset(&BltFx, 0, sizeof(BltFx));
6566 BltFx.dwSize = sizeof(BltFx);
6567 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format);
6568 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6571 ERR("Blt failed, hr %#x\n", hr);
6575 IWineD3DResource_Release(resource);
6578 /* rendertarget and depth stencil functions */
6579 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6582 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6583 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6584 return WINED3DERR_INVALIDCALL;
6587 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6588 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6589 /* Note inc ref on returned surface */
6590 if(*ppRenderTarget != NULL)
6591 IWineD3DSurface_AddRef(*ppRenderTarget);
6595 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6597 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6598 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6599 IWineD3DSwapChainImpl *Swapchain;
6602 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6604 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6605 if(hr != WINED3D_OK) {
6606 ERR("Can't get the swapchain\n");
6610 /* Make sure to release the swapchain */
6611 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6613 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6614 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6615 return WINED3DERR_INVALIDCALL;
6617 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6618 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6619 return WINED3DERR_INVALIDCALL;
6622 if(Swapchain->frontBuffer != Front) {
6623 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6625 if(Swapchain->frontBuffer)
6626 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6627 Swapchain->frontBuffer = Front;
6629 if(Swapchain->frontBuffer) {
6630 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6634 if(Back && !Swapchain->backBuffer) {
6635 /* We need memory for the back buffer array - only one back buffer this way */
6636 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6637 if(!Swapchain->backBuffer) {
6638 ERR("Out of memory\n");
6639 return E_OUTOFMEMORY;
6643 if(Swapchain->backBuffer[0] != Back) {
6644 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6646 /* What to do about the context here in the case of multithreading? Not sure.
6647 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6650 if(!Swapchain->backBuffer[0]) {
6651 /* GL was told to draw to the front buffer at creation,
6654 glDrawBuffer(GL_BACK);
6655 checkGLcall("glDrawBuffer(GL_BACK)");
6656 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6657 Swapchain->presentParms.BackBufferCount = 1;
6659 /* That makes problems - disable for now */
6660 /* glDrawBuffer(GL_FRONT); */
6661 checkGLcall("glDrawBuffer(GL_FRONT)");
6662 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6663 Swapchain->presentParms.BackBufferCount = 0;
6667 if(Swapchain->backBuffer[0])
6668 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6669 Swapchain->backBuffer[0] = Back;
6671 if(Swapchain->backBuffer[0]) {
6672 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6674 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6675 Swapchain->backBuffer = NULL;
6683 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6685 *ppZStencilSurface = This->stencilBufferTarget;
6686 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6688 if(*ppZStencilSurface != NULL) {
6689 /* Note inc ref on returned surface */
6690 IWineD3DSurface_AddRef(*ppZStencilSurface);
6693 return WINED3DERR_NOTFOUND;
6697 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6698 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6700 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6701 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6702 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6704 POINT offset = {0, 0};
6706 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6707 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6708 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6709 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6712 case WINED3DTEXF_LINEAR:
6713 gl_filter = GL_LINEAR;
6717 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6718 case WINED3DTEXF_NONE:
6719 case WINED3DTEXF_POINT:
6720 gl_filter = GL_NEAREST;
6724 /* Attach src surface to src fbo */
6725 src_swapchain = get_swapchain(src_surface);
6726 if (src_swapchain) {
6727 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6729 TRACE("Source surface %p is onscreen\n", src_surface);
6730 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6731 /* Make sure the drawable is up to date. In the offscreen case
6732 * attach_surface_fbo() implicitly takes care of this. */
6733 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6735 if(buffer == GL_FRONT) {
6738 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6739 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6740 h = windowsize.bottom - windowsize.top;
6741 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6742 src_rect->y1 = offset.y + h - src_rect->y1;
6743 src_rect->y2 = offset.y + h - src_rect->y2;
6745 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6746 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6750 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6751 glReadBuffer(buffer);
6752 checkGLcall("glReadBuffer()");
6754 TRACE("Source surface %p is offscreen\n", src_surface);
6756 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6757 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6758 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6759 checkGLcall("glReadBuffer()");
6760 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6761 checkGLcall("glFramebufferRenderbufferEXT");
6765 /* Attach dst surface to dst fbo */
6766 dst_swapchain = get_swapchain(dst_surface);
6767 if (dst_swapchain) {
6768 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6770 TRACE("Destination surface %p is onscreen\n", dst_surface);
6771 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6772 /* Make sure the drawable is up to date. In the offscreen case
6773 * attach_surface_fbo() implicitly takes care of this. */
6774 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6776 if(buffer == GL_FRONT) {
6779 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6780 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6781 h = windowsize.bottom - windowsize.top;
6782 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6783 dst_rect->y1 = offset.y + h - dst_rect->y1;
6784 dst_rect->y2 = offset.y + h - dst_rect->y2;
6786 /* Screen coords = window coords, surface height = window height */
6787 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6788 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6792 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6793 glDrawBuffer(buffer);
6794 checkGLcall("glDrawBuffer()");
6796 TRACE("Destination surface %p is offscreen\n", dst_surface);
6798 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6799 if(!src_swapchain) {
6800 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6804 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6805 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6806 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6807 checkGLcall("glDrawBuffer()");
6808 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6809 checkGLcall("glFramebufferRenderbufferEXT");
6811 glDisable(GL_SCISSOR_TEST);
6812 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6815 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6816 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6817 checkGLcall("glBlitFramebuffer()");
6819 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6820 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6821 checkGLcall("glBlitFramebuffer()");
6824 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6826 if (This->activeContext->current_fbo) {
6827 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6829 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6830 checkGLcall("glBindFramebuffer()");
6833 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6834 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6835 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6836 glDrawBuffer(GL_BACK);
6837 checkGLcall("glDrawBuffer()");
6842 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6844 WINED3DVIEWPORT viewport;
6846 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6848 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6849 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6850 This, RenderTargetIndex, GL_LIMITS(buffers));
6851 return WINED3DERR_INVALIDCALL;
6854 /* MSDN says that null disables the render target
6855 but a device must always be associated with a render target
6856 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6858 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6859 FIXME("Trying to set render target 0 to NULL\n");
6860 return WINED3DERR_INVALIDCALL;
6862 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6863 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);
6864 return WINED3DERR_INVALIDCALL;
6867 /* If we are trying to set what we already have, don't bother */
6868 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6869 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6872 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6873 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6874 This->render_targets[RenderTargetIndex] = pRenderTarget;
6876 /* Render target 0 is special */
6877 if(RenderTargetIndex == 0) {
6878 /* Finally, reset the viewport as the MSDN states. */
6879 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6880 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6883 viewport.MaxZ = 1.0f;
6884 viewport.MinZ = 0.0f;
6885 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6886 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6887 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6889 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6894 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6896 HRESULT hr = WINED3D_OK;
6897 IWineD3DSurface *tmp;
6899 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6901 if (pNewZStencil == This->stencilBufferTarget) {
6902 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6904 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6905 * depending on the renter target implementation being used.
6906 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6907 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6908 * stencil buffer and incur an extra memory overhead
6909 ******************************************************/
6911 if (This->stencilBufferTarget) {
6912 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6913 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6914 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6916 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6917 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6918 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6922 tmp = This->stencilBufferTarget;
6923 This->stencilBufferTarget = pNewZStencil;
6924 /* should we be calling the parent or the wined3d surface? */
6925 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6926 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6929 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6930 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6931 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6932 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6933 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6940 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6941 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6943 /* TODO: the use of Impl is deprecated. */
6944 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6945 WINED3DLOCKED_RECT lockedRect;
6947 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6949 /* some basic validation checks */
6950 if(This->cursorTexture) {
6951 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6953 glDeleteTextures(1, &This->cursorTexture);
6955 This->cursorTexture = 0;
6958 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6959 This->haveHardwareCursor = TRUE;
6961 This->haveHardwareCursor = FALSE;
6964 WINED3DLOCKED_RECT rect;
6966 /* MSDN: Cursor must be A8R8G8B8 */
6967 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6968 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6969 return WINED3DERR_INVALIDCALL;
6972 /* MSDN: Cursor must be smaller than the display mode */
6973 if(pSur->currentDesc.Width > This->ddraw_width ||
6974 pSur->currentDesc.Height > This->ddraw_height) {
6975 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);
6976 return WINED3DERR_INVALIDCALL;
6979 if (!This->haveHardwareCursor) {
6980 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6982 /* Do not store the surface's pointer because the application may
6983 * release it after setting the cursor image. Windows doesn't
6984 * addref the set surface, so we can't do this either without
6985 * creating circular refcount dependencies. Copy out the gl texture
6988 This->cursorWidth = pSur->currentDesc.Width;
6989 This->cursorHeight = pSur->currentDesc.Height;
6990 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6992 const struct GlPixelFormatDesc *glDesc;
6993 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6994 char *mem, *bits = rect.pBits;
6995 GLint intfmt = glDesc->glInternal;
6996 GLint format = glDesc->glFormat;
6997 GLint type = glDesc->glType;
6998 INT height = This->cursorHeight;
6999 INT width = This->cursorWidth;
7000 INT bpp = tableEntry->bpp;
7003 /* Reformat the texture memory (pitch and width can be
7005 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
7006 for(i = 0; i < height; i++)
7007 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
7008 IWineD3DSurface_UnlockRect(pCursorBitmap);
7011 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7012 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
7013 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
7016 /* Make sure that a proper texture unit is selected */
7017 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
7018 checkGLcall("glActiveTextureARB");
7019 sampler = This->rev_tex_unit_map[0];
7020 if (sampler != -1) {
7021 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
7023 /* Create a new cursor texture */
7024 glGenTextures(1, &This->cursorTexture);
7025 checkGLcall("glGenTextures");
7026 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
7027 checkGLcall("glBindTexture");
7028 /* Copy the bitmap memory into the cursor texture */
7029 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
7030 HeapFree(GetProcessHeap(), 0, mem);
7031 checkGLcall("glTexImage2D");
7033 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7034 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
7035 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
7042 FIXME("A cursor texture was not returned.\n");
7043 This->cursorTexture = 0;
7048 /* Draw a hardware cursor */
7049 ICONINFO cursorInfo;
7051 /* Create and clear maskBits because it is not needed for
7052 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
7054 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7055 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
7056 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
7057 WINED3DLOCK_NO_DIRTY_UPDATE |
7058 WINED3DLOCK_READONLY
7060 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
7061 pSur->currentDesc.Height);
7063 cursorInfo.fIcon = FALSE;
7064 cursorInfo.xHotspot = XHotSpot;
7065 cursorInfo.yHotspot = YHotSpot;
7066 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
7067 pSur->currentDesc.Height, 1,
7069 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
7070 pSur->currentDesc.Height, 1,
7071 32, lockedRect.pBits);
7072 IWineD3DSurface_UnlockRect(pCursorBitmap);
7073 /* Create our cursor and clean up. */
7074 cursor = CreateIconIndirect(&cursorInfo);
7076 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
7077 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
7078 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
7079 This->hardwareCursor = cursor;
7080 HeapFree(GetProcessHeap(), 0, maskBits);
7084 This->xHotSpot = XHotSpot;
7085 This->yHotSpot = YHotSpot;
7089 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7091 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7093 This->xScreenSpace = XScreenSpace;
7094 This->yScreenSpace = YScreenSpace;
7100 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7102 BOOL oldVisible = This->bCursorVisible;
7105 TRACE("(%p) : visible(%d)\n", This, bShow);
7108 * When ShowCursor is first called it should make the cursor appear at the OS's last
7109 * known cursor position. Because of this, some applications just repetitively call
7110 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7113 This->xScreenSpace = pt.x;
7114 This->yScreenSpace = pt.y;
7116 if (This->haveHardwareCursor) {
7117 This->bCursorVisible = bShow;
7119 SetCursor(This->hardwareCursor);
7125 if (This->cursorTexture)
7126 This->bCursorVisible = bShow;
7132 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7134 IWineD3DResourceImpl *resource;
7135 TRACE("(%p) : state (%u)\n", This, This->state);
7137 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7138 switch (This->state) {
7141 case WINED3DERR_DEVICELOST:
7143 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7144 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7145 return WINED3DERR_DEVICENOTRESET;
7147 return WINED3DERR_DEVICELOST;
7149 case WINED3DERR_DRIVERINTERNALERROR:
7150 return WINED3DERR_DRIVERINTERNALERROR;
7154 return WINED3DERR_DRIVERINTERNALERROR;
7158 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7160 /** FIXME: Resource tracking needs to be done,
7161 * The closes we can do to this is set the priorities of all managed textures low
7162 * and then reset them.
7163 ***********************************************************/
7164 FIXME("(%p) : stub\n", This);
7168 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
7170 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7172 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7173 if(surface->Flags & SFLAG_DIBSECTION) {
7174 /* Release the DC */
7175 SelectObject(surface->hDC, surface->dib.holdbitmap);
7176 DeleteDC(surface->hDC);
7177 /* Release the DIB section */
7178 DeleteObject(surface->dib.DIBsection);
7179 surface->dib.bitmap_data = NULL;
7180 surface->resource.allocatedMemory = NULL;
7181 surface->Flags &= ~SFLAG_DIBSECTION;
7183 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7184 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7185 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7186 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7187 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7188 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7190 surface->pow2Width = surface->pow2Height = 1;
7191 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7192 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7194 surface->glRect.left = 0;
7195 surface->glRect.top = 0;
7196 surface->glRect.right = surface->pow2Width;
7197 surface->glRect.bottom = surface->pow2Height;
7199 if(surface->glDescription.textureName) {
7200 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7202 glDeleteTextures(1, &surface->glDescription.textureName);
7204 surface->glDescription.textureName = 0;
7205 surface->Flags &= ~SFLAG_CLIENT;
7207 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7208 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7209 surface->Flags |= SFLAG_NONPOW2;
7211 surface->Flags &= ~SFLAG_NONPOW2;
7213 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7214 surface->resource.allocatedMemory = NULL;
7215 surface->resource.heapMemory = NULL;
7216 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7217 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7218 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7219 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7221 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7225 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7226 TRACE("Unloading resource %p\n", resource);
7227 IWineD3DResource_UnLoad(resource);
7228 IWineD3DResource_Release(resource);
7232 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7235 WINED3DDISPLAYMODE m;
7238 /* All Windowed modes are supported, as is leaving the current mode */
7239 if(pp->Windowed) return TRUE;
7240 if(!pp->BackBufferWidth) return TRUE;
7241 if(!pp->BackBufferHeight) return TRUE;
7243 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7244 for(i = 0; i < count; i++) {
7245 memset(&m, 0, sizeof(m));
7246 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7248 ERR("EnumAdapterModes failed\n");
7250 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7251 /* Mode found, it is supported */
7255 /* Mode not found -> not supported */
7259 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7261 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7263 IWineD3DBaseShaderImpl *shader;
7265 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7266 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7267 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7271 if(This->depth_blt_texture) {
7272 glDeleteTextures(1, &This->depth_blt_texture);
7273 This->depth_blt_texture = 0;
7275 if (This->depth_blt_rb) {
7276 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7277 This->depth_blt_rb = 0;
7278 This->depth_blt_rb_w = 0;
7279 This->depth_blt_rb_h = 0;
7283 This->blitter->free_private(iface);
7284 This->frag_pipe->free_private(iface);
7285 This->shader_backend->shader_free_private(iface);
7288 for (i = 0; i < GL_LIMITS(textures); i++) {
7289 /* Textures are recreated below */
7290 glDeleteTextures(1, &This->dummyTextureName[i]);
7291 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7292 This->dummyTextureName[i] = 0;
7296 while(This->numContexts) {
7297 DestroyContext(This, This->contexts[0]);
7299 This->activeContext = NULL;
7300 HeapFree(GetProcessHeap(), 0, swapchain->context);
7301 swapchain->context = NULL;
7302 swapchain->num_contexts = 0;
7305 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7307 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7309 IWineD3DSurfaceImpl *target;
7311 /* Recreate the primary swapchain's context */
7312 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7313 if(swapchain->backBuffer) {
7314 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7316 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7318 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7319 &swapchain->presentParms);
7320 swapchain->num_contexts = 1;
7321 This->activeContext = swapchain->context[0];
7323 create_dummy_textures(This);
7325 hr = This->shader_backend->shader_alloc_private(iface);
7327 ERR("Failed to recreate shader private data\n");
7330 hr = This->frag_pipe->alloc_private(iface);
7332 TRACE("Fragment pipeline private data couldn't be allocated\n");
7335 hr = This->blitter->alloc_private(iface);
7337 TRACE("Blitter private data couldn't be allocated\n");
7344 This->blitter->free_private(iface);
7345 This->frag_pipe->free_private(iface);
7346 This->shader_backend->shader_free_private(iface);
7350 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7352 IWineD3DSwapChainImpl *swapchain;
7354 BOOL DisplayModeChanged = FALSE;
7355 WINED3DDISPLAYMODE mode;
7356 TRACE("(%p)\n", This);
7358 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7360 ERR("Failed to get the first implicit swapchain\n");
7364 if(!is_display_mode_supported(This, pPresentationParameters)) {
7365 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7366 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7367 pPresentationParameters->BackBufferHeight);
7368 return WINED3DERR_INVALIDCALL;
7371 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7372 * on an existing gl context, so there's no real need for recreation.
7374 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7376 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7378 TRACE("New params:\n");
7379 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7380 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7381 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7382 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7383 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7384 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7385 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7386 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7387 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7388 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7389 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7390 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7391 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7393 /* No special treatment of these parameters. Just store them */
7394 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7395 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7396 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7397 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7399 /* What to do about these? */
7400 if(pPresentationParameters->BackBufferCount != 0 &&
7401 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7402 ERR("Cannot change the back buffer count yet\n");
7404 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7405 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7406 ERR("Cannot change the back buffer format yet\n");
7408 if(pPresentationParameters->hDeviceWindow != NULL &&
7409 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7410 ERR("Cannot change the device window yet\n");
7412 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7413 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7414 return WINED3DERR_INVALIDCALL;
7417 /* Reset the depth stencil */
7418 if (pPresentationParameters->EnableAutoDepthStencil)
7419 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7421 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7423 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7425 if(pPresentationParameters->Windowed) {
7426 mode.Width = swapchain->orig_width;
7427 mode.Height = swapchain->orig_height;
7428 mode.RefreshRate = 0;
7429 mode.Format = swapchain->presentParms.BackBufferFormat;
7431 mode.Width = pPresentationParameters->BackBufferWidth;
7432 mode.Height = pPresentationParameters->BackBufferHeight;
7433 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7434 mode.Format = swapchain->presentParms.BackBufferFormat;
7437 /* Should Width == 800 && Height == 0 set 800x600? */
7438 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7439 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7440 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7444 if(!pPresentationParameters->Windowed) {
7445 DisplayModeChanged = TRUE;
7447 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7448 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7450 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7451 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7452 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7454 if(This->auto_depth_stencil_buffer) {
7455 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7459 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7460 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7461 DisplayModeChanged) {
7463 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7465 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7466 if(swapchain->presentParms.Windowed) {
7467 /* switch from windowed to fs */
7468 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7469 pPresentationParameters->BackBufferWidth,
7470 pPresentationParameters->BackBufferHeight);
7472 /* Fullscreen -> fullscreen mode change */
7473 MoveWindow(swapchain->win_handle, 0, 0,
7474 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7477 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7478 /* Fullscreen -> windowed switch */
7479 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7481 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7482 } else if(!pPresentationParameters->Windowed) {
7483 DWORD style = This->style, exStyle = This->exStyle;
7484 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7485 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7486 * Reset to clear up their mess. Guild Wars also loses the device during that.
7490 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7491 pPresentationParameters->BackBufferWidth,
7492 pPresentationParameters->BackBufferHeight);
7493 This->style = style;
7494 This->exStyle = exStyle;
7497 TRACE("Resetting stateblock\n");
7498 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7499 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7501 /* Note: No parent needed for initial internal stateblock */
7502 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7503 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7504 else TRACE("Created stateblock %p\n", This->stateBlock);
7505 This->updateStateBlock = This->stateBlock;
7506 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7508 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7510 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7513 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7514 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7516 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7522 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7524 /** FIXME: always true at the moment **/
7525 if(!bEnableDialogs) {
7526 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7532 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7534 TRACE("(%p) : pParameters %p\n", This, pParameters);
7536 *pParameters = This->createParms;
7540 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7541 IWineD3DSwapChain *swapchain;
7543 TRACE("Relaying to swapchain\n");
7545 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7546 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7547 IWineD3DSwapChain_Release(swapchain);
7552 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7553 IWineD3DSwapChain *swapchain;
7555 TRACE("Relaying to swapchain\n");
7557 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7558 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7559 IWineD3DSwapChain_Release(swapchain);
7565 /** ********************************************************
7566 * Notification functions
7567 ** ********************************************************/
7568 /** This function must be called in the release of a resource when ref == 0,
7569 * the contents of resource must still be correct,
7570 * any handles to other resource held by the caller must be closed
7571 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7572 *****************************************************/
7573 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7576 TRACE("(%p) : Adding Resource %p\n", This, resource);
7577 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7580 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7583 TRACE("(%p) : Removing resource %p\n", This, resource);
7585 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7589 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7591 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7594 TRACE("(%p) : resource %p\n", This, resource);
7596 context_resource_released(iface, resource, type);
7599 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7600 case WINED3DRTYPE_SURFACE: {
7603 /* Cleanup any FBO attachments if d3d is enabled */
7604 if(This->d3d_initialized) {
7605 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7606 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7608 TRACE("Last active render target destroyed\n");
7609 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7610 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7611 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7612 * and the lastActiveRenderTarget member shouldn't matter
7615 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7616 TRACE("Activating primary back buffer\n");
7617 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7618 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7619 /* Single buffering environment */
7620 TRACE("Activating primary front buffer\n");
7621 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7623 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7624 /* Implicit render target destroyed, that means the device is being destroyed
7625 * whatever we set here, it shouldn't matter
7627 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7630 /* May happen during ddraw uninitialization */
7631 TRACE("Render target set, but swapchain does not exist!\n");
7632 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7636 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7637 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7638 This->render_targets[i] = NULL;
7641 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7642 This->stencilBufferTarget = NULL;
7648 case WINED3DRTYPE_TEXTURE:
7649 case WINED3DRTYPE_CUBETEXTURE:
7650 case WINED3DRTYPE_VOLUMETEXTURE:
7651 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7652 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7653 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7654 This->stateBlock->textures[counter] = NULL;
7656 if (This->updateStateBlock != This->stateBlock ){
7657 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7658 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7659 This->updateStateBlock->textures[counter] = NULL;
7664 case WINED3DRTYPE_VOLUME:
7665 /* TODO: nothing really? */
7667 case WINED3DRTYPE_VERTEXBUFFER:
7670 TRACE("Cleaning up stream pointers\n");
7672 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7673 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7674 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7676 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7677 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7678 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7679 This->updateStateBlock->streamSource[streamNumber] = 0;
7680 /* Set changed flag? */
7683 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) */
7684 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7685 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7686 This->stateBlock->streamSource[streamNumber] = 0;
7692 case WINED3DRTYPE_INDEXBUFFER:
7693 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7694 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7695 This->updateStateBlock->pIndexData = NULL;
7698 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7699 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7700 This->stateBlock->pIndexData = NULL;
7705 case WINED3DRTYPE_BUFFER:
7706 /* Nothing to do, yet.*/
7710 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7715 /* Remove the resource from the resourceStore */
7716 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7718 TRACE("Resource released\n");
7722 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7724 IWineD3DResourceImpl *resource, *cursor;
7726 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7728 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7729 TRACE("enumerating resource %p\n", resource);
7730 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7731 ret = pCallback((IWineD3DResource *) resource, pData);
7732 if(ret == S_FALSE) {
7733 TRACE("Canceling enumeration\n");
7740 /**********************************************************
7741 * IWineD3DDevice VTbl follows
7742 **********************************************************/
7744 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7746 /*** IUnknown methods ***/
7747 IWineD3DDeviceImpl_QueryInterface,
7748 IWineD3DDeviceImpl_AddRef,
7749 IWineD3DDeviceImpl_Release,
7750 /*** IWineD3DDevice methods ***/
7751 IWineD3DDeviceImpl_GetParent,
7752 /*** Creation methods**/
7753 IWineD3DDeviceImpl_CreateBuffer,
7754 IWineD3DDeviceImpl_CreateVertexBuffer,
7755 IWineD3DDeviceImpl_CreateIndexBuffer,
7756 IWineD3DDeviceImpl_CreateStateBlock,
7757 IWineD3DDeviceImpl_CreateSurface,
7758 IWineD3DDeviceImpl_CreateRendertargetView,
7759 IWineD3DDeviceImpl_CreateTexture,
7760 IWineD3DDeviceImpl_CreateVolumeTexture,
7761 IWineD3DDeviceImpl_CreateVolume,
7762 IWineD3DDeviceImpl_CreateCubeTexture,
7763 IWineD3DDeviceImpl_CreateQuery,
7764 IWineD3DDeviceImpl_CreateSwapChain,
7765 IWineD3DDeviceImpl_CreateVertexDeclaration,
7766 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7767 IWineD3DDeviceImpl_CreateVertexShader,
7768 IWineD3DDeviceImpl_CreatePixelShader,
7769 IWineD3DDeviceImpl_CreatePalette,
7770 /*** Odd functions **/
7771 IWineD3DDeviceImpl_Init3D,
7772 IWineD3DDeviceImpl_InitGDI,
7773 IWineD3DDeviceImpl_Uninit3D,
7774 IWineD3DDeviceImpl_UninitGDI,
7775 IWineD3DDeviceImpl_SetMultithreaded,
7776 IWineD3DDeviceImpl_EvictManagedResources,
7777 IWineD3DDeviceImpl_GetAvailableTextureMem,
7778 IWineD3DDeviceImpl_GetBackBuffer,
7779 IWineD3DDeviceImpl_GetCreationParameters,
7780 IWineD3DDeviceImpl_GetDeviceCaps,
7781 IWineD3DDeviceImpl_GetDirect3D,
7782 IWineD3DDeviceImpl_GetDisplayMode,
7783 IWineD3DDeviceImpl_SetDisplayMode,
7784 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7785 IWineD3DDeviceImpl_GetRasterStatus,
7786 IWineD3DDeviceImpl_GetSwapChain,
7787 IWineD3DDeviceImpl_Reset,
7788 IWineD3DDeviceImpl_SetDialogBoxMode,
7789 IWineD3DDeviceImpl_SetCursorProperties,
7790 IWineD3DDeviceImpl_SetCursorPosition,
7791 IWineD3DDeviceImpl_ShowCursor,
7792 IWineD3DDeviceImpl_TestCooperativeLevel,
7793 /*** Getters and setters **/
7794 IWineD3DDeviceImpl_SetClipPlane,
7795 IWineD3DDeviceImpl_GetClipPlane,
7796 IWineD3DDeviceImpl_SetClipStatus,
7797 IWineD3DDeviceImpl_GetClipStatus,
7798 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7799 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7800 IWineD3DDeviceImpl_SetDepthStencilSurface,
7801 IWineD3DDeviceImpl_GetDepthStencilSurface,
7802 IWineD3DDeviceImpl_SetGammaRamp,
7803 IWineD3DDeviceImpl_GetGammaRamp,
7804 IWineD3DDeviceImpl_SetIndices,
7805 IWineD3DDeviceImpl_GetIndices,
7806 IWineD3DDeviceImpl_SetBaseVertexIndex,
7807 IWineD3DDeviceImpl_GetBaseVertexIndex,
7808 IWineD3DDeviceImpl_SetLight,
7809 IWineD3DDeviceImpl_GetLight,
7810 IWineD3DDeviceImpl_SetLightEnable,
7811 IWineD3DDeviceImpl_GetLightEnable,
7812 IWineD3DDeviceImpl_SetMaterial,
7813 IWineD3DDeviceImpl_GetMaterial,
7814 IWineD3DDeviceImpl_SetNPatchMode,
7815 IWineD3DDeviceImpl_GetNPatchMode,
7816 IWineD3DDeviceImpl_SetPaletteEntries,
7817 IWineD3DDeviceImpl_GetPaletteEntries,
7818 IWineD3DDeviceImpl_SetPixelShader,
7819 IWineD3DDeviceImpl_GetPixelShader,
7820 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7821 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7822 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7823 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7824 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7825 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7826 IWineD3DDeviceImpl_SetRenderState,
7827 IWineD3DDeviceImpl_GetRenderState,
7828 IWineD3DDeviceImpl_SetRenderTarget,
7829 IWineD3DDeviceImpl_GetRenderTarget,
7830 IWineD3DDeviceImpl_SetFrontBackBuffers,
7831 IWineD3DDeviceImpl_SetSamplerState,
7832 IWineD3DDeviceImpl_GetSamplerState,
7833 IWineD3DDeviceImpl_SetScissorRect,
7834 IWineD3DDeviceImpl_GetScissorRect,
7835 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7836 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7837 IWineD3DDeviceImpl_SetStreamSource,
7838 IWineD3DDeviceImpl_GetStreamSource,
7839 IWineD3DDeviceImpl_SetStreamSourceFreq,
7840 IWineD3DDeviceImpl_GetStreamSourceFreq,
7841 IWineD3DDeviceImpl_SetTexture,
7842 IWineD3DDeviceImpl_GetTexture,
7843 IWineD3DDeviceImpl_SetTextureStageState,
7844 IWineD3DDeviceImpl_GetTextureStageState,
7845 IWineD3DDeviceImpl_SetTransform,
7846 IWineD3DDeviceImpl_GetTransform,
7847 IWineD3DDeviceImpl_SetVertexDeclaration,
7848 IWineD3DDeviceImpl_GetVertexDeclaration,
7849 IWineD3DDeviceImpl_SetVertexShader,
7850 IWineD3DDeviceImpl_GetVertexShader,
7851 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7852 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7853 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7854 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7855 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7856 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7857 IWineD3DDeviceImpl_SetViewport,
7858 IWineD3DDeviceImpl_GetViewport,
7859 IWineD3DDeviceImpl_MultiplyTransform,
7860 IWineD3DDeviceImpl_ValidateDevice,
7861 IWineD3DDeviceImpl_ProcessVertices,
7862 /*** State block ***/
7863 IWineD3DDeviceImpl_BeginStateBlock,
7864 IWineD3DDeviceImpl_EndStateBlock,
7865 /*** Scene management ***/
7866 IWineD3DDeviceImpl_BeginScene,
7867 IWineD3DDeviceImpl_EndScene,
7868 IWineD3DDeviceImpl_Present,
7869 IWineD3DDeviceImpl_Clear,
7870 IWineD3DDeviceImpl_ClearRendertargetView,
7872 IWineD3DDeviceImpl_SetPrimitiveType,
7873 IWineD3DDeviceImpl_GetPrimitiveType,
7874 IWineD3DDeviceImpl_DrawPrimitive,
7875 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7876 IWineD3DDeviceImpl_DrawPrimitiveUP,
7877 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7878 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7879 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7880 IWineD3DDeviceImpl_DrawRectPatch,
7881 IWineD3DDeviceImpl_DrawTriPatch,
7882 IWineD3DDeviceImpl_DeletePatch,
7883 IWineD3DDeviceImpl_ColorFill,
7884 IWineD3DDeviceImpl_UpdateTexture,
7885 IWineD3DDeviceImpl_UpdateSurface,
7886 IWineD3DDeviceImpl_GetFrontBufferData,
7887 /*** object tracking ***/
7888 IWineD3DDeviceImpl_ResourceReleased,
7889 IWineD3DDeviceImpl_EnumResources
7892 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7893 WINED3DRS_ALPHABLENDENABLE ,
7894 WINED3DRS_ALPHAFUNC ,
7895 WINED3DRS_ALPHAREF ,
7896 WINED3DRS_ALPHATESTENABLE ,
7898 WINED3DRS_COLORWRITEENABLE ,
7899 WINED3DRS_DESTBLEND ,
7900 WINED3DRS_DITHERENABLE ,
7901 WINED3DRS_FILLMODE ,
7902 WINED3DRS_FOGDENSITY ,
7904 WINED3DRS_FOGSTART ,
7905 WINED3DRS_LASTPIXEL ,
7906 WINED3DRS_SHADEMODE ,
7907 WINED3DRS_SRCBLEND ,
7908 WINED3DRS_STENCILENABLE ,
7909 WINED3DRS_STENCILFAIL ,
7910 WINED3DRS_STENCILFUNC ,
7911 WINED3DRS_STENCILMASK ,
7912 WINED3DRS_STENCILPASS ,
7913 WINED3DRS_STENCILREF ,
7914 WINED3DRS_STENCILWRITEMASK ,
7915 WINED3DRS_STENCILZFAIL ,
7916 WINED3DRS_TEXTUREFACTOR ,
7927 WINED3DRS_ZWRITEENABLE
7930 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7931 WINED3DTSS_ALPHAARG0 ,
7932 WINED3DTSS_ALPHAARG1 ,
7933 WINED3DTSS_ALPHAARG2 ,
7934 WINED3DTSS_ALPHAOP ,
7935 WINED3DTSS_BUMPENVLOFFSET ,
7936 WINED3DTSS_BUMPENVLSCALE ,
7937 WINED3DTSS_BUMPENVMAT00 ,
7938 WINED3DTSS_BUMPENVMAT01 ,
7939 WINED3DTSS_BUMPENVMAT10 ,
7940 WINED3DTSS_BUMPENVMAT11 ,
7941 WINED3DTSS_COLORARG0 ,
7942 WINED3DTSS_COLORARG1 ,
7943 WINED3DTSS_COLORARG2 ,
7944 WINED3DTSS_COLOROP ,
7945 WINED3DTSS_RESULTARG ,
7946 WINED3DTSS_TEXCOORDINDEX ,
7947 WINED3DTSS_TEXTURETRANSFORMFLAGS
7950 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7951 WINED3DSAMP_ADDRESSU ,
7952 WINED3DSAMP_ADDRESSV ,
7953 WINED3DSAMP_ADDRESSW ,
7954 WINED3DSAMP_BORDERCOLOR ,
7955 WINED3DSAMP_MAGFILTER ,
7956 WINED3DSAMP_MINFILTER ,
7957 WINED3DSAMP_MIPFILTER ,
7958 WINED3DSAMP_MIPMAPLODBIAS ,
7959 WINED3DSAMP_MAXMIPLEVEL ,
7960 WINED3DSAMP_MAXANISOTROPY ,
7961 WINED3DSAMP_SRGBTEXTURE ,
7962 WINED3DSAMP_ELEMENTINDEX
7965 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7967 WINED3DRS_AMBIENTMATERIALSOURCE ,
7968 WINED3DRS_CLIPPING ,
7969 WINED3DRS_CLIPPLANEENABLE ,
7970 WINED3DRS_COLORVERTEX ,
7971 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7972 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7973 WINED3DRS_FOGDENSITY ,
7975 WINED3DRS_FOGSTART ,
7976 WINED3DRS_FOGTABLEMODE ,
7977 WINED3DRS_FOGVERTEXMODE ,
7978 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7979 WINED3DRS_LIGHTING ,
7980 WINED3DRS_LOCALVIEWER ,
7981 WINED3DRS_MULTISAMPLEANTIALIAS ,
7982 WINED3DRS_MULTISAMPLEMASK ,
7983 WINED3DRS_NORMALIZENORMALS ,
7984 WINED3DRS_PATCHEDGESTYLE ,
7985 WINED3DRS_POINTSCALE_A ,
7986 WINED3DRS_POINTSCALE_B ,
7987 WINED3DRS_POINTSCALE_C ,
7988 WINED3DRS_POINTSCALEENABLE ,
7989 WINED3DRS_POINTSIZE ,
7990 WINED3DRS_POINTSIZE_MAX ,
7991 WINED3DRS_POINTSIZE_MIN ,
7992 WINED3DRS_POINTSPRITEENABLE ,
7993 WINED3DRS_RANGEFOGENABLE ,
7994 WINED3DRS_SPECULARMATERIALSOURCE ,
7995 WINED3DRS_TWEENFACTOR ,
7996 WINED3DRS_VERTEXBLEND ,
7997 WINED3DRS_CULLMODE ,
8001 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8002 WINED3DTSS_TEXCOORDINDEX ,
8003 WINED3DTSS_TEXTURETRANSFORMFLAGS
8006 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8007 WINED3DSAMP_DMAPOFFSET
8010 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8011 DWORD rep = This->StateTable[state].representative;
8015 WineD3DContext *context;
8018 for(i = 0; i < This->numContexts; i++) {
8019 context = This->contexts[i];
8020 if(isStateDirty(context, rep)) continue;
8022 context->dirtyArray[context->numDirtyEntries++] = rep;
8025 context->isStateDirty[idx] |= (1 << shift);
8029 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8030 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8031 /* The drawable size of a pbuffer render target is the current pbuffer size
8033 *width = dev->pbufferWidth;
8034 *height = dev->pbufferHeight;
8037 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8038 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8040 *width = This->pow2Width;
8041 *height = This->pow2Height;
8044 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8045 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8046 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8047 * current context's drawable, which is the size of the back buffer of the swapchain
8048 * the active context belongs to. The back buffer of the swapchain is stored as the
8049 * surface the context belongs to.
8051 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8052 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;