2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
54 /* static function declarations */
55 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /**********************************************************
58 * Global variable / Constants follow
59 **********************************************************/
60 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
62 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
63 * actually have the same values in GL and D3D. */
64 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
66 switch(primitive_type)
68 case WINED3DPT_POINTLIST:
71 case WINED3DPT_LINELIST:
74 case WINED3DPT_LINESTRIP:
77 case WINED3DPT_TRIANGLELIST:
80 case WINED3DPT_TRIANGLESTRIP:
81 return GL_TRIANGLE_STRIP;
83 case WINED3DPT_TRIANGLEFAN:
84 return GL_TRIANGLE_FAN;
86 case WINED3DPT_LINELIST_ADJ:
87 return GL_LINES_ADJACENCY_ARB;
89 case WINED3DPT_LINESTRIP_ADJ:
90 return GL_LINE_STRIP_ADJACENCY_ARB;
92 case WINED3DPT_TRIANGLELIST_ADJ:
93 return GL_TRIANGLES_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLESTRIP_ADJ:
96 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
99 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
104 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
106 switch(primitive_type)
109 return WINED3DPT_POINTLIST;
112 return WINED3DPT_LINELIST;
115 return WINED3DPT_LINESTRIP;
118 return WINED3DPT_TRIANGLELIST;
120 case GL_TRIANGLE_STRIP:
121 return WINED3DPT_TRIANGLESTRIP;
123 case GL_TRIANGLE_FAN:
124 return WINED3DPT_TRIANGLEFAN;
126 case GL_LINES_ADJACENCY_ARB:
127 return WINED3DPT_LINELIST_ADJ;
129 case GL_LINE_STRIP_ADJACENCY_ARB:
130 return WINED3DPT_LINESTRIP_ADJ;
132 case GL_TRIANGLES_ADJACENCY_ARB:
133 return WINED3DPT_TRIANGLELIST_ADJ;
135 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLESTRIP_ADJ;
139 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
140 return WINED3DPT_UNDEFINED;
145 /**********************************************************
146 * IUnknown parts follows
147 **********************************************************/
149 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
154 if (IsEqualGUID(riid, &IID_IUnknown)
155 || IsEqualGUID(riid, &IID_IWineD3DBase)
156 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
157 IUnknown_AddRef(iface);
162 return E_NOINTERFACE;
165 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
167 ULONG refCount = InterlockedIncrement(&This->ref);
169 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
173 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
175 ULONG refCount = InterlockedDecrement(&This->ref);
177 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
182 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
183 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
184 This->multistate_funcs[i] = NULL;
187 /* TODO: Clean up all the surfaces and textures! */
188 /* NOTE: You must release the parent if the object was created via a callback
189 ** ***************************/
191 if (!list_empty(&This->resources)) {
192 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
193 dumpResources(&This->resources);
196 if(This->contexts) ERR("Context array not freed!\n");
197 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
198 This->haveHardwareCursor = FALSE;
200 IWineD3D_Release(This->wineD3D);
201 This->wineD3D = NULL;
202 HeapFree(GetProcessHeap(), 0, This);
203 TRACE("Freed device %p\n", This);
209 /**********************************************************
210 * IWineD3DDevice implementation follows
211 **********************************************************/
212 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
214 *pParent = This->parent;
215 IUnknown_AddRef(This->parent);
219 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface,
220 struct wined3d_buffer_desc *desc, IUnknown *parent, IWineD3DBuffer **buffer)
222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
223 struct wined3d_buffer *object;
226 TRACE("iface %p, desc %p, parent %p, buffer %p\n", iface, desc, parent, buffer);
228 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
231 ERR("Failed to allocate memory\n");
232 return E_OUTOFMEMORY;
235 object->vtbl = &wined3d_buffer_vtbl;
236 object->desc = *desc;
238 FIXME("Ignoring access flags (pool)\n");
240 hr = resource_init(&object->resource, WINED3DRTYPE_BUFFER, This, desc->byte_width,
241 desc->usage, WINED3DFMT_UNKNOWN, WINED3DPOOL_MANAGED, parent);
244 WARN("Failed to initialize resource, returning %#x\n", hr);
245 HeapFree(GetProcessHeap(), 0, object);
249 TRACE("Created resource %p\n", object);
251 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
253 TRACE("size %#x, usage=%#x, format %s, memory @ %p, iface @ %p\n", object->resource.size, object->resource.usage,
254 debug_d3dformat(object->resource.format_desc->format), object->resource.allocatedMemory, object);
256 *buffer = (IWineD3DBuffer *)object;
261 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
262 DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer, HANDLE *sharedHandle, IUnknown *parent)
264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
265 /* Dummy format for now */
266 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_VERTEXDATA, &This->adapter->gl_info);
267 struct wined3d_buffer *object;
268 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
273 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
274 *ppVertexBuffer = NULL;
275 return WINED3DERR_INVALIDCALL;
276 } else if(Pool == WINED3DPOOL_SCRATCH) {
277 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
278 * anyway, SCRATCH vertex buffers aren't usable anywhere
280 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
281 *ppVertexBuffer = NULL;
282 return WINED3DERR_INVALIDCALL;
285 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
288 ERR("Out of memory\n");
289 *ppVertexBuffer = NULL;
290 return WINED3DERR_OUTOFVIDEOMEMORY;
293 object->vtbl = &wined3d_buffer_vtbl;
294 hr = resource_init(&object->resource, WINED3DRTYPE_VERTEXBUFFER, This, Size, Usage, format_desc, Pool, parent);
297 WARN("Failed to initialize resource, returning %#x\n", hr);
298 HeapFree(GetProcessHeap(), 0, object);
299 *ppVertexBuffer = NULL;
303 TRACE("(%p) : Created resource %p\n", This, object);
305 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
307 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
308 *ppVertexBuffer = (IWineD3DBuffer *)object;
312 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
313 * drawStridedFast (half-life 2).
315 * Basically converting the vertices in the buffer is quite expensive, and observations
316 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
317 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
319 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
320 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
321 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
322 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
324 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
325 * more. In this call we can convert dx7 buffers too.
327 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
328 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
329 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
330 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
331 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
332 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
333 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
334 } else if(dxVersion <= 7 && conv) {
335 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
337 object->flags |= WINED3D_BUFFER_CREATEBO;
342 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
343 GLenum error, glUsage;
344 TRACE("Creating VBO for Index Buffer %p\n", object);
346 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
347 * restored on the next draw
349 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
351 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
352 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
357 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
358 error = glGetError();
359 if(error != GL_NO_ERROR || object->vbo == 0) {
360 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
364 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
365 error = glGetError();
366 if(error != GL_NO_ERROR) {
367 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
371 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
372 * copy no readback will be needed
374 glUsage = GL_STATIC_DRAW_ARB;
375 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
376 error = glGetError();
377 if(error != GL_NO_ERROR) {
378 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
382 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
386 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
387 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
392 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
393 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
394 HANDLE *sharedHandle, IUnknown *parent) {
395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
396 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
397 IWineD3DIndexBufferImpl *object;
400 TRACE("(%p) Creating index buffer\n", This);
402 /* Allocate the storage for the device */
403 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
406 ERR("Out of memory\n");
407 *ppIndexBuffer = NULL;
408 return WINED3DERR_OUTOFVIDEOMEMORY;
411 object->lpVtbl = &IWineD3DIndexBuffer_Vtbl;
412 hr = resource_init(&object->resource, WINED3DRTYPE_INDEXBUFFER, This, Length, Usage, format_desc, Pool, parent);
415 WARN("Failed to initialize resource, returning %#x\n", hr);
416 HeapFree(GetProcessHeap(), 0, object);
417 *ppIndexBuffer = NULL;
421 TRACE("(%p) : Created resource %p\n", This, object);
423 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
425 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
426 CreateIndexBufferVBO(This, object);
429 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
430 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
431 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
436 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
439 IWineD3DStateBlockImpl *object;
443 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
446 ERR("Out of memory\n");
447 *ppStateBlock = NULL;
448 return WINED3DERR_OUTOFVIDEOMEMORY;
451 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
452 object->wineD3DDevice = This;
453 object->parent = parent;
455 object->blockType = Type;
457 *ppStateBlock = (IWineD3DStateBlock *)object;
459 for(i = 0; i < LIGHTMAP_SIZE; i++) {
460 list_init(&object->lightMap[i]);
463 temp_result = allocate_shader_constants(object);
464 if (FAILED(temp_result))
466 HeapFree(GetProcessHeap(), 0, object);
470 /* Special case - Used during initialization to produce a placeholder stateblock
471 so other functions called can update a state block */
472 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
474 /* Don't bother increasing the reference count otherwise a device will never
475 be freed due to circular dependencies */
479 /* Otherwise, might as well set the whole state block to the appropriate values */
480 if (This->stateBlock != NULL)
481 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
483 memset(object->streamFreq, 1, sizeof(object->streamFreq));
485 /* Reset the ref and type after kludging it */
486 object->wineD3DDevice = This;
488 object->blockType = Type;
490 TRACE("Updating changed flags appropriate for type %d\n", Type);
492 if (Type == WINED3DSBT_ALL) {
494 TRACE("ALL => Pretend everything has changed\n");
495 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
497 /* Lights are not part of the changed / set structure */
498 for(j = 0; j < LIGHTMAP_SIZE; j++) {
500 LIST_FOR_EACH(e, &object->lightMap[j]) {
501 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
502 light->changed = TRUE;
503 light->enabledChanged = TRUE;
506 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
507 object->contained_render_states[j - 1] = j;
509 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
510 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
511 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
512 object->contained_transform_states[j - 1] = j;
514 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
515 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
516 object->contained_vs_consts_f[j] = j;
518 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
519 for(j = 0; j < MAX_CONST_I; j++) {
520 object->contained_vs_consts_i[j] = j;
522 object->num_contained_vs_consts_i = MAX_CONST_I;
523 for(j = 0; j < MAX_CONST_B; j++) {
524 object->contained_vs_consts_b[j] = j;
526 object->num_contained_vs_consts_b = MAX_CONST_B;
527 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
528 object->contained_ps_consts_f[j] = j;
530 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
531 for(j = 0; j < MAX_CONST_I; j++) {
532 object->contained_ps_consts_i[j] = j;
534 object->num_contained_ps_consts_i = MAX_CONST_I;
535 for(j = 0; j < MAX_CONST_B; j++) {
536 object->contained_ps_consts_b[j] = j;
538 object->num_contained_ps_consts_b = MAX_CONST_B;
539 for(i = 0; i < MAX_TEXTURES; i++) {
540 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
542 object->contained_tss_states[object->num_contained_tss_states].stage = i;
543 object->contained_tss_states[object->num_contained_tss_states].state = j;
544 object->num_contained_tss_states++;
547 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
548 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
549 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
550 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
551 object->num_contained_sampler_states++;
555 for(i = 0; i < MAX_STREAMS; i++) {
556 if(object->streamSource[i]) {
557 IWineD3DBuffer_AddRef(object->streamSource[i]);
560 if(object->pIndexData) {
561 IWineD3DIndexBuffer_AddRef(object->pIndexData);
563 if(object->vertexShader) {
564 IWineD3DVertexShader_AddRef(object->vertexShader);
566 if(object->pixelShader) {
567 IWineD3DPixelShader_AddRef(object->pixelShader);
570 } else if (Type == WINED3DSBT_PIXELSTATE) {
572 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
573 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
575 object->changed.pixelShader = TRUE;
577 /* Pixel Shader Constants */
578 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
579 object->contained_ps_consts_f[i] = i;
580 object->changed.pixelShaderConstantsF[i] = TRUE;
582 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
583 for (i = 0; i < MAX_CONST_B; ++i) {
584 object->contained_ps_consts_b[i] = i;
585 object->changed.pixelShaderConstantsB |= (1 << i);
587 object->num_contained_ps_consts_b = MAX_CONST_B;
588 for (i = 0; i < MAX_CONST_I; ++i) {
589 object->contained_ps_consts_i[i] = i;
590 object->changed.pixelShaderConstantsI |= (1 << i);
592 object->num_contained_ps_consts_i = MAX_CONST_I;
594 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
595 DWORD rs = SavedPixelStates_R[i];
596 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
597 object->contained_render_states[i] = rs;
599 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
600 for (j = 0; j < MAX_TEXTURES; j++) {
601 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
602 DWORD state = SavedPixelStates_T[i];
603 object->changed.textureState[j] |= 1 << state;
604 object->contained_tss_states[object->num_contained_tss_states].stage = j;
605 object->contained_tss_states[object->num_contained_tss_states].state = state;
606 object->num_contained_tss_states++;
609 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
610 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
611 DWORD state = SavedPixelStates_S[i];
612 object->changed.samplerState[j] |= 1 << state;
613 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
614 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
615 object->num_contained_sampler_states++;
618 if(object->pixelShader) {
619 IWineD3DPixelShader_AddRef(object->pixelShader);
622 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
623 * on them. This makes releasing the buffer easier
625 for(i = 0; i < MAX_STREAMS; i++) {
626 object->streamSource[i] = NULL;
628 object->pIndexData = NULL;
629 object->vertexShader = NULL;
631 } else if (Type == WINED3DSBT_VERTEXSTATE) {
633 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
634 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
636 object->changed.vertexShader = TRUE;
638 /* Vertex Shader Constants */
639 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
640 object->changed.vertexShaderConstantsF[i] = TRUE;
641 object->contained_vs_consts_f[i] = i;
643 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
644 for (i = 0; i < MAX_CONST_B; ++i) {
645 object->contained_vs_consts_b[i] = i;
646 object->changed.vertexShaderConstantsB |= (1 << i);
648 object->num_contained_vs_consts_b = MAX_CONST_B;
649 for (i = 0; i < MAX_CONST_I; ++i) {
650 object->contained_vs_consts_i[i] = i;
651 object->changed.vertexShaderConstantsI |= (1 << i);
653 object->num_contained_vs_consts_i = MAX_CONST_I;
654 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
655 DWORD rs = SavedVertexStates_R[i];
656 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
657 object->contained_render_states[i] = rs;
659 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
660 for (j = 0; j < MAX_TEXTURES; j++) {
661 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
662 DWORD state = SavedVertexStates_T[i];
663 object->changed.textureState[j] |= 1 << state;
664 object->contained_tss_states[object->num_contained_tss_states].stage = j;
665 object->contained_tss_states[object->num_contained_tss_states].state = state;
666 object->num_contained_tss_states++;
669 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
670 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
671 DWORD state = SavedVertexStates_S[i];
672 object->changed.samplerState[j] |= 1 << state;
673 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
674 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
675 object->num_contained_sampler_states++;
679 for(j = 0; j < LIGHTMAP_SIZE; j++) {
681 LIST_FOR_EACH(e, &object->lightMap[j]) {
682 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
683 light->changed = TRUE;
684 light->enabledChanged = TRUE;
688 for(i = 0; i < MAX_STREAMS; i++) {
689 if(object->streamSource[i]) {
690 IWineD3DBuffer_AddRef(object->streamSource[i]);
693 if(object->vertexShader) {
694 IWineD3DVertexShader_AddRef(object->vertexShader);
696 object->pIndexData = NULL;
697 object->pixelShader = NULL;
699 FIXME("Unrecognized state block type %d\n", Type);
702 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
706 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
708 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
709 unsigned int Size = 1;
710 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(Format, &GLINFO_LOCATION);
714 TRACE("(%p) Create surface\n",This);
716 if(MultisampleQuality > 0) {
717 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
718 MultisampleQuality=0;
721 /** FIXME: Check that the format is supported
723 *******************************/
725 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
726 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
728 *********************************/
729 mul_4w = (Width + 3) & ~3;
730 mul_4h = (Height + 3) & ~3;
731 if (WINED3DFMT_UNKNOWN == Format) {
733 } else if (Format == WINED3DFMT_DXT1) {
734 /* DXT1 is half byte per pixel */
735 Size = (mul_4w * glDesc->byte_count * mul_4h) >> 1;
737 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
738 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
739 Format == WINED3DFMT_ATI2N) {
740 Size = (mul_4w * glDesc->byte_count * mul_4h);
742 /* The pitch is a multiple of 4 bytes */
743 Size = ((Width * glDesc->byte_count) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
747 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
749 /** Create and initialise the surface resource **/
750 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
753 ERR("Out of memory\n");
755 return WINED3DERR_OUTOFVIDEOMEMORY;
758 /* Look at the implementation and set the correct Vtable */
762 /* Check if a 3D adapter is available when creating gl surfaces */
765 ERR("OpenGL surfaces are not available without opengl\n");
766 HeapFree(GetProcessHeap(), 0, object);
767 return WINED3DERR_NOTAVAILABLE;
769 object->lpVtbl = &IWineD3DSurface_Vtbl;
773 object->lpVtbl = &IWineGDISurface_Vtbl;
777 /* To be sure to catch this */
778 ERR("Unknown requested surface implementation %d!\n", Impl);
779 HeapFree(GetProcessHeap(), 0, object);
780 return WINED3DERR_INVALIDCALL;
783 hr = resource_init(&object->resource, WINED3DRTYPE_SURFACE, This, Size, Usage, glDesc, Pool, parent);
786 WARN("Failed to initialize resource, returning %#x\n", hr);
787 HeapFree(GetProcessHeap(), 0, object);
792 TRACE("(%p) : Created resource %p\n", This, object);
794 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
796 *ppSurface = (IWineD3DSurface *)object;
798 /* "Standalone" surface */
799 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
801 object->currentDesc.Width = Width;
802 object->currentDesc.Height = Height;
803 object->currentDesc.MultiSampleType = MultiSample;
804 object->currentDesc.MultiSampleQuality = MultisampleQuality;
805 object->glDescription.level = Level;
806 list_init(&object->overlays);
809 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
810 object->Flags |= Discard ? SFLAG_DISCARD : 0;
811 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
812 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
814 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
816 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
817 * this function is too deep to need to care about things like this.
818 * Levels need to be checked too, and possibly Type since they all affect what can be done.
819 * ****************************************/
821 case WINED3DPOOL_SCRATCH:
823 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
824 "which are mutually exclusive, setting lockable to TRUE\n");
827 case WINED3DPOOL_SYSTEMMEM:
828 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
829 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
830 case WINED3DPOOL_MANAGED:
831 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
832 "Usage of DYNAMIC which are mutually exclusive, not doing "
833 "anything just telling you.\n");
835 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
836 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
837 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
838 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
841 FIXME("(%p) Unknown pool %d\n", This, Pool);
845 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
846 FIXME("Trying to create a render target that isn't in the default pool\n");
849 /* mark the texture as dirty so that it gets loaded first time around*/
850 surface_add_dirty_rect(*ppSurface, NULL);
851 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
852 This, Width, Height, Format, debug_d3dformat(Format),
853 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
855 list_init(&object->renderbuffers);
857 /* Call the private setup routine */
858 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)object);
861 ERR("Private setup failed, returning %#x\n", hr);
862 IWineD3DSurface_Release(*ppSurface);
870 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
871 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
873 struct wined3d_rendertarget_view *object;
875 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
878 ERR("Failed to allocate memory\n");
879 return E_OUTOFMEMORY;
882 object->vtbl = &wined3d_rendertarget_view_vtbl;
883 object->refcount = 1;
884 IWineD3DResource_AddRef(resource);
885 object->resource = resource;
886 object->parent = parent;
888 *rendertarget_view = (IWineD3DRendertargetView *)object;
893 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
894 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
895 IWineD3DTexture **ppTexture, HANDLE *pSharedHandle, IUnknown *parent)
897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
898 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
899 IWineD3DTextureImpl *object;
904 unsigned int pow2Width;
905 unsigned int pow2Height;
907 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
908 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
909 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
911 /* TODO: It should only be possible to create textures for formats
912 that are reported as supported */
913 if (WINED3DFMT_UNKNOWN >= Format) {
914 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
915 return WINED3DERR_INVALIDCALL;
918 /* Non-power2 support */
919 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO))
926 /* Find the nearest pow2 match */
927 pow2Width = pow2Height = 1;
928 while (pow2Width < Width) pow2Width <<= 1;
929 while (pow2Height < Height) pow2Height <<= 1;
931 if (pow2Width != Width || pow2Height != Height)
935 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
936 return WINED3DERR_INVALIDCALL;
942 /* Calculate levels for mip mapping */
943 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
945 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
947 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
948 return WINED3DERR_INVALIDCALL;
953 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
954 return WINED3DERR_INVALIDCALL;
961 Levels = wined3d_log2i(max(Width, Height)) + 1;
962 TRACE("Calculated levels = %d\n", Levels);
965 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
968 ERR("Out of memory\n");
970 return WINED3DERR_OUTOFVIDEOMEMORY;
973 object->lpVtbl = &IWineD3DTexture_Vtbl;
974 hr = resource_init(&object->resource, WINED3DRTYPE_TEXTURE, This, 0, Usage, format_desc, Pool, parent);
977 WARN("Failed to initialize resource, returning %#x\n", hr);
978 HeapFree(GetProcessHeap(), 0, object);
983 TRACE("(%p) : Created resource %p\n", This, object);
985 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
987 *ppTexture = (IWineD3DTexture *)object;
989 basetexture_init(&object->baseTexture, Levels, Usage);
991 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
993 object->baseTexture.minMipLookup = minMipLookup;
994 object->baseTexture.magLookup = magLookup;
996 object->baseTexture.minMipLookup = minMipLookup_noFilter;
997 object->baseTexture.magLookup = magLookup_noFilter;
1000 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1001 /* Precalculated scaling for 'faked' non power of two texture coords.
1002 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
1003 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
1004 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
1006 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
1007 object->baseTexture.pow2Matrix[0] = 1.0;
1008 object->baseTexture.pow2Matrix[5] = 1.0;
1009 object->baseTexture.pow2Matrix[10] = 1.0;
1010 object->baseTexture.pow2Matrix[15] = 1.0;
1011 object->target = GL_TEXTURE_2D;
1012 object->cond_np2 = TRUE;
1013 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1014 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
1015 (Width != pow2Width || Height != pow2Height) &&
1016 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
1018 object->baseTexture.pow2Matrix[0] = (float)Width;
1019 object->baseTexture.pow2Matrix[5] = (float)Height;
1020 object->baseTexture.pow2Matrix[10] = 1.0;
1021 object->baseTexture.pow2Matrix[15] = 1.0;
1022 object->target = GL_TEXTURE_RECTANGLE_ARB;
1023 object->cond_np2 = TRUE;
1024 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1026 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
1027 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
1028 object->baseTexture.pow2Matrix[10] = 1.0;
1029 object->baseTexture.pow2Matrix[15] = 1.0;
1030 object->target = GL_TEXTURE_2D;
1031 object->cond_np2 = FALSE;
1033 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
1035 /* Generate all the surfaces */
1038 for (i = 0; i < object->baseTexture.levels; i++)
1040 /* use the callback to create the texture surface */
1041 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpH, Format,
1042 Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i]);
1043 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1044 FIXME("Failed to create surface %p\n", object);
1046 object->surfaces[i] = NULL;
1047 IWineD3DTexture_Release((IWineD3DTexture *)object);
1053 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1054 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1055 surface_set_texture_target(object->surfaces[i], object->target);
1056 /* calculate the next mipmap level */
1057 tmpW = max(1, tmpW >> 1);
1058 tmpH = max(1, tmpH >> 1);
1060 object->baseTexture.internal_preload = texture_internal_preload;
1062 TRACE("(%p) : Created texture %p\n", This, object);
1066 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1067 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1068 IWineD3DVolumeTexture **ppVolumeTexture, HANDLE *pSharedHandle, IUnknown *parent)
1070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1071 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1072 IWineD3DVolumeTextureImpl *object;
1079 /* TODO: It should only be possible to create textures for formats
1080 that are reported as supported */
1081 if (WINED3DFMT_UNKNOWN >= Format) {
1082 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1083 return WINED3DERR_INVALIDCALL;
1085 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1086 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
1087 return WINED3DERR_INVALIDCALL;
1090 /* Calculate levels for mip mapping */
1091 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1093 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1095 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1096 return WINED3DERR_INVALIDCALL;
1101 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1102 return WINED3DERR_INVALIDCALL;
1109 Levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
1110 TRACE("Calculated levels = %d\n", Levels);
1113 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1116 ERR("Out of memory\n");
1117 *ppVolumeTexture = NULL;
1118 return WINED3DERR_OUTOFVIDEOMEMORY;
1121 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1122 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUMETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1125 WARN("Failed to initialize resource, returning %#x\n", hr);
1126 HeapFree(GetProcessHeap(), 0, object);
1127 *ppVolumeTexture = NULL;
1131 TRACE("(%p) : Created resource %p\n", This, object);
1133 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1135 basetexture_init(&object->baseTexture, Levels, Usage);
1137 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1138 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1140 /* Is NP2 support for volumes needed? */
1141 object->baseTexture.pow2Matrix[ 0] = 1.0;
1142 object->baseTexture.pow2Matrix[ 5] = 1.0;
1143 object->baseTexture.pow2Matrix[10] = 1.0;
1144 object->baseTexture.pow2Matrix[15] = 1.0;
1146 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1148 object->baseTexture.minMipLookup = minMipLookup;
1149 object->baseTexture.magLookup = magLookup;
1151 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1152 object->baseTexture.magLookup = magLookup_noFilter;
1155 /* Generate all the surfaces */
1160 for (i = 0; i < object->baseTexture.levels; i++)
1163 /* Create the volume */
1164 hr = IWineD3DDeviceParent_CreateVolume(This->device_parent, parent,
1165 tmpW, tmpH, tmpD, Format, Pool, Usage, &object->volumes[i]);
1167 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1168 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1169 *ppVolumeTexture = NULL;
1173 /* Set its container to this object */
1174 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1176 /* calculate the next mipmap level */
1177 tmpW = max(1, tmpW >> 1);
1178 tmpH = max(1, tmpH >> 1);
1179 tmpD = max(1, tmpD >> 1);
1181 object->baseTexture.internal_preload = volumetexture_internal_preload;
1183 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1184 TRACE("(%p) : Created volume texture %p\n", This, object);
1188 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1189 UINT Width, UINT Height, UINT Depth,
1191 WINED3DFORMAT Format, WINED3DPOOL Pool,
1192 IWineD3DVolume** ppVolume,
1193 HANDLE* pSharedHandle, IUnknown *parent) {
1195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1196 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1197 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1200 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1201 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1202 return WINED3DERR_INVALIDCALL;
1205 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1208 ERR("Out of memory\n");
1210 return WINED3DERR_OUTOFVIDEOMEMORY;
1213 object->lpVtbl = &IWineD3DVolume_Vtbl;
1214 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUME, This,
1215 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1218 WARN("Failed to initialize resource, returning %#x\n", hr);
1219 HeapFree(GetProcessHeap(), 0, object);
1224 TRACE("(%p) : Created resource %p\n", This, object);
1226 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1228 *ppVolume = (IWineD3DVolume *)object;
1230 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1231 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1233 object->currentDesc.Width = Width;
1234 object->currentDesc.Height = Height;
1235 object->currentDesc.Depth = Depth;
1237 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1238 object->lockable = TRUE;
1239 object->locked = FALSE;
1240 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1241 object->dirty = TRUE;
1243 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1248 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1249 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1250 IWineD3DCubeTexture **ppCubeTexture, HANDLE *pSharedHandle, IUnknown *parent)
1252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1253 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1254 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1258 unsigned int pow2EdgeLength;
1260 /* TODO: It should only be possible to create textures for formats
1261 that are reported as supported */
1262 if (WINED3DFMT_UNKNOWN >= Format) {
1263 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1264 return WINED3DERR_INVALIDCALL;
1267 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1268 WARN("(%p) : Tried to create not supported cube texture\n", This);
1269 return WINED3DERR_INVALIDCALL;
1272 /* Calculate levels for mip mapping */
1273 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1275 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1277 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1278 return WINED3DERR_INVALIDCALL;
1283 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1284 return WINED3DERR_INVALIDCALL;
1291 Levels = wined3d_log2i(EdgeLength) + 1;
1292 TRACE("Calculated levels = %d\n", Levels);
1295 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1298 ERR("Out of memory\n");
1299 *ppCubeTexture = NULL;
1300 return WINED3DERR_OUTOFVIDEOMEMORY;
1303 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1304 hr = resource_init(&object->resource, WINED3DRTYPE_CUBETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1307 WARN("Failed to initialize resource, returning %#x\n", hr);
1308 HeapFree(GetProcessHeap(), 0, object);
1309 *ppCubeTexture = NULL;
1313 TRACE("(%p) : Created resource %p\n", This, object);
1315 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1317 basetexture_init(&object->baseTexture, Levels, Usage);
1319 TRACE("(%p) Create Cube Texture\n", This);
1321 /* Find the nearest pow2 match */
1323 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1325 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
1326 /* Precalculated scaling for 'faked' non power of two texture coords */
1327 object->baseTexture.pow2Matrix[ 0] = 1.0;
1328 object->baseTexture.pow2Matrix[ 5] = 1.0;
1329 object->baseTexture.pow2Matrix[10] = 1.0;
1330 object->baseTexture.pow2Matrix[15] = 1.0;
1332 /* Precalculated scaling for 'faked' non power of two texture coords */
1333 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1334 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1335 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1336 object->baseTexture.pow2Matrix[15] = 1.0;
1339 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1341 object->baseTexture.minMipLookup = minMipLookup;
1342 object->baseTexture.magLookup = magLookup;
1344 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1345 object->baseTexture.magLookup = magLookup_noFilter;
1348 /* Generate all the surfaces */
1350 for (i = 0; i < object->baseTexture.levels; i++) {
1352 /* Create the 6 faces */
1353 for (j = 0; j < 6; j++) {
1354 static const GLenum cube_targets[6] = {
1355 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1356 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1357 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1358 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1359 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1360 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1363 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpW,
1364 Format, Usage, Pool, i /* Level */, j, &object->surfaces[j][i]);
1367 FIXME("(%p) Failed to create surface\n",object);
1368 IWineD3DCubeTexture_Release((IWineD3DCubeTexture *)object);
1369 *ppCubeTexture = NULL;
1372 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1373 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1374 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1376 tmpW = max(1, tmpW >> 1);
1378 object->baseTexture.internal_preload = cubetexture_internal_preload;
1380 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1381 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1385 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1387 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1388 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1389 const IWineD3DQueryVtbl *vtable;
1391 /* Just a check to see if we support this type of query */
1393 case WINED3DQUERYTYPE_OCCLUSION:
1394 TRACE("(%p) occlusion query\n", This);
1395 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1398 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1400 vtable = &IWineD3DOcclusionQuery_Vtbl;
1403 case WINED3DQUERYTYPE_EVENT:
1404 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1405 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1406 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1408 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1410 vtable = &IWineD3DEventQuery_Vtbl;
1414 case WINED3DQUERYTYPE_VCACHE:
1415 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1416 case WINED3DQUERYTYPE_VERTEXSTATS:
1417 case WINED3DQUERYTYPE_TIMESTAMP:
1418 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1419 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1420 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1421 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1422 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1423 case WINED3DQUERYTYPE_PIXELTIMINGS:
1424 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1425 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1427 /* Use the base Query vtable until we have a special one for each query */
1428 vtable = &IWineD3DQuery_Vtbl;
1429 FIXME("(%p) Unhandled query type %d\n", This, Type);
1431 if(NULL == ppQuery || hr != WINED3D_OK) {
1435 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1438 ERR("Out of memory\n");
1440 return WINED3DERR_OUTOFVIDEOMEMORY;
1443 object->lpVtbl = vtable;
1444 object->type = Type;
1445 object->state = QUERY_CREATED;
1446 object->wineD3DDevice = This;
1447 object->parent = parent;
1450 *ppQuery = (IWineD3DQuery *)object;
1452 /* allocated the 'extended' data based on the type of query requested */
1454 case WINED3DQUERYTYPE_OCCLUSION:
1455 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1456 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1458 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1459 TRACE("(%p) Allocating data for an occlusion query\n", This);
1461 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1463 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1467 case WINED3DQUERYTYPE_EVENT:
1468 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1469 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1471 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1473 if(GL_SUPPORT(APPLE_FENCE)) {
1474 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1475 checkGLcall("glGenFencesAPPLE");
1476 } else if(GL_SUPPORT(NV_FENCE)) {
1477 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1478 checkGLcall("glGenFencesNV");
1483 case WINED3DQUERYTYPE_VCACHE:
1484 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1485 case WINED3DQUERYTYPE_VERTEXSTATS:
1486 case WINED3DQUERYTYPE_TIMESTAMP:
1487 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1488 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1489 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1490 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1491 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1492 case WINED3DQUERYTYPE_PIXELTIMINGS:
1493 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1494 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1496 object->extendedData = 0;
1497 FIXME("(%p) Unhandled query type %d\n",This , Type);
1499 TRACE("(%p) : Created Query %p\n", This, object);
1503 /*****************************************************************************
1504 * IWineD3DDeviceImpl_SetupFullscreenWindow
1506 * Helper function that modifies a HWND's Style and ExStyle for proper
1510 * iface: Pointer to the IWineD3DDevice interface
1511 * window: Window to setup
1513 *****************************************************************************/
1514 static LONG fullscreen_style(LONG orig_style) {
1515 LONG style = orig_style;
1516 style &= ~WS_CAPTION;
1517 style &= ~WS_THICKFRAME;
1519 /* Make sure the window is managed, otherwise we won't get keyboard input */
1520 style |= WS_POPUP | WS_SYSMENU;
1525 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1526 LONG exStyle = orig_exStyle;
1528 /* Filter out window decorations */
1529 exStyle &= ~WS_EX_WINDOWEDGE;
1530 exStyle &= ~WS_EX_CLIENTEDGE;
1535 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1538 LONG style, exStyle;
1539 /* Don't do anything if an original style is stored.
1540 * That shouldn't happen
1542 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1543 if (This->style || This->exStyle) {
1544 ERR("(%p): Want to change the window parameters of HWND %p, but "
1545 "another style is stored for restoration afterwards\n", This, window);
1548 /* Get the parameters and save them */
1549 style = GetWindowLongW(window, GWL_STYLE);
1550 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1551 This->style = style;
1552 This->exStyle = exStyle;
1554 style = fullscreen_style(style);
1555 exStyle = fullscreen_exStyle(exStyle);
1557 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1558 This->style, This->exStyle, style, exStyle);
1560 SetWindowLongW(window, GWL_STYLE, style);
1561 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1563 /* Inform the window about the update. */
1564 SetWindowPos(window, HWND_TOP, 0, 0,
1565 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1568 /*****************************************************************************
1569 * IWineD3DDeviceImpl_RestoreWindow
1571 * Helper function that restores a windows' properties when taking it out
1572 * of fullscreen mode
1575 * iface: Pointer to the IWineD3DDevice interface
1576 * window: Window to setup
1578 *****************************************************************************/
1579 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1581 LONG style, exStyle;
1583 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1584 * switch, do nothing
1586 if (!This->style && !This->exStyle) return;
1588 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1589 This, window, This->style, This->exStyle);
1591 style = GetWindowLongW(window, GWL_STYLE);
1592 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1594 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1595 * Some applications change it before calling Reset() when switching between windowed and
1596 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1598 if(style == fullscreen_style(This->style) &&
1599 exStyle == fullscreen_style(This->exStyle)) {
1600 SetWindowLongW(window, GWL_STYLE, This->style);
1601 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1604 /* Delete the old values */
1608 /* Inform the window about the update */
1609 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1610 0, 0, 0, 0, /* Pos, Size, ignored */
1611 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1614 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1615 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1616 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1617 IUnknown *parent, WINED3DSURFTYPE surface_type)
1619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1622 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1624 IUnknown *bufferParent;
1625 BOOL displaymode_set = FALSE;
1626 WINED3DDISPLAYMODE Mode;
1627 const struct GlPixelFormatDesc *format_desc;
1629 TRACE("(%p) : Created Additional Swap Chain\n", This);
1631 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1632 * does a device hold a reference to a swap chain giving them a lifetime of the device
1633 * or does the swap chain notify the device of its destruction.
1634 *******************************/
1636 /* Check the params */
1637 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1638 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1639 return WINED3DERR_INVALIDCALL;
1640 } else if (pPresentationParameters->BackBufferCount > 1) {
1641 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1644 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1647 ERR("Out of memory\n");
1648 *ppSwapChain = NULL;
1649 return WINED3DERR_OUTOFVIDEOMEMORY;
1652 switch(surface_type) {
1654 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1656 case SURFACE_OPENGL:
1657 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1659 case SURFACE_UNKNOWN:
1660 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1661 HeapFree(GetProcessHeap(), 0, object);
1662 return WINED3DERR_INVALIDCALL;
1664 object->wineD3DDevice = This;
1665 object->parent = parent;
1668 *ppSwapChain = (IWineD3DSwapChain *)object;
1670 /*********************
1671 * Lookup the window Handle and the relating X window handle
1672 ********************/
1674 /* Setup hwnd we are using, plus which display this equates to */
1675 object->win_handle = pPresentationParameters->hDeviceWindow;
1676 if (!object->win_handle) {
1677 object->win_handle = This->createParms.hFocusWindow;
1679 if(!pPresentationParameters->Windowed && object->win_handle) {
1680 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1681 pPresentationParameters->BackBufferWidth,
1682 pPresentationParameters->BackBufferHeight);
1685 hDc = GetDC(object->win_handle);
1686 TRACE("Using hDc %p\n", hDc);
1689 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1690 return WINED3DERR_NOTAVAILABLE;
1693 /* Get info on the current display setup */
1694 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1695 object->orig_width = Mode.Width;
1696 object->orig_height = Mode.Height;
1697 object->orig_fmt = Mode.Format;
1698 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1700 if (pPresentationParameters->Windowed &&
1701 ((pPresentationParameters->BackBufferWidth == 0) ||
1702 (pPresentationParameters->BackBufferHeight == 0) ||
1703 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1706 GetClientRect(object->win_handle, &Rect);
1708 if (pPresentationParameters->BackBufferWidth == 0) {
1709 pPresentationParameters->BackBufferWidth = Rect.right;
1710 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1712 if (pPresentationParameters->BackBufferHeight == 0) {
1713 pPresentationParameters->BackBufferHeight = Rect.bottom;
1714 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1716 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1717 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1718 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1722 /* Put the correct figures in the presentation parameters */
1723 TRACE("Copying across presentation parameters\n");
1724 object->presentParms = *pPresentationParameters;
1726 TRACE("calling rendertarget CB\n");
1727 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1728 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1729 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1730 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1731 if (SUCCEEDED(hr)) {
1732 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1733 if(surface_type == SURFACE_OPENGL) {
1734 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1737 ERR("Failed to create the front buffer\n");
1741 /*********************
1742 * Windowed / Fullscreen
1743 *******************/
1746 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1747 * so we should really check to see if there is a fullscreen swapchain already
1748 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1749 **************************************/
1751 if (!pPresentationParameters->Windowed) {
1752 WINED3DDISPLAYMODE mode;
1755 /* Change the display settings */
1756 mode.Width = pPresentationParameters->BackBufferWidth;
1757 mode.Height = pPresentationParameters->BackBufferHeight;
1758 mode.Format = pPresentationParameters->BackBufferFormat;
1759 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1761 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1762 displaymode_set = TRUE;
1766 * Create an opengl context for the display visual
1767 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1768 * use different properties after that point in time. FIXME: How to handle when requested format
1769 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1770 * it chooses is identical to the one already being used!
1771 **********************************/
1772 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1774 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1775 if(!object->context) {
1776 ERR("Failed to create the context array\n");
1780 object->num_contexts = 1;
1782 if(surface_type == SURFACE_OPENGL) {
1783 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1784 if (!object->context[0]) {
1785 ERR("Failed to create a new context\n");
1786 hr = WINED3DERR_NOTAVAILABLE;
1789 TRACE("Context created (HWND=%p, glContext=%p)\n",
1790 object->win_handle, object->context[0]->glCtx);
1794 /*********************
1795 * Create the back, front and stencil buffers
1796 *******************/
1797 if(object->presentParms.BackBufferCount > 0) {
1800 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1801 if(!object->backBuffer) {
1802 ERR("Out of memory\n");
1807 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1808 TRACE("calling rendertarget CB\n");
1809 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1810 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1811 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1812 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1814 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1816 ERR("Cannot create new back buffer\n");
1819 if(surface_type == SURFACE_OPENGL) {
1821 glDrawBuffer(GL_BACK);
1822 checkGLcall("glDrawBuffer(GL_BACK)");
1827 object->backBuffer = NULL;
1829 /* Single buffering - draw to front buffer */
1830 if(surface_type == SURFACE_OPENGL) {
1832 glDrawBuffer(GL_FRONT);
1833 checkGLcall("glDrawBuffer(GL_FRONT)");
1838 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1839 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1840 TRACE("Creating depth stencil buffer\n");
1841 if (This->auto_depth_stencil_buffer == NULL ) {
1842 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1843 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1844 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1845 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1846 &This->auto_depth_stencil_buffer);
1847 if (SUCCEEDED(hr)) {
1848 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1850 ERR("Failed to create the auto depth stencil\n");
1856 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1858 TRACE("Created swapchain %p\n", object);
1859 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1863 if (displaymode_set) {
1867 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1870 /* Change the display settings */
1871 memset(&devmode, 0, sizeof(devmode));
1872 devmode.dmSize = sizeof(devmode);
1873 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1874 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1875 devmode.dmPelsWidth = object->orig_width;
1876 devmode.dmPelsHeight = object->orig_height;
1877 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1880 if (object->backBuffer) {
1882 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1883 if(object->backBuffer[i]) {
1884 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1885 IUnknown_Release(bufferParent); /* once for the get parent */
1886 if (IUnknown_Release(bufferParent) > 0) {
1887 FIXME("(%p) Something's still holding the back buffer\n",This);
1891 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1892 object->backBuffer = NULL;
1894 if(object->context && object->context[0])
1895 DestroyContext(This, object->context[0]);
1896 if(object->frontBuffer) {
1897 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1898 IUnknown_Release(bufferParent); /* once for the get parent */
1899 if (IUnknown_Release(bufferParent) > 0) {
1900 FIXME("(%p) Something's still holding the front buffer\n",This);
1903 HeapFree(GetProcessHeap(), 0, object);
1907 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1908 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1910 TRACE("(%p)\n", This);
1912 return This->NumberOfSwapChains;
1915 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1917 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1919 if(iSwapChain < This->NumberOfSwapChains) {
1920 *pSwapChain = This->swapchains[iSwapChain];
1921 IWineD3DSwapChain_AddRef(*pSwapChain);
1922 TRACE("(%p) returning %p\n", This, *pSwapChain);
1925 TRACE("Swapchain out of range\n");
1927 return WINED3DERR_INVALIDCALL;
1932 * Vertex Declaration
1934 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1935 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1936 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1937 IWineD3DVertexDeclarationImpl *object = NULL;
1938 HRESULT hr = WINED3D_OK;
1940 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1941 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1943 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1946 ERR("Out of memory\n");
1947 *ppVertexDeclaration = NULL;
1948 return WINED3DERR_OUTOFVIDEOMEMORY;
1951 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
1952 object->wineD3DDevice = This;
1953 object->parent = parent;
1956 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1958 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1960 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1961 *ppVertexDeclaration = NULL;
1967 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1968 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1970 unsigned int idx, idx2;
1971 unsigned int offset;
1972 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1973 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1974 BOOL has_blend_idx = has_blend &&
1975 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1976 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1977 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1978 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1979 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1980 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1981 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1983 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1984 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1986 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1987 WINED3DVERTEXELEMENT *elements = NULL;
1990 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1991 if (has_blend_idx) num_blends--;
1993 /* Compute declaration size */
1994 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1995 has_psize + has_diffuse + has_specular + num_textures + 1;
1997 /* convert the declaration */
1998 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
2002 elements[size-1] = end_element;
2005 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
2006 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2007 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
2009 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
2010 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2011 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
2014 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2015 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
2017 elements[idx].UsageIndex = 0;
2020 if (has_blend && (num_blends > 0)) {
2021 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
2022 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2024 switch(num_blends) {
2025 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
2026 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
2027 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
2028 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
2030 ERR("Unexpected amount of blend values: %u\n", num_blends);
2033 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
2034 elements[idx].UsageIndex = 0;
2037 if (has_blend_idx) {
2038 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
2039 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
2040 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
2041 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
2042 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2044 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2045 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
2046 elements[idx].UsageIndex = 0;
2050 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2051 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
2052 elements[idx].UsageIndex = 0;
2056 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2057 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
2058 elements[idx].UsageIndex = 0;
2062 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2063 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
2064 elements[idx].UsageIndex = 0;
2068 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2069 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
2070 elements[idx].UsageIndex = 1;
2073 for (idx2 = 0; idx2 < num_textures; idx2++) {
2074 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
2075 switch (numcoords) {
2076 case WINED3DFVF_TEXTUREFORMAT1:
2077 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2079 case WINED3DFVF_TEXTUREFORMAT2:
2080 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
2082 case WINED3DFVF_TEXTUREFORMAT3:
2083 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2085 case WINED3DFVF_TEXTUREFORMAT4:
2086 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2089 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
2090 elements[idx].UsageIndex = idx2;
2094 /* Now compute offsets, and initialize the rest of the fields */
2095 for (idx = 0, offset = 0; idx < size-1; idx++) {
2096 elements[idx].Stream = 0;
2097 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
2098 elements[idx].Offset = offset;
2099 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
2102 *ppVertexElements = elements;
2106 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
2107 WINED3DVERTEXELEMENT* elements = NULL;
2108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2112 size = ConvertFvfToDeclaration(This, Fvf, &elements);
2113 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
2115 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
2116 HeapFree(GetProcessHeap(), 0, elements);
2117 if (hr != S_OK) return hr;
2122 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
2123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2124 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
2125 HRESULT hr = WINED3D_OK;
2127 if (!pFunction) return WINED3DERR_INVALIDCALL;
2129 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2132 ERR("Out of memory\n");
2133 *ppVertexShader = NULL;
2134 return WINED3DERR_OUTOFVIDEOMEMORY;
2137 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
2138 object->parent = parent;
2139 shader_init(&object->baseShader, iface, IWineD3DVertexShaderImpl_shader_ins);
2140 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2141 *ppVertexShader = (IWineD3DVertexShader *)object;
2143 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
2145 if (vertex_declaration) {
2146 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
2149 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
2152 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2153 IWineD3DVertexShader_Release(*ppVertexShader);
2154 *ppVertexShader = NULL;
2161 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
2162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2163 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2164 HRESULT hr = WINED3D_OK;
2166 if (!pFunction) return WINED3DERR_INVALIDCALL;
2168 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2171 ERR("Out of memory\n");
2172 *ppPixelShader = NULL;
2173 return WINED3DERR_OUTOFVIDEOMEMORY;
2176 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2177 object->parent = parent;
2178 shader_init(&object->baseShader, iface, IWineD3DPixelShaderImpl_shader_ins);
2179 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2180 *ppPixelShader = (IWineD3DPixelShader *)object;
2182 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2184 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
2187 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2188 IWineD3DPixelShader_Release(*ppPixelShader);
2189 *ppPixelShader = NULL;
2196 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2197 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2200 IWineD3DPaletteImpl *object;
2202 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2204 /* Create the new object */
2205 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2207 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2208 return E_OUTOFMEMORY;
2211 object->lpVtbl = &IWineD3DPalette_Vtbl;
2213 object->Flags = Flags;
2214 object->parent = Parent;
2215 object->wineD3DDevice = This;
2216 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2217 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2220 HeapFree( GetProcessHeap(), 0, object);
2221 return E_OUTOFMEMORY;
2224 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2226 IWineD3DPalette_Release((IWineD3DPalette *) object);
2230 *Palette = (IWineD3DPalette *) object;
2235 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2239 HDC dcb = NULL, dcs = NULL;
2240 WINEDDCOLORKEY colorkey;
2242 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2245 GetObjectA(hbm, sizeof(BITMAP), &bm);
2246 dcb = CreateCompatibleDC(NULL);
2248 SelectObject(dcb, hbm);
2252 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2253 * couldn't be loaded
2255 memset(&bm, 0, sizeof(bm));
2260 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2261 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2262 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
2264 ERR("Wine logo requested, but failed to create surface\n");
2269 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2270 if(FAILED(hr)) goto out;
2271 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2272 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2274 colorkey.dwColorSpaceLowValue = 0;
2275 colorkey.dwColorSpaceHighValue = 0;
2276 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2278 /* Fill the surface with a white color to show that wined3d is there */
2279 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2292 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2294 /* Under DirectX you can have texture stage operations even if no texture is
2295 bound, whereas opengl will only do texture operations when a valid texture is
2296 bound. We emulate this by creating dummy textures and binding them to each
2297 texture stage, but disable all stages by default. Hence if a stage is enabled
2298 then the default texture will kick in until replaced by a SetTexture call */
2301 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2302 /* The dummy texture does not have client storage backing */
2303 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2304 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2306 for (i = 0; i < GL_LIMITS(textures); i++) {
2307 GLubyte white = 255;
2309 /* Make appropriate texture active */
2310 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2311 checkGLcall("glActiveTextureARB");
2313 /* Generate an opengl texture name */
2314 glGenTextures(1, &This->dummyTextureName[i]);
2315 checkGLcall("glGenTextures");
2316 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2318 /* Generate a dummy 2d texture (not using 1d because they cause many
2319 * DRI drivers fall back to sw) */
2320 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2321 checkGLcall("glBindTexture");
2323 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2324 checkGLcall("glTexImage2D");
2326 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2327 /* Reenable because if supported it is enabled by default */
2328 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2329 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2335 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2336 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2339 IWineD3DSwapChainImpl *swapchain = NULL;
2344 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2346 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2347 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2349 /* TODO: Test if OpenGL is compiled in and loaded */
2351 TRACE("(%p) : Creating stateblock\n", This);
2352 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2353 hr = IWineD3DDevice_CreateStateBlock(iface,
2355 (IWineD3DStateBlock **)&This->stateBlock,
2357 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2358 WARN("Failed to create stateblock\n");
2361 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2362 This->updateStateBlock = This->stateBlock;
2363 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2365 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2366 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2368 This->NumberOfPalettes = 1;
2369 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2370 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2371 ERR("Out of memory!\n");
2374 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2375 if(!This->palettes[0]) {
2376 ERR("Out of memory!\n");
2379 for (i = 0; i < 256; ++i) {
2380 This->palettes[0][i].peRed = 0xFF;
2381 This->palettes[0][i].peGreen = 0xFF;
2382 This->palettes[0][i].peBlue = 0xFF;
2383 This->palettes[0][i].peFlags = 0xFF;
2385 This->currentPalette = 0;
2387 /* Initialize the texture unit mapping to a 1:1 mapping */
2388 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2389 if (state < GL_LIMITS(fragment_samplers)) {
2390 This->texUnitMap[state] = state;
2391 This->rev_tex_unit_map[state] = state;
2393 This->texUnitMap[state] = -1;
2394 This->rev_tex_unit_map[state] = -1;
2398 /* Setup the implicit swapchain */
2399 TRACE("Creating implicit swapchain\n");
2400 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2401 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2404 WARN("Failed to create implicit swapchain\n");
2408 This->NumberOfSwapChains = 1;
2409 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2410 if(!This->swapchains) {
2411 ERR("Out of memory!\n");
2414 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2416 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2417 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2418 This->render_targets[0] = swapchain->backBuffer[0];
2419 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2422 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2423 This->render_targets[0] = swapchain->frontBuffer;
2424 This->lastActiveRenderTarget = swapchain->frontBuffer;
2426 IWineD3DSurface_AddRef(This->render_targets[0]);
2427 This->activeContext = swapchain->context[0];
2428 This->lastThread = GetCurrentThreadId();
2430 /* Depth Stencil support */
2431 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2432 if (NULL != This->stencilBufferTarget) {
2433 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2436 hr = This->shader_backend->shader_alloc_private(iface);
2438 TRACE("Shader private data couldn't be allocated\n");
2441 hr = This->frag_pipe->alloc_private(iface);
2443 TRACE("Fragment pipeline private data couldn't be allocated\n");
2446 hr = This->blitter->alloc_private(iface);
2448 TRACE("Blitter private data couldn't be allocated\n");
2452 /* Set up some starting GL setup */
2454 /* Setup all the devices defaults */
2455 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2456 create_dummy_textures(This);
2460 /* Initialize the current view state */
2461 This->view_ident = 1;
2462 This->contexts[0]->last_was_rhw = 0;
2463 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2464 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2466 switch(wined3d_settings.offscreen_rendering_mode) {
2469 This->offscreenBuffer = GL_BACK;
2472 case ORM_BACKBUFFER:
2474 if(This->activeContext->aux_buffers > 0) {
2475 TRACE("Using auxilliary buffer for offscreen rendering\n");
2476 This->offscreenBuffer = GL_AUX0;
2478 TRACE("Using back buffer for offscreen rendering\n");
2479 This->offscreenBuffer = GL_BACK;
2484 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2487 /* Clear the screen */
2488 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2489 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2492 This->d3d_initialized = TRUE;
2494 if(wined3d_settings.logo) {
2495 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2497 This->highest_dirty_ps_const = 0;
2498 This->highest_dirty_vs_const = 0;
2502 HeapFree(GetProcessHeap(), 0, This->render_targets);
2503 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2504 HeapFree(GetProcessHeap(), 0, This->swapchains);
2505 This->NumberOfSwapChains = 0;
2506 if(This->palettes) {
2507 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2508 HeapFree(GetProcessHeap(), 0, This->palettes);
2510 This->NumberOfPalettes = 0;
2512 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2514 if(This->stateBlock) {
2515 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2516 This->stateBlock = NULL;
2518 if (This->blit_priv) {
2519 This->blitter->free_private(iface);
2521 if (This->fragment_priv) {
2522 This->frag_pipe->free_private(iface);
2524 if (This->shader_priv) {
2525 This->shader_backend->shader_free_private(iface);
2530 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2531 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2534 IWineD3DSwapChainImpl *swapchain = NULL;
2537 /* Setup the implicit swapchain */
2538 TRACE("Creating implicit swapchain\n");
2539 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2540 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2543 WARN("Failed to create implicit swapchain\n");
2547 This->NumberOfSwapChains = 1;
2548 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2549 if(!This->swapchains) {
2550 ERR("Out of memory!\n");
2553 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2557 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2561 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2563 IWineD3DResource_UnLoad(resource);
2564 IWineD3DResource_Release(resource);
2568 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2572 TRACE("(%p)\n", This);
2574 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2576 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2577 * it was created. Thus make sure a context is active for the glDelete* calls
2579 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2581 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2583 /* Unload resources */
2584 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2586 TRACE("Deleting high order patches\n");
2587 for(i = 0; i < PATCHMAP_SIZE; i++) {
2588 struct list *e1, *e2;
2589 struct WineD3DRectPatch *patch;
2590 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2591 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2592 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2596 /* Delete the palette conversion shader if it is around */
2597 if(This->paletteConversionShader) {
2599 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2601 This->paletteConversionShader = 0;
2604 /* Delete the pbuffer context if there is any */
2605 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2607 /* Delete the mouse cursor texture */
2608 if(This->cursorTexture) {
2610 glDeleteTextures(1, &This->cursorTexture);
2612 This->cursorTexture = 0;
2615 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2616 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2618 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2619 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2622 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2623 * private data, it might contain opengl pointers
2625 if(This->depth_blt_texture) {
2626 glDeleteTextures(1, &This->depth_blt_texture);
2627 This->depth_blt_texture = 0;
2629 if (This->depth_blt_rb) {
2630 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2631 This->depth_blt_rb = 0;
2632 This->depth_blt_rb_w = 0;
2633 This->depth_blt_rb_h = 0;
2636 /* Release the update stateblock */
2637 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2638 if(This->updateStateBlock != This->stateBlock)
2639 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2641 This->updateStateBlock = NULL;
2643 { /* because were not doing proper internal refcounts releasing the primary state block
2644 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2645 to set this->stateBlock = NULL; first */
2646 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2647 This->stateBlock = NULL;
2649 /* Release the stateblock */
2650 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2651 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2655 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2656 This->blitter->free_private(iface);
2657 This->frag_pipe->free_private(iface);
2658 This->shader_backend->shader_free_private(iface);
2660 /* Release the buffers (with sanity checks)*/
2661 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2662 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2663 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2664 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2666 This->stencilBufferTarget = NULL;
2668 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2669 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2670 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2672 TRACE("Setting rendertarget to NULL\n");
2673 This->render_targets[0] = NULL;
2675 if (This->auto_depth_stencil_buffer) {
2676 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2677 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2679 This->auto_depth_stencil_buffer = NULL;
2682 for(i=0; i < This->NumberOfSwapChains; i++) {
2683 TRACE("Releasing the implicit swapchain %d\n", i);
2684 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2685 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2689 HeapFree(GetProcessHeap(), 0, This->swapchains);
2690 This->swapchains = NULL;
2691 This->NumberOfSwapChains = 0;
2693 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2694 HeapFree(GetProcessHeap(), 0, This->palettes);
2695 This->palettes = NULL;
2696 This->NumberOfPalettes = 0;
2698 HeapFree(GetProcessHeap(), 0, This->render_targets);
2699 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2700 This->render_targets = NULL;
2701 This->draw_buffers = NULL;
2703 This->d3d_initialized = FALSE;
2707 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2711 for(i=0; i < This->NumberOfSwapChains; i++) {
2712 TRACE("Releasing the implicit swapchain %d\n", i);
2713 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2714 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2718 HeapFree(GetProcessHeap(), 0, This->swapchains);
2719 This->swapchains = NULL;
2720 This->NumberOfSwapChains = 0;
2724 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2725 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2726 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2728 * There is no way to deactivate thread safety once it is enabled.
2730 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2733 /*For now just store the flag(needed in case of ddraw) */
2734 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2739 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2740 const WINED3DDISPLAYMODE* pMode) {
2742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2744 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2747 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2749 /* Resize the screen even without a window:
2750 * The app could have unset it with SetCooperativeLevel, but not called
2751 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2752 * but we don't have any hwnd
2755 memset(&devmode, 0, sizeof(devmode));
2756 devmode.dmSize = sizeof(devmode);
2757 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2758 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2759 devmode.dmPelsWidth = pMode->Width;
2760 devmode.dmPelsHeight = pMode->Height;
2762 devmode.dmDisplayFrequency = pMode->RefreshRate;
2763 if (pMode->RefreshRate != 0) {
2764 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2767 /* Only change the mode if necessary */
2768 if( (This->ddraw_width == pMode->Width) &&
2769 (This->ddraw_height == pMode->Height) &&
2770 (This->ddraw_format == pMode->Format) &&
2771 (pMode->RefreshRate == 0) ) {
2775 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2776 if (ret != DISP_CHANGE_SUCCESSFUL) {
2777 if(devmode.dmDisplayFrequency != 0) {
2778 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2779 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2780 devmode.dmDisplayFrequency = 0;
2781 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2783 if(ret != DISP_CHANGE_SUCCESSFUL) {
2784 return WINED3DERR_NOTAVAILABLE;
2788 /* Store the new values */
2789 This->ddraw_width = pMode->Width;
2790 This->ddraw_height = pMode->Height;
2791 This->ddraw_format = pMode->Format;
2793 /* And finally clip mouse to our screen */
2794 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2795 ClipCursor(&clip_rc);
2800 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2802 *ppD3D= This->wineD3D;
2803 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2804 IWineD3D_AddRef(*ppD3D);
2808 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2811 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2812 (This->adapter->TextureRam/(1024*1024)),
2813 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2814 /* return simulated texture memory left */
2815 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2819 * Get / Set Stream Source
2821 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2822 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2825 IWineD3DBuffer *oldSrc;
2827 if (StreamNumber >= MAX_STREAMS) {
2828 WARN("Stream out of range %d\n", StreamNumber);
2829 return WINED3DERR_INVALIDCALL;
2830 } else if(OffsetInBytes & 0x3) {
2831 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2832 return WINED3DERR_INVALIDCALL;
2835 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2836 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2838 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2840 if(oldSrc == pStreamData &&
2841 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2842 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2843 TRACE("Application is setting the old values over, nothing to do\n");
2847 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2849 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2850 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2853 /* Handle recording of state blocks */
2854 if (This->isRecordingState) {
2855 TRACE("Recording... not performing anything\n");
2856 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2857 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2861 if (pStreamData != NULL) {
2862 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2863 IWineD3DBuffer_AddRef(pStreamData);
2865 if (oldSrc != NULL) {
2866 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2867 IWineD3DBuffer_Release(oldSrc);
2870 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2875 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2876 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2880 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2881 This->stateBlock->streamSource[StreamNumber],
2882 This->stateBlock->streamOffset[StreamNumber],
2883 This->stateBlock->streamStride[StreamNumber]);
2885 if (StreamNumber >= MAX_STREAMS) {
2886 WARN("Stream out of range %d\n", StreamNumber);
2887 return WINED3DERR_INVALIDCALL;
2889 *pStream = This->stateBlock->streamSource[StreamNumber];
2890 *pStride = This->stateBlock->streamStride[StreamNumber];
2892 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2895 if (*pStream != NULL) {
2896 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2901 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2903 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2904 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2906 /* Verify input at least in d3d9 this is invalid*/
2907 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2908 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2909 return WINED3DERR_INVALIDCALL;
2911 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2912 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2913 return WINED3DERR_INVALIDCALL;
2916 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2917 return WINED3DERR_INVALIDCALL;
2920 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2921 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2923 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2924 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2926 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2927 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2928 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2934 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2937 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2938 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2940 TRACE("(%p) : returning %d\n", This, *Divider);
2946 * Get / Set & Multiply Transform
2948 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2951 /* Most of this routine, comments included copied from ddraw tree initially: */
2952 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2954 /* Handle recording of state blocks */
2955 if (This->isRecordingState) {
2956 TRACE("Recording... not performing anything\n");
2957 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2958 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2963 * If the new matrix is the same as the current one,
2964 * we cut off any further processing. this seems to be a reasonable
2965 * optimization because as was noticed, some apps (warcraft3 for example)
2966 * tend towards setting the same matrix repeatedly for some reason.
2968 * From here on we assume that the new matrix is different, wherever it matters.
2970 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2971 TRACE("The app is setting the same matrix over again\n");
2974 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2978 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2979 where ViewMat = Camera space, WorldMat = world space.
2981 In OpenGL, camera and world space is combined into GL_MODELVIEW
2982 matrix. The Projection matrix stay projection matrix.
2985 /* Capture the times we can just ignore the change for now */
2986 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2987 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2988 /* Handled by the state manager */
2991 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2995 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2997 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2998 *pMatrix = This->stateBlock->transforms[State];
3002 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
3003 const WINED3DMATRIX *mat = NULL;
3006 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
3007 * below means it will be recorded in a state block change, but it
3008 * works regardless where it is recorded.
3009 * If this is found to be wrong, change to StateBlock.
3011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3012 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
3014 if (State <= HIGHEST_TRANSFORMSTATE)
3016 mat = &This->updateStateBlock->transforms[State];
3018 FIXME("Unhandled transform state!!\n");
3021 multiply_matrix(&temp, mat, pMatrix);
3023 /* Apply change via set transform - will reapply to eg. lights this way */
3024 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
3030 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
3031 you can reference any indexes you want as long as that number max are enabled at any
3032 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
3033 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
3034 but when recording, just build a chain pretty much of commands to be replayed. */
3036 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
3038 PLIGHTINFOEL *object = NULL;
3039 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3043 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
3045 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
3049 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
3050 return WINED3DERR_INVALIDCALL;
3053 switch(pLight->Type) {
3054 case WINED3DLIGHT_POINT:
3055 case WINED3DLIGHT_SPOT:
3056 case WINED3DLIGHT_PARALLELPOINT:
3057 case WINED3DLIGHT_GLSPOT:
3058 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
3061 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
3062 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
3063 return WINED3DERR_INVALIDCALL;
3067 case WINED3DLIGHT_DIRECTIONAL:
3068 /* Ignores attenuation */
3072 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
3073 return WINED3DERR_INVALIDCALL;
3076 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3077 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3078 if(object->OriginalIndex == Index) break;
3083 TRACE("Adding new light\n");
3084 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
3086 ERR("Out of memory error when allocating a light\n");
3087 return E_OUTOFMEMORY;
3089 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
3090 object->glIndex = -1;
3091 object->OriginalIndex = Index;
3092 object->changed = TRUE;
3095 /* Initialize the object */
3096 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,
3097 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
3098 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
3099 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
3100 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
3101 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
3102 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
3104 /* Save away the information */
3105 object->OriginalParms = *pLight;
3107 switch (pLight->Type) {
3108 case WINED3DLIGHT_POINT:
3110 object->lightPosn[0] = pLight->Position.x;
3111 object->lightPosn[1] = pLight->Position.y;
3112 object->lightPosn[2] = pLight->Position.z;
3113 object->lightPosn[3] = 1.0f;
3114 object->cutoff = 180.0f;
3118 case WINED3DLIGHT_DIRECTIONAL:
3120 object->lightPosn[0] = -pLight->Direction.x;
3121 object->lightPosn[1] = -pLight->Direction.y;
3122 object->lightPosn[2] = -pLight->Direction.z;
3123 object->lightPosn[3] = 0.0;
3124 object->exponent = 0.0f;
3125 object->cutoff = 180.0f;
3128 case WINED3DLIGHT_SPOT:
3130 object->lightPosn[0] = pLight->Position.x;
3131 object->lightPosn[1] = pLight->Position.y;
3132 object->lightPosn[2] = pLight->Position.z;
3133 object->lightPosn[3] = 1.0;
3136 object->lightDirn[0] = pLight->Direction.x;
3137 object->lightDirn[1] = pLight->Direction.y;
3138 object->lightDirn[2] = pLight->Direction.z;
3139 object->lightDirn[3] = 1.0;
3142 * opengl-ish and d3d-ish spot lights use too different models for the
3143 * light "intensity" as a function of the angle towards the main light direction,
3144 * so we only can approximate very roughly.
3145 * however spot lights are rather rarely used in games (if ever used at all).
3146 * furthermore if still used, probably nobody pays attention to such details.
3148 if (pLight->Falloff == 0) {
3149 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3150 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3151 * will always be 1.0 for both of them, and we don't have to care for the
3152 * rest of the rather complex calculation
3154 object->exponent = 0;
3156 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3157 if (rho < 0.0001) rho = 0.0001f;
3158 object->exponent = -0.3/log(cos(rho/2));
3160 if (object->exponent > 128.0) {
3161 object->exponent = 128.0;
3163 object->cutoff = pLight->Phi*90/M_PI;
3169 FIXME("Unrecognized light type %d\n", pLight->Type);
3172 /* Update the live definitions if the light is currently assigned a glIndex */
3173 if (object->glIndex != -1 && !This->isRecordingState) {
3174 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3179 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3180 PLIGHTINFOEL *lightInfo = NULL;
3181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3182 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3184 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3186 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3187 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3188 if(lightInfo->OriginalIndex == Index) break;
3192 if (lightInfo == NULL) {
3193 TRACE("Light information requested but light not defined\n");
3194 return WINED3DERR_INVALIDCALL;
3197 *pLight = lightInfo->OriginalParms;
3202 * Get / Set Light Enable
3203 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3205 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3206 PLIGHTINFOEL *lightInfo = NULL;
3207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3208 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3210 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3212 /* Tests show true = 128...not clear why */
3213 Enable = Enable? 128: 0;
3215 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3216 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3217 if(lightInfo->OriginalIndex == Index) break;
3220 TRACE("Found light: %p\n", lightInfo);
3222 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3223 if (lightInfo == NULL) {
3225 TRACE("Light enabled requested but light not defined, so defining one!\n");
3226 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3228 /* Search for it again! Should be fairly quick as near head of list */
3229 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3230 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3231 if(lightInfo->OriginalIndex == Index) break;
3234 if (lightInfo == NULL) {
3235 FIXME("Adding default lights has failed dismally\n");
3236 return WINED3DERR_INVALIDCALL;
3240 lightInfo->enabledChanged = TRUE;
3242 if(lightInfo->glIndex != -1) {
3243 if(!This->isRecordingState) {
3244 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3247 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3248 lightInfo->glIndex = -1;
3250 TRACE("Light already disabled, nothing to do\n");
3252 lightInfo->enabled = FALSE;
3254 lightInfo->enabled = TRUE;
3255 if (lightInfo->glIndex != -1) {
3257 TRACE("Nothing to do as light was enabled\n");
3260 /* Find a free gl light */
3261 for(i = 0; i < This->maxConcurrentLights; i++) {
3262 if(This->updateStateBlock->activeLights[i] == NULL) {
3263 This->updateStateBlock->activeLights[i] = lightInfo;
3264 lightInfo->glIndex = i;
3268 if(lightInfo->glIndex == -1) {
3269 /* Our tests show that Windows returns D3D_OK in this situation, even with
3270 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3271 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3272 * as well for those lights.
3274 * TODO: Test how this affects rendering
3276 WARN("Too many concurrently active lights\n");
3280 /* i == lightInfo->glIndex */
3281 if(!This->isRecordingState) {
3282 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3290 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3292 PLIGHTINFOEL *lightInfo = NULL;
3293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3295 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3296 TRACE("(%p) : for idx(%d)\n", This, Index);
3298 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3299 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3300 if(lightInfo->OriginalIndex == Index) break;
3304 if (lightInfo == NULL) {
3305 TRACE("Light enabled state requested but light not defined\n");
3306 return WINED3DERR_INVALIDCALL;
3308 /* true is 128 according to SetLightEnable */
3309 *pEnable = lightInfo->enabled ? 128 : 0;
3314 * Get / Set Clip Planes
3316 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3318 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3320 /* Validate Index */
3321 if (Index >= GL_LIMITS(clipplanes)) {
3322 TRACE("Application has requested clipplane this device doesn't support\n");
3323 return WINED3DERR_INVALIDCALL;
3326 This->updateStateBlock->changed.clipplane |= 1 << Index;
3328 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3329 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3330 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3331 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3332 TRACE("Application is setting old values over, nothing to do\n");
3336 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3337 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3338 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3339 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3341 /* Handle recording of state blocks */
3342 if (This->isRecordingState) {
3343 TRACE("Recording... not performing anything\n");
3347 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3352 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3353 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3354 TRACE("(%p) : for idx %d\n", This, Index);
3356 /* Validate Index */
3357 if (Index >= GL_LIMITS(clipplanes)) {
3358 TRACE("Application has requested clipplane this device doesn't support\n");
3359 return WINED3DERR_INVALIDCALL;
3362 pPlane[0] = This->stateBlock->clipplane[Index][0];
3363 pPlane[1] = This->stateBlock->clipplane[Index][1];
3364 pPlane[2] = This->stateBlock->clipplane[Index][2];
3365 pPlane[3] = This->stateBlock->clipplane[Index][3];
3370 * Get / Set Clip Plane Status
3371 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3373 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3375 FIXME("(%p) : stub\n", This);
3376 if (NULL == pClipStatus) {
3377 return WINED3DERR_INVALIDCALL;
3379 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3380 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3384 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3386 FIXME("(%p) : stub\n", This);
3387 if (NULL == pClipStatus) {
3388 return WINED3DERR_INVALIDCALL;
3390 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3391 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3396 * Get / Set Material
3398 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3401 This->updateStateBlock->changed.material = TRUE;
3402 This->updateStateBlock->material = *pMaterial;
3404 /* Handle recording of state blocks */
3405 if (This->isRecordingState) {
3406 TRACE("Recording... not performing anything\n");
3410 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3414 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3416 *pMaterial = This->updateStateBlock->material;
3417 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3418 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3419 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3420 pMaterial->Ambient.b, pMaterial->Ambient.a);
3421 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3422 pMaterial->Specular.b, pMaterial->Specular.a);
3423 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3424 pMaterial->Emissive.b, pMaterial->Emissive.a);
3425 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3433 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3435 IWineD3DIndexBuffer *oldIdxs;
3437 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3438 oldIdxs = This->updateStateBlock->pIndexData;
3440 This->updateStateBlock->changed.indices = TRUE;
3441 This->updateStateBlock->pIndexData = pIndexData;
3443 /* Handle recording of state blocks */
3444 if (This->isRecordingState) {
3445 TRACE("Recording... not performing anything\n");
3446 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3447 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3451 if(oldIdxs != pIndexData) {
3452 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3453 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3454 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3459 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3462 *ppIndexData = This->stateBlock->pIndexData;
3464 /* up ref count on ppindexdata */
3466 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3467 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3469 TRACE("(%p) No index data set\n", This);
3471 TRACE("Returning %p\n", *ppIndexData);
3476 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3477 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3479 TRACE("(%p)->(%d)\n", This, BaseIndex);
3481 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3482 TRACE("Application is setting the old value over, nothing to do\n");
3486 This->updateStateBlock->baseVertexIndex = BaseIndex;
3488 if (This->isRecordingState) {
3489 TRACE("Recording... not performing anything\n");
3492 /* The base vertex index affects the stream sources */
3493 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3497 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3499 TRACE("(%p) : base_index %p\n", This, base_index);
3501 *base_index = This->stateBlock->baseVertexIndex;
3503 TRACE("Returning %u\n", *base_index);
3509 * Get / Set Viewports
3511 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3514 TRACE("(%p)\n", This);
3515 This->updateStateBlock->changed.viewport = TRUE;
3516 This->updateStateBlock->viewport = *pViewport;
3518 /* Handle recording of state blocks */
3519 if (This->isRecordingState) {
3520 TRACE("Recording... not performing anything\n");
3524 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3525 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3527 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3532 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3534 TRACE("(%p)\n", This);
3535 *pViewport = This->stateBlock->viewport;
3540 * Get / Set Render States
3541 * TODO: Verify against dx9 definitions
3543 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3546 DWORD oldValue = This->stateBlock->renderState[State];
3548 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3550 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3551 This->updateStateBlock->renderState[State] = Value;
3553 /* Handle recording of state blocks */
3554 if (This->isRecordingState) {
3555 TRACE("Recording... not performing anything\n");
3559 /* Compared here and not before the assignment to allow proper stateblock recording */
3560 if(Value == oldValue) {
3561 TRACE("Application is setting the old value over, nothing to do\n");
3563 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3569 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3571 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3572 *pValue = This->stateBlock->renderState[State];
3577 * Get / Set Sampler States
3578 * TODO: Verify against dx9 definitions
3581 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3585 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3586 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3588 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3589 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3592 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3593 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3594 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3597 * SetSampler is designed to allow for more than the standard up to 8 textures
3598 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3599 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3601 * http://developer.nvidia.com/object/General_FAQ.html#t6
3603 * There are two new settings for GForce
3605 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3606 * and the texture one:
3607 * GL_MAX_TEXTURE_COORDS_ARB.
3608 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3611 oldValue = This->stateBlock->samplerState[Sampler][Type];
3612 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3613 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3615 /* Handle recording of state blocks */
3616 if (This->isRecordingState) {
3617 TRACE("Recording... not performing anything\n");
3621 if(oldValue == Value) {
3622 TRACE("Application is setting the old value over, nothing to do\n");
3626 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3631 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3634 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3635 This, Sampler, debug_d3dsamplerstate(Type), Type);
3637 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3638 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3641 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3642 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3643 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3645 *Value = This->stateBlock->samplerState[Sampler][Type];
3646 TRACE("(%p) : Returning %#x\n", This, *Value);
3651 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3654 This->updateStateBlock->changed.scissorRect = TRUE;
3655 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3656 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3659 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3661 if(This->isRecordingState) {
3662 TRACE("Recording... not performing anything\n");
3666 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3671 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3674 *pRect = This->updateStateBlock->scissorRect;
3675 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3679 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3681 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3683 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3685 This->updateStateBlock->vertexDecl = pDecl;
3686 This->updateStateBlock->changed.vertexDecl = TRUE;
3688 if (This->isRecordingState) {
3689 TRACE("Recording... not performing anything\n");
3691 } else if(pDecl == oldDecl) {
3692 /* Checked after the assignment to allow proper stateblock recording */
3693 TRACE("Application is setting the old declaration over, nothing to do\n");
3697 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3701 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3704 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3706 *ppDecl = This->stateBlock->vertexDecl;
3707 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3711 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3713 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3715 This->updateStateBlock->vertexShader = pShader;
3716 This->updateStateBlock->changed.vertexShader = TRUE;
3718 if (This->isRecordingState) {
3719 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3720 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3721 TRACE("Recording... not performing anything\n");
3723 } else if(oldShader == pShader) {
3724 /* Checked here to allow proper stateblock recording */
3725 TRACE("App is setting the old shader over, nothing to do\n");
3729 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3730 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3731 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3733 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3738 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3741 if (NULL == ppShader) {
3742 return WINED3DERR_INVALIDCALL;
3744 *ppShader = This->stateBlock->vertexShader;
3745 if( NULL != *ppShader)
3746 IWineD3DVertexShader_AddRef(*ppShader);
3748 TRACE("(%p) : returning %p\n", This, *ppShader);
3752 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3753 IWineD3DDevice *iface,
3755 CONST BOOL *srcData,
3758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3759 int i, cnt = min(count, MAX_CONST_B - start);
3761 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3762 iface, srcData, start, count);
3764 if (srcData == NULL || cnt < 0)
3765 return WINED3DERR_INVALIDCALL;
3767 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3768 for (i = 0; i < cnt; i++)
3769 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3771 for (i = start; i < cnt + start; ++i) {
3772 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3775 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3780 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3781 IWineD3DDevice *iface,
3786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3787 int cnt = min(count, MAX_CONST_B - start);
3789 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3790 iface, dstData, start, count);
3792 if (dstData == NULL || cnt < 0)
3793 return WINED3DERR_INVALIDCALL;
3795 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3799 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3800 IWineD3DDevice *iface,
3805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3806 int i, cnt = min(count, MAX_CONST_I - start);
3808 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3809 iface, srcData, start, count);
3811 if (srcData == NULL || cnt < 0)
3812 return WINED3DERR_INVALIDCALL;
3814 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3815 for (i = 0; i < cnt; i++)
3816 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3817 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3819 for (i = start; i < cnt + start; ++i) {
3820 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3823 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3828 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3829 IWineD3DDevice *iface,
3834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3835 int cnt = min(count, MAX_CONST_I - start);
3837 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3838 iface, dstData, start, count);
3840 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3841 return WINED3DERR_INVALIDCALL;
3843 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3847 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3848 IWineD3DDevice *iface,
3850 CONST float *srcData,
3853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3856 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3857 iface, srcData, start, count);
3859 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3860 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3861 return WINED3DERR_INVALIDCALL;
3863 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3865 for (i = 0; i < count; i++)
3866 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3867 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3870 if (!This->isRecordingState)
3872 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3873 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3876 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3877 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3882 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3883 IWineD3DDevice *iface,
3888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3889 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3891 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3892 iface, dstData, start, count);
3894 if (dstData == NULL || cnt < 0)
3895 return WINED3DERR_INVALIDCALL;
3897 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3901 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3903 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3905 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3909 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3910 int i = This->rev_tex_unit_map[unit];
3911 int j = This->texUnitMap[stage];
3913 This->texUnitMap[stage] = unit;
3914 if (i != -1 && i != stage) {
3915 This->texUnitMap[i] = -1;
3918 This->rev_tex_unit_map[unit] = stage;
3919 if (j != -1 && j != unit) {
3920 This->rev_tex_unit_map[j] = -1;
3924 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3927 This->fixed_function_usage_map = 0;
3928 for (i = 0; i < MAX_TEXTURES; ++i) {
3929 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3930 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3931 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3932 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3933 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3934 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3935 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3936 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3938 if (color_op == WINED3DTOP_DISABLE) {
3939 /* Not used, and disable higher stages */
3943 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3944 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3945 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3946 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3947 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3948 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3949 This->fixed_function_usage_map |= (1 << i);
3952 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3953 This->fixed_function_usage_map |= (1 << (i + 1));
3958 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3962 device_update_fixed_function_usage_map(This);
3963 ffu_map = This->fixed_function_usage_map;
3965 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3966 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3967 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3969 if (!(ffu_map & 1)) continue;
3971 if (This->texUnitMap[i] != i) {
3972 device_map_stage(This, i, i);
3973 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3974 markTextureStagesDirty(This, i);
3980 /* Now work out the mapping */
3982 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3984 if (!(ffu_map & 1)) continue;
3986 if (This->texUnitMap[i] != tex) {
3987 device_map_stage(This, i, tex);
3988 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3989 markTextureStagesDirty(This, i);
3996 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3997 const DWORD *sampler_tokens =
3998 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
4001 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
4002 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
4003 device_map_stage(This, i, i);
4004 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4005 if (i < MAX_TEXTURES) {
4006 markTextureStagesDirty(This, i);
4012 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
4013 const DWORD *vshader_sampler_tokens, int unit)
4015 int current_mapping = This->rev_tex_unit_map[unit];
4017 if (current_mapping == -1) {
4018 /* Not currently used */
4022 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
4023 /* Used by a fragment sampler */
4025 if (!pshader_sampler_tokens) {
4026 /* No pixel shader, check fixed function */
4027 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
4030 /* Pixel shader, check the shader's sampler map */
4031 return !pshader_sampler_tokens[current_mapping];
4034 /* Used by a vertex sampler */
4035 return !vshader_sampler_tokens[current_mapping];
4038 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
4039 const DWORD *vshader_sampler_tokens =
4040 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
4041 const DWORD *pshader_sampler_tokens = NULL;
4042 int start = GL_LIMITS(combined_samplers) - 1;
4046 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
4048 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
4049 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
4050 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
4053 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
4054 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
4055 if (vshader_sampler_tokens[i]) {
4056 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
4058 /* Already mapped somewhere */
4062 while (start >= 0) {
4063 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
4064 device_map_stage(This, vsampler_idx, start);
4065 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
4077 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
4078 BOOL vs = use_vs(This->stateBlock);
4079 BOOL ps = use_ps(This->stateBlock);
4082 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
4083 * that would be really messy and require shader recompilation
4084 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
4085 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
4088 device_map_psamplers(This);
4090 device_map_fixed_function_samplers(This);
4094 device_map_vsamplers(This, ps);
4098 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4100 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4101 This->updateStateBlock->pixelShader = pShader;
4102 This->updateStateBlock->changed.pixelShader = TRUE;
4104 /* Handle recording of state blocks */
4105 if (This->isRecordingState) {
4106 TRACE("Recording... not performing anything\n");
4109 if (This->isRecordingState) {
4110 TRACE("Recording... not performing anything\n");
4111 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4112 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4116 if(pShader == oldShader) {
4117 TRACE("App is setting the old pixel shader over, nothing to do\n");
4121 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4122 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4124 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4125 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4130 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4133 if (NULL == ppShader) {
4134 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4135 return WINED3DERR_INVALIDCALL;
4138 *ppShader = This->stateBlock->pixelShader;
4139 if (NULL != *ppShader) {
4140 IWineD3DPixelShader_AddRef(*ppShader);
4142 TRACE("(%p) : returning %p\n", This, *ppShader);
4146 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4147 IWineD3DDevice *iface,
4149 CONST BOOL *srcData,
4152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4153 int i, cnt = min(count, MAX_CONST_B - start);
4155 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4156 iface, srcData, start, count);
4158 if (srcData == NULL || cnt < 0)
4159 return WINED3DERR_INVALIDCALL;
4161 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4162 for (i = 0; i < cnt; i++)
4163 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4165 for (i = start; i < cnt + start; ++i) {
4166 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4169 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4174 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4175 IWineD3DDevice *iface,
4180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4181 int cnt = min(count, MAX_CONST_B - start);
4183 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4184 iface, dstData, start, count);
4186 if (dstData == NULL || cnt < 0)
4187 return WINED3DERR_INVALIDCALL;
4189 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4193 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4194 IWineD3DDevice *iface,
4199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4200 int i, cnt = min(count, MAX_CONST_I - start);
4202 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4203 iface, srcData, start, count);
4205 if (srcData == NULL || cnt < 0)
4206 return WINED3DERR_INVALIDCALL;
4208 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4209 for (i = 0; i < cnt; i++)
4210 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4211 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4213 for (i = start; i < cnt + start; ++i) {
4214 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4217 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4222 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4223 IWineD3DDevice *iface,
4228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4229 int cnt = min(count, MAX_CONST_I - start);
4231 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4232 iface, dstData, start, count);
4234 if (dstData == NULL || cnt < 0)
4235 return WINED3DERR_INVALIDCALL;
4237 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4241 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4242 IWineD3DDevice *iface,
4244 CONST float *srcData,
4247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4250 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4251 iface, srcData, start, count);
4253 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4254 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4255 return WINED3DERR_INVALIDCALL;
4257 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4259 for (i = 0; i < count; i++)
4260 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4261 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4264 if (!This->isRecordingState)
4266 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4267 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4270 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4271 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4276 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4277 IWineD3DDevice *iface,
4282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4283 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4285 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4286 iface, dstData, start, count);
4288 if (dstData == NULL || cnt < 0)
4289 return WINED3DERR_INVALIDCALL;
4291 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4295 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4296 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4297 const WineDirect3DVertexStridedData *lpStrideData, struct wined3d_buffer *dest, DWORD dwFlags)
4299 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4301 DWORD DestFVF = dest->fvf;
4303 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4307 if (lpStrideData->u.s.normal.lpData) {
4308 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4311 if (lpStrideData->u.s.position.lpData == NULL) {
4312 ERR("Source has no position mask\n");
4313 return WINED3DERR_INVALIDCALL;
4316 /* We might access VBOs from this code, so hold the lock */
4319 if (dest->resource.allocatedMemory == NULL) {
4320 /* This may happen if we do direct locking into a vbo. Unlikely,
4321 * but theoretically possible(ddraw processvertices test)
4323 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4324 if(!dest->resource.allocatedMemory) {
4326 ERR("Out of memory\n");
4327 return E_OUTOFMEMORY;
4329 if (dest->buffer_object)
4332 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4333 checkGLcall("glBindBufferARB");
4334 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4336 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4338 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4339 checkGLcall("glUnmapBufferARB");
4343 /* Get a pointer into the destination vbo(create one if none exists) and
4344 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4346 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4348 dest->flags |= WINED3D_BUFFER_CREATEBO;
4349 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4352 if (dest->buffer_object)
4354 unsigned char extrabytes = 0;
4355 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4356 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4357 * this may write 4 extra bytes beyond the area that should be written
4359 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4360 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4361 if(!dest_conv_addr) {
4362 ERR("Out of memory\n");
4363 /* Continue without storing converted vertices */
4365 dest_conv = dest_conv_addr;
4369 * a) WINED3DRS_CLIPPING is enabled
4370 * b) WINED3DVOP_CLIP is passed
4372 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4373 static BOOL warned = FALSE;
4375 * The clipping code is not quite correct. Some things need
4376 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4377 * so disable clipping for now.
4378 * (The graphics in Half-Life are broken, and my processvertices
4379 * test crashes with IDirect3DDevice3)
4385 FIXME("Clipping is broken and disabled for now\n");
4387 } else doClip = FALSE;
4388 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4390 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4393 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4394 WINED3DTS_PROJECTION,
4396 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4397 WINED3DTS_WORLDMATRIX(0),
4400 TRACE("View mat:\n");
4401 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);
4402 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);
4403 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);
4404 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);
4406 TRACE("Proj mat:\n");
4407 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);
4408 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);
4409 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);
4410 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);
4412 TRACE("World mat:\n");
4413 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);
4414 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);
4415 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);
4416 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);
4418 /* Get the viewport */
4419 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4420 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4421 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4423 multiply_matrix(&mat,&view_mat,&world_mat);
4424 multiply_matrix(&mat,&proj_mat,&mat);
4426 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4428 for (i = 0; i < dwCount; i+= 1) {
4429 unsigned int tex_index;
4431 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4432 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4433 /* The position first */
4435 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4437 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4439 /* Multiplication with world, view and projection matrix */
4440 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);
4441 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);
4442 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);
4443 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);
4445 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4447 /* WARNING: The following things are taken from d3d7 and were not yet checked
4448 * against d3d8 or d3d9!
4451 /* Clipping conditions: From msdn
4453 * A vertex is clipped if it does not match the following requirements
4457 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4459 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4460 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4465 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4466 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4469 /* "Normal" viewport transformation (not clipped)
4470 * 1) The values are divided by rhw
4471 * 2) The y axis is negative, so multiply it with -1
4472 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4473 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4474 * 4) Multiply x with Width/2 and add Width/2
4475 * 5) The same for the height
4476 * 6) Add the viewpoint X and Y to the 2D coordinates and
4477 * The minimum Z value to z
4478 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4480 * Well, basically it's simply a linear transformation into viewport
4492 z *= vp.MaxZ - vp.MinZ;
4494 x += vp.Width / 2 + vp.X;
4495 y += vp.Height / 2 + vp.Y;
4500 /* That vertex got clipped
4501 * Contrary to OpenGL it is not dropped completely, it just
4502 * undergoes a different calculation.
4504 TRACE("Vertex got clipped\n");
4511 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4512 * outside of the main vertex buffer memory. That needs some more
4517 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4520 ( (float *) dest_ptr)[0] = x;
4521 ( (float *) dest_ptr)[1] = y;
4522 ( (float *) dest_ptr)[2] = z;
4523 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4525 dest_ptr += 3 * sizeof(float);
4527 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4528 dest_ptr += sizeof(float);
4533 ( (float *) dest_conv)[0] = x * w;
4534 ( (float *) dest_conv)[1] = y * w;
4535 ( (float *) dest_conv)[2] = z * w;
4536 ( (float *) dest_conv)[3] = w;
4538 dest_conv += 3 * sizeof(float);
4540 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4541 dest_conv += sizeof(float);
4545 if (DestFVF & WINED3DFVF_PSIZE) {
4546 dest_ptr += sizeof(DWORD);
4547 if(dest_conv) dest_conv += sizeof(DWORD);
4549 if (DestFVF & WINED3DFVF_NORMAL) {
4550 const float *normal =
4551 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4552 /* AFAIK this should go into the lighting information */
4553 FIXME("Didn't expect the destination to have a normal\n");
4554 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4556 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4560 if (DestFVF & WINED3DFVF_DIFFUSE) {
4561 const DWORD *color_d =
4562 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4564 static BOOL warned = FALSE;
4567 ERR("No diffuse color in source, but destination has one\n");
4571 *( (DWORD *) dest_ptr) = 0xffffffff;
4572 dest_ptr += sizeof(DWORD);
4575 *( (DWORD *) dest_conv) = 0xffffffff;
4576 dest_conv += sizeof(DWORD);
4580 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4582 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4583 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4584 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4585 dest_conv += sizeof(DWORD);
4590 if (DestFVF & WINED3DFVF_SPECULAR) {
4591 /* What's the color value in the feedback buffer? */
4592 const DWORD *color_s =
4593 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4595 static BOOL warned = FALSE;
4598 ERR("No specular color in source, but destination has one\n");
4602 *( (DWORD *) dest_ptr) = 0xFF000000;
4603 dest_ptr += sizeof(DWORD);
4606 *( (DWORD *) dest_conv) = 0xFF000000;
4607 dest_conv += sizeof(DWORD);
4611 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4613 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4614 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4615 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4616 dest_conv += sizeof(DWORD);
4621 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4622 const float *tex_coord =
4623 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4624 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4626 ERR("No source texture, but destination requests one\n");
4627 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4628 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4631 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4633 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4640 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4641 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4642 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4643 dwCount * get_flexible_vertex_size(DestFVF),
4645 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4646 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4653 #undef copy_and_next
4655 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4656 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags)
4658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4659 WineDirect3DVertexStridedData strided;
4660 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4661 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4664 ERR("Output vertex declaration not implemented yet\n");
4667 /* Need any context to write to the vbo. */
4668 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4670 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4671 * control the streamIsUP flag, thus restore it afterwards.
4673 This->stateBlock->streamIsUP = FALSE;
4674 memset(&strided, 0, sizeof(strided));
4675 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4676 This->stateBlock->streamIsUP = streamWasUP;
4678 if(vbo || SrcStartIndex) {
4680 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4681 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4683 * Also get the start index in, but only loop over all elements if there's something to add at all.
4685 #define FIXSRC(type) \
4686 if(strided.u.s.type.VBO) { \
4687 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4688 strided.u.s.type.VBO = 0; \
4689 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4691 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object)); \
4692 vb->buffer_object = 0; \
4695 if(strided.u.s.type.lpData) { \
4696 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4699 FIXSRC(blendWeights);
4700 FIXSRC(blendMatrixIndices);
4705 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4706 FIXSRC(texCoords[i]);
4719 return process_vertices_strided(This, DestIndex, VertexCount, &strided,
4720 (struct wined3d_buffer *)pDestBuffer, Flags);
4724 * Get / Set Texture Stage States
4725 * TODO: Verify against dx9 definitions
4727 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4729 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4731 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4733 if (Stage >= MAX_TEXTURES) {
4734 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4738 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4739 This->updateStateBlock->textureState[Stage][Type] = Value;
4741 if (This->isRecordingState) {
4742 TRACE("Recording... not performing anything\n");
4746 /* Checked after the assignments to allow proper stateblock recording */
4747 if(oldValue == Value) {
4748 TRACE("App is setting the old value over, nothing to do\n");
4752 if(Stage > This->stateBlock->lowest_disabled_stage &&
4753 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4754 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4755 * Changes in other states are important on disabled stages too
4760 if(Type == WINED3DTSS_COLOROP) {
4763 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4764 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4765 * they have to be disabled
4767 * The current stage is dirtified below.
4769 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4770 TRACE("Additionally dirtifying stage %d\n", i);
4771 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4773 This->stateBlock->lowest_disabled_stage = Stage;
4774 TRACE("New lowest disabled: %d\n", Stage);
4775 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4776 /* Previously disabled stage enabled. Stages above it may need enabling
4777 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4778 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4780 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4783 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4784 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4787 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4788 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4790 This->stateBlock->lowest_disabled_stage = i;
4791 TRACE("New lowest disabled: %d\n", i);
4795 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4800 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4802 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4803 *pValue = This->updateStateBlock->textureState[Stage][Type];
4810 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4812 IWineD3DBaseTexture *oldTexture;
4814 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4816 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4817 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4820 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4821 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4822 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4825 oldTexture = This->updateStateBlock->textures[Stage];
4827 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4828 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4830 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4831 return WINED3DERR_INVALIDCALL;
4834 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4835 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4837 This->updateStateBlock->changed.textures |= 1 << Stage;
4838 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4839 This->updateStateBlock->textures[Stage] = pTexture;
4841 /* Handle recording of state blocks */
4842 if (This->isRecordingState) {
4843 TRACE("Recording... not performing anything\n");
4847 if(oldTexture == pTexture) {
4848 TRACE("App is setting the same texture again, nothing to do\n");
4852 /** NOTE: MSDN says that setTexture increases the reference count,
4853 * and that the application must set the texture back to null (or have a leaky application),
4854 * This means we should pass the refcount up to the parent
4855 *******************************/
4856 if (NULL != This->updateStateBlock->textures[Stage]) {
4857 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4858 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4859 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4861 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4863 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4865 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4868 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4869 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4870 * so the COLOROP and ALPHAOP have to be dirtified.
4872 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4873 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4875 if(bindCount == 1) {
4876 new->baseTexture.sampler = Stage;
4878 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4882 if (NULL != oldTexture) {
4883 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4884 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4886 IWineD3DBaseTexture_Release(oldTexture);
4887 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4888 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4889 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4892 if(bindCount && old->baseTexture.sampler == Stage) {
4894 /* Have to do a search for the other sampler(s) where the texture is bound to
4895 * Shouldn't happen as long as apps bind a texture only to one stage
4897 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4898 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4899 if(This->updateStateBlock->textures[i] == oldTexture) {
4900 old->baseTexture.sampler = i;
4907 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4912 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4915 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4917 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4918 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4921 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4922 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4923 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4926 *ppTexture=This->stateBlock->textures[Stage];
4928 IWineD3DBaseTexture_AddRef(*ppTexture);
4930 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4938 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4939 IWineD3DSurface **ppBackBuffer) {
4940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4941 IWineD3DSwapChain *swapChain;
4944 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4946 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4947 if (hr == WINED3D_OK) {
4948 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4949 IWineD3DSwapChain_Release(swapChain);
4951 *ppBackBuffer = NULL;
4956 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4957 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4958 WARN("(%p) : stub, calling idirect3d for now\n", This);
4959 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4962 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4964 IWineD3DSwapChain *swapChain;
4967 if(iSwapChain > 0) {
4968 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4969 if (hr == WINED3D_OK) {
4970 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4971 IWineD3DSwapChain_Release(swapChain);
4973 FIXME("(%p) Error getting display mode\n", This);
4976 /* Don't read the real display mode,
4977 but return the stored mode instead. X11 can't change the color
4978 depth, and some apps are pretty angry if they SetDisplayMode from
4979 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4981 Also don't relay to the swapchain because with ddraw it's possible
4982 that there isn't a swapchain at all */
4983 pMode->Width = This->ddraw_width;
4984 pMode->Height = This->ddraw_height;
4985 pMode->Format = This->ddraw_format;
4986 pMode->RefreshRate = 0;
4994 * Stateblock related functions
4997 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4999 IWineD3DStateBlock *stateblock;
5002 TRACE("(%p)\n", This);
5004 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
5006 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
5007 if (FAILED(hr)) return hr;
5009 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5010 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
5011 This->isRecordingState = TRUE;
5013 TRACE("(%p) recording stateblock %p\n", This, stateblock);
5018 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5021 IWineD3DStateBlockImpl *object = This->updateStateBlock;
5023 if (!This->isRecordingState) {
5024 WARN("(%p) not recording! returning error\n", This);
5025 *ppStateBlock = NULL;
5026 return WINED3DERR_INVALIDCALL;
5029 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
5031 DWORD map = object->changed.renderState[i];
5032 for (j = 0; map; map >>= 1, ++j)
5034 if (!(map & 1)) continue;
5036 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
5040 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
5042 DWORD map = object->changed.transform[i];
5043 for (j = 0; map; map >>= 1, ++j)
5045 if (!(map & 1)) continue;
5047 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
5050 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
5051 if(object->changed.vertexShaderConstantsF[i]) {
5052 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
5053 object->num_contained_vs_consts_f++;
5056 for(i = 0; i < MAX_CONST_I; i++) {
5057 if (object->changed.vertexShaderConstantsI & (1 << i))
5059 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
5060 object->num_contained_vs_consts_i++;
5063 for(i = 0; i < MAX_CONST_B; i++) {
5064 if (object->changed.vertexShaderConstantsB & (1 << i))
5066 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
5067 object->num_contained_vs_consts_b++;
5070 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
5072 if (object->changed.pixelShaderConstantsF[i])
5074 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
5075 ++object->num_contained_ps_consts_f;
5078 for(i = 0; i < MAX_CONST_I; i++) {
5079 if (object->changed.pixelShaderConstantsI & (1 << i))
5081 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
5082 object->num_contained_ps_consts_i++;
5085 for(i = 0; i < MAX_CONST_B; i++) {
5086 if (object->changed.pixelShaderConstantsB & (1 << i))
5088 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
5089 object->num_contained_ps_consts_b++;
5092 for(i = 0; i < MAX_TEXTURES; i++) {
5093 DWORD map = object->changed.textureState[i];
5095 for(j = 0; map; map >>= 1, ++j)
5097 if (!(map & 1)) continue;
5099 object->contained_tss_states[object->num_contained_tss_states].stage = i;
5100 object->contained_tss_states[object->num_contained_tss_states].state = j;
5101 ++object->num_contained_tss_states;
5104 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
5105 DWORD map = object->changed.samplerState[i];
5107 for (j = 0; map; map >>= 1, ++j)
5109 if (!(map & 1)) continue;
5111 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
5112 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
5113 ++object->num_contained_sampler_states;
5117 *ppStateBlock = (IWineD3DStateBlock*) object;
5118 This->isRecordingState = FALSE;
5119 This->updateStateBlock = This->stateBlock;
5120 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5121 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5122 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5127 * Scene related functions
5129 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5130 /* At the moment we have no need for any functionality at the beginning
5132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5133 TRACE("(%p)\n", This);
5136 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
5137 return WINED3DERR_INVALIDCALL;
5139 This->inScene = TRUE;
5143 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5145 TRACE("(%p)\n", This);
5147 if(!This->inScene) {
5148 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
5149 return WINED3DERR_INVALIDCALL;
5152 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5153 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5155 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5159 This->inScene = FALSE;
5163 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5164 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5165 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5167 IWineD3DSwapChain *swapChain = NULL;
5169 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5171 TRACE("(%p) Presenting the frame\n", This);
5173 for(i = 0 ; i < swapchains ; i ++) {
5175 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5176 TRACE("presentinng chain %d, %p\n", i, swapChain);
5177 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5178 IWineD3DSwapChain_Release(swapChain);
5184 /* Not called from the VTable (internal subroutine) */
5185 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5186 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5187 float Z, DWORD Stencil) {
5188 GLbitfield glMask = 0;
5190 WINED3DRECT curRect;
5192 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5193 UINT drawable_width, drawable_height;
5194 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5195 IWineD3DSwapChainImpl *swapchain = NULL;
5197 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5198 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5199 * for the cleared parts, and the untouched parts.
5201 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5202 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5203 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5204 * checking all this if the dest surface is in the drawable anyway.
5206 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5208 if(vp->X != 0 || vp->Y != 0 ||
5209 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5210 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5213 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5214 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5215 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5216 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5217 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5220 if(Count > 0 && pRects && (
5221 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5222 pRects[0].x2 < target->currentDesc.Width ||
5223 pRects[0].y2 < target->currentDesc.Height)) {
5224 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5231 target->get_drawable_size(target, &drawable_width, &drawable_height);
5233 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5236 /* Only set the values up once, as they are not changing */
5237 if (Flags & WINED3DCLEAR_STENCIL) {
5238 glClearStencil(Stencil);
5239 checkGLcall("glClearStencil");
5240 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5241 glStencilMask(0xFFFFFFFF);
5244 if (Flags & WINED3DCLEAR_ZBUFFER) {
5245 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5246 glDepthMask(GL_TRUE);
5248 checkGLcall("glClearDepth");
5249 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5250 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5252 if (vp->X != 0 || vp->Y != 0 ||
5253 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5254 surface_load_ds_location(This->stencilBufferTarget, location);
5256 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5257 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5258 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5259 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5260 surface_load_ds_location(This->stencilBufferTarget, location);
5262 else if (Count > 0 && pRects && (
5263 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5264 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5265 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5266 surface_load_ds_location(This->stencilBufferTarget, location);
5270 if (Flags & WINED3DCLEAR_TARGET) {
5271 TRACE("Clearing screen with glClear to color %x\n", Color);
5272 glClearColor(D3DCOLOR_R(Color),
5276 checkGLcall("glClearColor");
5278 /* Clear ALL colors! */
5279 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5280 glMask = glMask | GL_COLOR_BUFFER_BIT;
5283 vp_rect.left = vp->X;
5284 vp_rect.top = vp->Y;
5285 vp_rect.right = vp->X + vp->Width;
5286 vp_rect.bottom = vp->Y + vp->Height;
5287 if (!(Count > 0 && pRects)) {
5288 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5289 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5291 if(This->render_offscreen) {
5292 glScissor(vp_rect.left, vp_rect.top,
5293 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5295 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5296 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5298 checkGLcall("glScissor");
5300 checkGLcall("glClear");
5302 /* Now process each rect in turn */
5303 for (i = 0; i < Count; i++) {
5304 /* Note gl uses lower left, width/height */
5305 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5306 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5307 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5309 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5310 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5311 curRect.x1, (target->currentDesc.Height - curRect.y2),
5312 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5314 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5315 * The rectangle is not cleared, no error is returned, but further rectanlges are
5316 * still cleared if they are valid
5318 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5319 TRACE("Rectangle with negative dimensions, ignoring\n");
5323 if(This->render_offscreen) {
5324 glScissor(curRect.x1, curRect.y1,
5325 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5327 glScissor(curRect.x1, drawable_height - curRect.y2,
5328 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5330 checkGLcall("glScissor");
5333 checkGLcall("glClear");
5337 /* Restore the old values (why..?) */
5338 if (Flags & WINED3DCLEAR_STENCIL) {
5339 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5341 if (Flags & WINED3DCLEAR_TARGET) {
5342 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5343 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5344 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5345 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5346 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5348 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5349 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5351 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5353 if (Flags & WINED3DCLEAR_ZBUFFER) {
5354 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5355 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5356 surface_modify_ds_location(This->stencilBufferTarget, location);
5361 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5362 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5365 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5371 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5372 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5374 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5376 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5377 Count, pRects, Flags, Color, Z, Stencil);
5379 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5380 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5381 /* TODO: What about depth stencil buffers without stencil bits? */
5382 return WINED3DERR_INVALIDCALL;
5385 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5392 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5393 WINED3DPRIMITIVETYPE primitive_type)
5395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5397 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5399 This->updateStateBlock->changed.primitive_type = TRUE;
5400 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5403 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5404 WINED3DPRIMITIVETYPE *primitive_type)
5406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5408 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5410 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5412 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5415 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5419 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5421 if(!This->stateBlock->vertexDecl) {
5422 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5423 return WINED3DERR_INVALIDCALL;
5426 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5427 if(This->stateBlock->streamIsUP) {
5428 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5429 This->stateBlock->streamIsUP = FALSE;
5432 if(This->stateBlock->loadBaseVertexIndex != 0) {
5433 This->stateBlock->loadBaseVertexIndex = 0;
5434 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5436 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5437 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5438 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5442 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5443 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5447 IWineD3DIndexBuffer *pIB;
5448 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5451 pIB = This->stateBlock->pIndexData;
5453 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5454 * without an index buffer set. (The first time at least...)
5455 * D3D8 simply dies, but I doubt it can do much harm to return
5456 * D3DERR_INVALIDCALL there as well. */
5457 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5458 return WINED3DERR_INVALIDCALL;
5461 if(!This->stateBlock->vertexDecl) {
5462 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5463 return WINED3DERR_INVALIDCALL;
5466 if(This->stateBlock->streamIsUP) {
5467 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5468 This->stateBlock->streamIsUP = FALSE;
5470 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5472 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5473 This, minIndex, NumVertices, startIndex, index_count);
5475 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5476 if (IdxBufDsc.Format == WINED3DFMT_R16_UINT) {
5482 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5483 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5484 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5487 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5488 vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5493 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5494 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5499 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5500 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5502 if(!This->stateBlock->vertexDecl) {
5503 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5504 return WINED3DERR_INVALIDCALL;
5507 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5508 vb = This->stateBlock->streamSource[0];
5509 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5510 if (vb) IWineD3DBuffer_Release(vb);
5511 This->stateBlock->streamOffset[0] = 0;
5512 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5513 This->stateBlock->streamIsUP = TRUE;
5514 This->stateBlock->loadBaseVertexIndex = 0;
5516 /* TODO: Only mark dirty if drawing from a different UP address */
5517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5519 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5520 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5522 /* MSDN specifies stream zero settings must be set to NULL */
5523 This->stateBlock->streamStride[0] = 0;
5524 This->stateBlock->streamSource[0] = NULL;
5526 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5527 * the new stream sources or use UP drawing again
5532 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5533 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5534 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5539 IWineD3DIndexBuffer *ib;
5541 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5542 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5543 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5545 if(!This->stateBlock->vertexDecl) {
5546 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5547 return WINED3DERR_INVALIDCALL;
5550 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5556 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5557 vb = This->stateBlock->streamSource[0];
5558 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5559 if (vb) IWineD3DBuffer_Release(vb);
5560 This->stateBlock->streamIsUP = TRUE;
5561 This->stateBlock->streamOffset[0] = 0;
5562 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5564 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5565 This->stateBlock->baseVertexIndex = 0;
5566 This->stateBlock->loadBaseVertexIndex = 0;
5567 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5568 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5569 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5571 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5572 idxStride, pIndexData, MinVertexIndex);
5574 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5575 This->stateBlock->streamSource[0] = NULL;
5576 This->stateBlock->streamStride[0] = 0;
5577 ib = This->stateBlock->pIndexData;
5579 IWineD3DIndexBuffer_Release(ib);
5580 This->stateBlock->pIndexData = NULL;
5582 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5583 * SetStreamSource to specify a vertex buffer
5589 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5590 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5594 /* Mark the state dirty until we have nicer tracking
5595 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5598 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5599 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5600 This->stateBlock->baseVertexIndex = 0;
5601 This->up_strided = DrawPrimStrideData;
5602 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5603 This->up_strided = NULL;
5607 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5608 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5609 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5612 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5614 /* Mark the state dirty until we have nicer tracking
5615 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5618 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5619 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5620 This->stateBlock->streamIsUP = TRUE;
5621 This->stateBlock->baseVertexIndex = 0;
5622 This->up_strided = DrawPrimStrideData;
5623 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5624 This->up_strided = NULL;
5628 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5629 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5630 * not callable by the app directly no parameter validation checks are needed here.
5632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5633 WINED3DLOCKED_BOX src;
5634 WINED3DLOCKED_BOX dst;
5636 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5638 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5639 * dirtification to improve loading performance.
5641 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5642 if(FAILED(hr)) return hr;
5643 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5645 IWineD3DVolume_UnlockBox(pSourceVolume);
5649 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5651 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5653 IWineD3DVolume_UnlockBox(pSourceVolume);
5655 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5660 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5661 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5663 HRESULT hr = WINED3D_OK;
5664 WINED3DRESOURCETYPE sourceType;
5665 WINED3DRESOURCETYPE destinationType;
5668 /* TODO: think about moving the code into IWineD3DBaseTexture */
5670 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5672 /* verify that the source and destination textures aren't NULL */
5673 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5674 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5675 This, pSourceTexture, pDestinationTexture);
5676 hr = WINED3DERR_INVALIDCALL;
5679 if (pSourceTexture == pDestinationTexture) {
5680 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5681 This, pSourceTexture, pDestinationTexture);
5682 hr = WINED3DERR_INVALIDCALL;
5684 /* Verify that the source and destination textures are the same type */
5685 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5686 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5688 if (sourceType != destinationType) {
5689 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5691 hr = WINED3DERR_INVALIDCALL;
5694 /* check that both textures have the identical numbers of levels */
5695 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5696 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5697 hr = WINED3DERR_INVALIDCALL;
5700 if (WINED3D_OK == hr) {
5701 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5703 /* Make sure that the destination texture is loaded */
5704 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5706 /* Update every surface level of the texture */
5707 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5709 switch (sourceType) {
5710 case WINED3DRTYPE_TEXTURE:
5712 IWineD3DSurface *srcSurface;
5713 IWineD3DSurface *destSurface;
5715 for (i = 0 ; i < levels ; ++i) {
5716 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5717 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5718 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5719 IWineD3DSurface_Release(srcSurface);
5720 IWineD3DSurface_Release(destSurface);
5721 if (WINED3D_OK != hr) {
5722 WARN("(%p) : Call to update surface failed\n", This);
5728 case WINED3DRTYPE_CUBETEXTURE:
5730 IWineD3DSurface *srcSurface;
5731 IWineD3DSurface *destSurface;
5732 WINED3DCUBEMAP_FACES faceType;
5734 for (i = 0 ; i < levels ; ++i) {
5735 /* Update each cube face */
5736 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5737 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5738 if (WINED3D_OK != hr) {
5739 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5741 TRACE("Got srcSurface %p\n", srcSurface);
5743 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5744 if (WINED3D_OK != hr) {
5745 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5747 TRACE("Got desrSurface %p\n", destSurface);
5749 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5750 IWineD3DSurface_Release(srcSurface);
5751 IWineD3DSurface_Release(destSurface);
5752 if (WINED3D_OK != hr) {
5753 WARN("(%p) : Call to update surface failed\n", This);
5761 case WINED3DRTYPE_VOLUMETEXTURE:
5763 IWineD3DVolume *srcVolume = NULL;
5764 IWineD3DVolume *destVolume = NULL;
5766 for (i = 0 ; i < levels ; ++i) {
5767 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5768 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5769 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5770 IWineD3DVolume_Release(srcVolume);
5771 IWineD3DVolume_Release(destVolume);
5772 if (WINED3D_OK != hr) {
5773 WARN("(%p) : Call to update volume failed\n", This);
5781 FIXME("(%p) : Unsupported source and destination type\n", This);
5782 hr = WINED3DERR_INVALIDCALL;
5789 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5790 IWineD3DSwapChain *swapChain;
5792 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5793 if(hr == WINED3D_OK) {
5794 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5795 IWineD3DSwapChain_Release(swapChain);
5800 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5802 IWineD3DBaseTextureImpl *texture;
5805 TRACE("(%p) : %p\n", This, pNumPasses);
5807 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5808 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5809 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5810 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5812 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5813 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5814 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5817 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5818 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5820 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5821 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5824 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5825 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5828 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5829 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5830 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5835 /* return a sensible default */
5838 TRACE("returning D3D_OK\n");
5842 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5846 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5847 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5848 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
5849 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
5851 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5856 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5860 PALETTEENTRY **palettes;
5862 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5864 if (PaletteNumber >= MAX_PALETTES) {
5865 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5866 return WINED3DERR_INVALIDCALL;
5869 if (PaletteNumber >= This->NumberOfPalettes) {
5870 NewSize = This->NumberOfPalettes;
5873 } while(PaletteNumber >= NewSize);
5874 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5876 ERR("Out of memory!\n");
5877 return E_OUTOFMEMORY;
5879 This->palettes = palettes;
5880 This->NumberOfPalettes = NewSize;
5883 if (!This->palettes[PaletteNumber]) {
5884 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5885 if (!This->palettes[PaletteNumber]) {
5886 ERR("Out of memory!\n");
5887 return E_OUTOFMEMORY;
5891 for (j = 0; j < 256; ++j) {
5892 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5893 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5894 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5895 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5897 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5898 TRACE("(%p) : returning\n", This);
5902 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5905 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5906 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5907 /* What happens in such situation isn't documented; Native seems to silently abort
5908 on such conditions. Return Invalid Call. */
5909 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5910 return WINED3DERR_INVALIDCALL;
5912 for (j = 0; j < 256; ++j) {
5913 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5914 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5915 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5916 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5918 TRACE("(%p) : returning\n", This);
5922 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5924 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5925 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5926 (tested with reference rasterizer). Return Invalid Call. */
5927 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5928 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5929 return WINED3DERR_INVALIDCALL;
5931 /*TODO: stateblocks */
5932 if (This->currentPalette != PaletteNumber) {
5933 This->currentPalette = PaletteNumber;
5934 dirtify_p8_texture_samplers(This);
5936 TRACE("(%p) : returning\n", This);
5940 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5942 if (PaletteNumber == NULL) {
5943 WARN("(%p) : returning Invalid Call\n", This);
5944 return WINED3DERR_INVALIDCALL;
5946 /*TODO: stateblocks */
5947 *PaletteNumber = This->currentPalette;
5948 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5952 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5957 FIXME("(%p) : stub\n", This);
5961 This->softwareVertexProcessing = bSoftware;
5966 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5971 FIXME("(%p) : stub\n", This);
5974 return This->softwareVertexProcessing;
5978 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5980 IWineD3DSwapChain *swapChain;
5983 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5985 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5986 if(hr == WINED3D_OK){
5987 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5988 IWineD3DSwapChain_Release(swapChain);
5990 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5996 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5999 if(nSegments != 0.0f) {
6002 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6009 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6014 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6020 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6022 /** TODO: remove casts to IWineD3DSurfaceImpl
6023 * NOTE: move code to surface to accomplish this
6024 ****************************************/
6025 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6026 int srcWidth, srcHeight;
6027 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6028 WINED3DFORMAT destFormat, srcFormat;
6030 int srcLeft, destLeft, destTop;
6031 WINED3DPOOL srcPool, destPool;
6033 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6034 glDescriptor *glDescription = NULL;
6035 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
6039 CONVERT_TYPES convert = NO_CONVERSION;
6041 WINED3DSURFACE_DESC winedesc;
6043 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6044 memset(&winedesc, 0, sizeof(winedesc));
6045 winedesc.Width = &srcSurfaceWidth;
6046 winedesc.Height = &srcSurfaceHeight;
6047 winedesc.Pool = &srcPool;
6048 winedesc.Format = &srcFormat;
6050 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6052 winedesc.Width = &destSurfaceWidth;
6053 winedesc.Height = &destSurfaceHeight;
6054 winedesc.Pool = &destPool;
6055 winedesc.Format = &destFormat;
6056 winedesc.Size = &destSize;
6058 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6060 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6061 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6062 return WINED3DERR_INVALIDCALL;
6065 /* This call loads the opengl surface directly, instead of copying the surface to the
6066 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
6067 * copy in sysmem and use regular surface loading.
6069 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
6070 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
6071 if(convert != NO_CONVERSION) {
6072 return IWineD3DSurface_BltFast(pDestinationSurface,
6073 pDestPoint ? pDestPoint->x : 0,
6074 pDestPoint ? pDestPoint->y : 0,
6075 pSourceSurface, pSourceRect, 0);
6078 if (destFormat == WINED3DFMT_UNKNOWN) {
6079 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6080 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6082 /* Get the update surface description */
6083 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6086 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6089 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6090 checkGLcall("glActiveTextureARB");
6093 /* Make sure the surface is loaded and up to date */
6094 surface_internal_preload(pDestinationSurface, SRGB_RGB);
6095 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
6097 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6099 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
6100 dst_format_desc = ((IWineD3DSurfaceImpl *)pDestinationSurface)->resource.format_desc;
6102 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6103 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6104 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
6105 srcLeft = pSourceRect ? pSourceRect->left : 0;
6106 destLeft = pDestPoint ? pDestPoint->x : 0;
6107 destTop = pDestPoint ? pDestPoint->y : 0;
6110 /* This function doesn't support compressed textures
6111 the pitch is just bytesPerPixel * width */
6112 if(srcWidth != srcSurfaceWidth || srcLeft ){
6113 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
6114 offset += srcLeft * src_format_desc->byte_count;
6115 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6117 /* TODO DXT formats */
6119 if(pSourceRect != NULL && pSourceRect->top != 0){
6120 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
6122 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
6123 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
6124 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
6127 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6129 /* need to lock the surface to get the data */
6130 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6135 /* TODO: Cube and volume support */
6137 /* not a whole row so we have to do it a line at a time */
6140 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
6141 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6143 for (j = destTop; j < (srcHeight + destTop); ++j)
6145 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, j,
6146 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
6150 } else { /* Full width, so just write out the whole texture */
6151 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6153 if (WINED3DFMT_DXT1 == destFormat ||
6154 WINED3DFMT_DXT2 == destFormat ||
6155 WINED3DFMT_DXT3 == destFormat ||
6156 WINED3DFMT_DXT4 == destFormat ||
6157 WINED3DFMT_DXT5 == destFormat) {
6158 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6159 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6160 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6161 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6162 } if (destFormat != srcFormat) {
6163 FIXME("Updating mixed format compressed texture is not curretly support\n");
6165 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6166 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
6169 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6174 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6175 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
6178 checkGLcall("glTexSubImage2D");
6182 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6183 sampler = This->rev_tex_unit_map[0];
6184 if (sampler != -1) {
6185 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6191 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6193 struct WineD3DRectPatch *patch;
6194 GLenum old_primitive_type;
6198 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6200 if(!(Handle || pRectPatchInfo)) {
6201 /* TODO: Write a test for the return value, thus the FIXME */
6202 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6203 return WINED3DERR_INVALIDCALL;
6207 i = PATCHMAP_HASHFUNC(Handle);
6209 LIST_FOR_EACH(e, &This->patches[i]) {
6210 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6211 if(patch->Handle == Handle) {
6218 TRACE("Patch does not exist. Creating a new one\n");
6219 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6220 patch->Handle = Handle;
6221 list_add_head(&This->patches[i], &patch->entry);
6223 TRACE("Found existing patch %p\n", patch);
6226 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6227 * attributes we have to tesselate, read back, and draw. This needs a patch
6228 * management structure instance. Create one.
6230 * A possible improvement is to check if a vertex shader is used, and if not directly
6233 FIXME("Drawing an uncached patch. This is slow\n");
6234 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6237 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6238 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6239 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6241 TRACE("Tesselation density or patch info changed, retesselating\n");
6243 if(pRectPatchInfo) {
6244 patch->RectPatchInfo = *pRectPatchInfo;
6246 patch->numSegs[0] = pNumSegs[0];
6247 patch->numSegs[1] = pNumSegs[1];
6248 patch->numSegs[2] = pNumSegs[2];
6249 patch->numSegs[3] = pNumSegs[3];
6251 hr = tesselate_rectpatch(This, patch);
6253 WARN("Patch tesselation failed\n");
6255 /* Do not release the handle to store the params of the patch */
6257 HeapFree(GetProcessHeap(), 0, patch);
6263 This->currentPatch = patch;
6264 old_primitive_type = This->stateBlock->gl_primitive_type;
6265 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
6266 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6267 This->stateBlock->gl_primitive_type = old_primitive_type;
6268 This->currentPatch = NULL;
6270 /* Destroy uncached patches */
6272 HeapFree(GetProcessHeap(), 0, patch->mem);
6273 HeapFree(GetProcessHeap(), 0, patch);
6278 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6280 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6281 FIXME("(%p) : Stub\n", This);
6285 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6288 struct WineD3DRectPatch *patch;
6290 TRACE("(%p) Handle(%d)\n", This, Handle);
6292 i = PATCHMAP_HASHFUNC(Handle);
6293 LIST_FOR_EACH(e, &This->patches[i]) {
6294 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6295 if(patch->Handle == Handle) {
6296 TRACE("Deleting patch %p\n", patch);
6297 list_remove(&patch->entry);
6298 HeapFree(GetProcessHeap(), 0, patch->mem);
6299 HeapFree(GetProcessHeap(), 0, patch);
6304 /* TODO: Write a test for the return value */
6305 FIXME("Attempt to destroy nonexistent patch\n");
6306 return WINED3DERR_INVALIDCALL;
6309 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6311 IWineD3DSwapChain *swapchain;
6313 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6314 if (SUCCEEDED(hr)) {
6315 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6322 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6323 const WINED3DRECT *rect, const float color[4])
6325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6326 IWineD3DSwapChain *swapchain;
6328 swapchain = get_swapchain(surface);
6332 TRACE("Surface %p is onscreen\n", surface);
6334 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6336 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6337 buffer = surface_get_gl_buffer(surface, swapchain);
6338 glDrawBuffer(buffer);
6339 checkGLcall("glDrawBuffer()");
6341 TRACE("Surface %p is offscreen\n", surface);
6343 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6345 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6346 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6347 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6348 checkGLcall("glFramebufferRenderbufferEXT");
6352 glEnable(GL_SCISSOR_TEST);
6354 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6356 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6357 rect->x2 - rect->x1, rect->y2 - rect->y1);
6359 checkGLcall("glScissor");
6360 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6362 glDisable(GL_SCISSOR_TEST);
6364 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6366 glDisable(GL_BLEND);
6367 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6369 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6370 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6372 glClearColor(color[0], color[1], color[2], color[3]);
6373 glClear(GL_COLOR_BUFFER_BIT);
6374 checkGLcall("glClear");
6376 if (This->activeContext->current_fbo) {
6377 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6379 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6380 checkGLcall("glBindFramebuffer()");
6383 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6384 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6385 glDrawBuffer(GL_BACK);
6386 checkGLcall("glDrawBuffer()");
6392 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6393 unsigned int r, g, b, a;
6396 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6397 destfmt == WINED3DFMT_R8G8B8)
6400 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6402 a = (color & 0xff000000) >> 24;
6403 r = (color & 0x00ff0000) >> 16;
6404 g = (color & 0x0000ff00) >> 8;
6405 b = (color & 0x000000ff) >> 0;
6409 case WINED3DFMT_R5G6B5:
6410 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6417 TRACE("Returning %08x\n", ret);
6420 case WINED3DFMT_X1R5G5B5:
6421 case WINED3DFMT_A1R5G5B5:
6430 TRACE("Returning %08x\n", ret);
6433 case WINED3DFMT_A8_UNORM:
6434 TRACE("Returning %08x\n", a);
6437 case WINED3DFMT_X4R4G4B4:
6438 case WINED3DFMT_A4R4G4B4:
6447 TRACE("Returning %08x\n", ret);
6450 case WINED3DFMT_R3G3B2:
6457 TRACE("Returning %08x\n", ret);
6460 case WINED3DFMT_X8B8G8R8:
6461 case WINED3DFMT_R8G8B8A8_UNORM:
6466 TRACE("Returning %08x\n", ret);
6469 case WINED3DFMT_A2R10G10B10:
6471 r = (r * 1024) / 256;
6472 g = (g * 1024) / 256;
6473 b = (b * 1024) / 256;
6478 TRACE("Returning %08x\n", ret);
6481 case WINED3DFMT_R10G10B10A2_UNORM:
6483 r = (r * 1024) / 256;
6484 g = (g * 1024) / 256;
6485 b = (b * 1024) / 256;
6490 TRACE("Returning %08x\n", ret);
6494 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6499 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6500 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6501 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6503 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6505 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6506 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6507 return WINED3DERR_INVALIDCALL;
6510 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6511 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6512 color_fill_fbo(iface, pSurface, pRect, c);
6515 /* Just forward this to the DirectDraw blitting engine */
6516 memset(&BltFx, 0, sizeof(BltFx));
6517 BltFx.dwSize = sizeof(BltFx);
6518 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6519 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6520 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6524 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6525 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6527 IWineD3DResource *resource;
6528 IWineD3DSurface *surface;
6531 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6534 ERR("Failed to get resource, hr %#x\n", hr);
6538 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6540 FIXME("Only supported on surface resources\n");
6541 IWineD3DResource_Release(resource);
6545 surface = (IWineD3DSurface *)resource;
6547 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6549 color_fill_fbo(iface, surface, NULL, color);
6556 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6558 c = ((DWORD)(color[2] * 255.0));
6559 c |= ((DWORD)(color[1] * 255.0)) << 8;
6560 c |= ((DWORD)(color[0] * 255.0)) << 16;
6561 c |= ((DWORD)(color[3] * 255.0)) << 24;
6563 /* Just forward this to the DirectDraw blitting engine */
6564 memset(&BltFx, 0, sizeof(BltFx));
6565 BltFx.dwSize = sizeof(BltFx);
6566 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6567 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6570 ERR("Blt failed, hr %#x\n", hr);
6574 IWineD3DResource_Release(resource);
6577 /* rendertarget and depth stencil functions */
6578 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6581 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6582 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6583 return WINED3DERR_INVALIDCALL;
6586 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6587 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6588 /* Note inc ref on returned surface */
6589 if(*ppRenderTarget != NULL)
6590 IWineD3DSurface_AddRef(*ppRenderTarget);
6594 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6596 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6597 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6598 IWineD3DSwapChainImpl *Swapchain;
6601 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6603 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6604 if(hr != WINED3D_OK) {
6605 ERR("Can't get the swapchain\n");
6609 /* Make sure to release the swapchain */
6610 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6612 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6613 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6614 return WINED3DERR_INVALIDCALL;
6616 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6617 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6618 return WINED3DERR_INVALIDCALL;
6621 if(Swapchain->frontBuffer != Front) {
6622 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6624 if(Swapchain->frontBuffer)
6625 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6626 Swapchain->frontBuffer = Front;
6628 if(Swapchain->frontBuffer) {
6629 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6633 if(Back && !Swapchain->backBuffer) {
6634 /* We need memory for the back buffer array - only one back buffer this way */
6635 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6636 if(!Swapchain->backBuffer) {
6637 ERR("Out of memory\n");
6638 return E_OUTOFMEMORY;
6642 if(Swapchain->backBuffer[0] != Back) {
6643 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6645 /* What to do about the context here in the case of multithreading? Not sure.
6646 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6649 if(!Swapchain->backBuffer[0]) {
6650 /* GL was told to draw to the front buffer at creation,
6653 glDrawBuffer(GL_BACK);
6654 checkGLcall("glDrawBuffer(GL_BACK)");
6655 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6656 Swapchain->presentParms.BackBufferCount = 1;
6658 /* That makes problems - disable for now */
6659 /* glDrawBuffer(GL_FRONT); */
6660 checkGLcall("glDrawBuffer(GL_FRONT)");
6661 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6662 Swapchain->presentParms.BackBufferCount = 0;
6666 if(Swapchain->backBuffer[0])
6667 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6668 Swapchain->backBuffer[0] = Back;
6670 if(Swapchain->backBuffer[0]) {
6671 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6673 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6674 Swapchain->backBuffer = NULL;
6682 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6684 *ppZStencilSurface = This->stencilBufferTarget;
6685 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6687 if(*ppZStencilSurface != NULL) {
6688 /* Note inc ref on returned surface */
6689 IWineD3DSurface_AddRef(*ppZStencilSurface);
6692 return WINED3DERR_NOTFOUND;
6696 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6697 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6700 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6701 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6703 POINT offset = {0, 0};
6705 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6706 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6707 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6708 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6711 case WINED3DTEXF_LINEAR:
6712 gl_filter = GL_LINEAR;
6716 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6717 case WINED3DTEXF_NONE:
6718 case WINED3DTEXF_POINT:
6719 gl_filter = GL_NEAREST;
6723 /* Attach src surface to src fbo */
6724 src_swapchain = get_swapchain(src_surface);
6725 if (src_swapchain) {
6726 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6728 TRACE("Source surface %p is onscreen\n", src_surface);
6729 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6730 /* Make sure the drawable is up to date. In the offscreen case
6731 * attach_surface_fbo() implicitly takes care of this. */
6732 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6734 if(buffer == GL_FRONT) {
6737 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6738 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6739 h = windowsize.bottom - windowsize.top;
6740 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6741 src_rect->y1 = offset.y + h - src_rect->y1;
6742 src_rect->y2 = offset.y + h - src_rect->y2;
6744 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6745 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6749 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6750 glReadBuffer(buffer);
6751 checkGLcall("glReadBuffer()");
6753 TRACE("Source surface %p is offscreen\n", src_surface);
6755 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6756 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6757 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6758 checkGLcall("glReadBuffer()");
6759 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6760 checkGLcall("glFramebufferRenderbufferEXT");
6764 /* Attach dst surface to dst fbo */
6765 dst_swapchain = get_swapchain(dst_surface);
6766 if (dst_swapchain) {
6767 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6769 TRACE("Destination surface %p is onscreen\n", dst_surface);
6770 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6771 /* Make sure the drawable is up to date. In the offscreen case
6772 * attach_surface_fbo() implicitly takes care of this. */
6773 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6775 if(buffer == GL_FRONT) {
6778 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6779 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6780 h = windowsize.bottom - windowsize.top;
6781 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6782 dst_rect->y1 = offset.y + h - dst_rect->y1;
6783 dst_rect->y2 = offset.y + h - dst_rect->y2;
6785 /* Screen coords = window coords, surface height = window height */
6786 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6787 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6791 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6792 glDrawBuffer(buffer);
6793 checkGLcall("glDrawBuffer()");
6795 TRACE("Destination surface %p is offscreen\n", dst_surface);
6797 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6798 if(!src_swapchain) {
6799 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6803 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6804 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6805 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6806 checkGLcall("glDrawBuffer()");
6807 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6808 checkGLcall("glFramebufferRenderbufferEXT");
6810 glDisable(GL_SCISSOR_TEST);
6811 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6814 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6815 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6816 checkGLcall("glBlitFramebuffer()");
6818 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6819 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6820 checkGLcall("glBlitFramebuffer()");
6823 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6825 if (This->activeContext->current_fbo) {
6826 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6828 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6829 checkGLcall("glBindFramebuffer()");
6832 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6833 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6834 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6835 glDrawBuffer(GL_BACK);
6836 checkGLcall("glDrawBuffer()");
6841 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6843 WINED3DVIEWPORT viewport;
6845 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6847 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6848 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6849 This, RenderTargetIndex, GL_LIMITS(buffers));
6850 return WINED3DERR_INVALIDCALL;
6853 /* MSDN says that null disables the render target
6854 but a device must always be associated with a render target
6855 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6857 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6858 FIXME("Trying to set render target 0 to NULL\n");
6859 return WINED3DERR_INVALIDCALL;
6861 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6862 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);
6863 return WINED3DERR_INVALIDCALL;
6866 /* If we are trying to set what we already have, don't bother */
6867 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6868 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6871 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6872 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6873 This->render_targets[RenderTargetIndex] = pRenderTarget;
6875 /* Render target 0 is special */
6876 if(RenderTargetIndex == 0) {
6877 /* Finally, reset the viewport as the MSDN states. */
6878 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6879 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6882 viewport.MaxZ = 1.0f;
6883 viewport.MinZ = 0.0f;
6884 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6885 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6886 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6888 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6893 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6895 HRESULT hr = WINED3D_OK;
6896 IWineD3DSurface *tmp;
6898 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6900 if (pNewZStencil == This->stencilBufferTarget) {
6901 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6903 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6904 * depending on the renter target implementation being used.
6905 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6906 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6907 * stencil buffer and incur an extra memory overhead
6908 ******************************************************/
6910 if (This->stencilBufferTarget) {
6911 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6912 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6913 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6915 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6916 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6917 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6921 tmp = This->stencilBufferTarget;
6922 This->stencilBufferTarget = pNewZStencil;
6923 /* should we be calling the parent or the wined3d surface? */
6924 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6925 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6928 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6929 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6930 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6931 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6932 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6939 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6940 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6942 /* TODO: the use of Impl is deprecated. */
6943 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6944 WINED3DLOCKED_RECT lockedRect;
6946 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6948 /* some basic validation checks */
6949 if(This->cursorTexture) {
6950 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6952 glDeleteTextures(1, &This->cursorTexture);
6954 This->cursorTexture = 0;
6957 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6958 This->haveHardwareCursor = TRUE;
6960 This->haveHardwareCursor = FALSE;
6963 WINED3DLOCKED_RECT rect;
6965 /* MSDN: Cursor must be A8R8G8B8 */
6966 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->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 = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
6993 char *mem, *bits = rect.pBits;
6994 GLint intfmt = glDesc->glInternal;
6995 GLint format = glDesc->glFormat;
6996 GLint type = glDesc->glType;
6997 INT height = This->cursorHeight;
6998 INT width = This->cursorWidth;
6999 INT bpp = glDesc->byte_count;
7002 /* Reformat the texture memory (pitch and width can be
7004 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
7005 for(i = 0; i < height; i++)
7006 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
7007 IWineD3DSurface_UnlockRect(pCursorBitmap);
7010 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7011 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
7012 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
7015 /* Make sure that a proper texture unit is selected */
7016 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
7017 checkGLcall("glActiveTextureARB");
7018 sampler = This->rev_tex_unit_map[0];
7019 if (sampler != -1) {
7020 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
7022 /* Create a new cursor texture */
7023 glGenTextures(1, &This->cursorTexture);
7024 checkGLcall("glGenTextures");
7025 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
7026 checkGLcall("glBindTexture");
7027 /* Copy the bitmap memory into the cursor texture */
7028 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
7029 HeapFree(GetProcessHeap(), 0, mem);
7030 checkGLcall("glTexImage2D");
7032 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7033 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
7034 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
7041 FIXME("A cursor texture was not returned.\n");
7042 This->cursorTexture = 0;
7047 /* Draw a hardware cursor */
7048 ICONINFO cursorInfo;
7050 /* Create and clear maskBits because it is not needed for
7051 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
7053 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7054 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
7055 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
7056 WINED3DLOCK_NO_DIRTY_UPDATE |
7057 WINED3DLOCK_READONLY
7059 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
7060 pSur->currentDesc.Height);
7062 cursorInfo.fIcon = FALSE;
7063 cursorInfo.xHotspot = XHotSpot;
7064 cursorInfo.yHotspot = YHotSpot;
7065 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
7066 pSur->currentDesc.Height, 1,
7068 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
7069 pSur->currentDesc.Height, 1,
7070 32, lockedRect.pBits);
7071 IWineD3DSurface_UnlockRect(pCursorBitmap);
7072 /* Create our cursor and clean up. */
7073 cursor = CreateIconIndirect(&cursorInfo);
7075 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
7076 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
7077 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
7078 This->hardwareCursor = cursor;
7079 HeapFree(GetProcessHeap(), 0, maskBits);
7083 This->xHotSpot = XHotSpot;
7084 This->yHotSpot = YHotSpot;
7088 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7090 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7092 This->xScreenSpace = XScreenSpace;
7093 This->yScreenSpace = YScreenSpace;
7099 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7101 BOOL oldVisible = This->bCursorVisible;
7104 TRACE("(%p) : visible(%d)\n", This, bShow);
7107 * When ShowCursor is first called it should make the cursor appear at the OS's last
7108 * known cursor position. Because of this, some applications just repetitively call
7109 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7112 This->xScreenSpace = pt.x;
7113 This->yScreenSpace = pt.y;
7115 if (This->haveHardwareCursor) {
7116 This->bCursorVisible = bShow;
7118 SetCursor(This->hardwareCursor);
7124 if (This->cursorTexture)
7125 This->bCursorVisible = bShow;
7131 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7133 IWineD3DResourceImpl *resource;
7134 TRACE("(%p) : state (%u)\n", This, This->state);
7136 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7137 switch (This->state) {
7140 case WINED3DERR_DEVICELOST:
7142 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7143 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7144 return WINED3DERR_DEVICENOTRESET;
7146 return WINED3DERR_DEVICELOST;
7148 case WINED3DERR_DRIVERINTERNALERROR:
7149 return WINED3DERR_DRIVERINTERNALERROR;
7153 return WINED3DERR_DRIVERINTERNALERROR;
7157 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7159 /** FIXME: Resource tracking needs to be done,
7160 * The closes we can do to this is set the priorities of all managed textures low
7161 * and then reset them.
7162 ***********************************************************/
7163 FIXME("(%p) : stub\n", This);
7167 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
7169 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7171 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7172 if(surface->Flags & SFLAG_DIBSECTION) {
7173 /* Release the DC */
7174 SelectObject(surface->hDC, surface->dib.holdbitmap);
7175 DeleteDC(surface->hDC);
7176 /* Release the DIB section */
7177 DeleteObject(surface->dib.DIBsection);
7178 surface->dib.bitmap_data = NULL;
7179 surface->resource.allocatedMemory = NULL;
7180 surface->Flags &= ~SFLAG_DIBSECTION;
7182 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7183 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7184 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7185 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7186 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7187 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7189 surface->pow2Width = surface->pow2Height = 1;
7190 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7191 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7193 surface->glRect.left = 0;
7194 surface->glRect.top = 0;
7195 surface->glRect.right = surface->pow2Width;
7196 surface->glRect.bottom = surface->pow2Height;
7198 if(surface->glDescription.textureName) {
7199 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7201 glDeleteTextures(1, &surface->glDescription.textureName);
7203 surface->glDescription.textureName = 0;
7204 surface->Flags &= ~SFLAG_CLIENT;
7206 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7207 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7208 surface->Flags |= SFLAG_NONPOW2;
7210 surface->Flags &= ~SFLAG_NONPOW2;
7212 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7213 surface->resource.allocatedMemory = NULL;
7214 surface->resource.heapMemory = NULL;
7215 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7216 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7217 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7218 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7220 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7224 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7225 TRACE("Unloading resource %p\n", resource);
7226 IWineD3DResource_UnLoad(resource);
7227 IWineD3DResource_Release(resource);
7231 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7234 WINED3DDISPLAYMODE m;
7237 /* All Windowed modes are supported, as is leaving the current mode */
7238 if(pp->Windowed) return TRUE;
7239 if(!pp->BackBufferWidth) return TRUE;
7240 if(!pp->BackBufferHeight) return TRUE;
7242 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7243 for(i = 0; i < count; i++) {
7244 memset(&m, 0, sizeof(m));
7245 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7247 ERR("EnumAdapterModes failed\n");
7249 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7250 /* Mode found, it is supported */
7254 /* Mode not found -> not supported */
7258 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7260 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7262 IWineD3DBaseShaderImpl *shader;
7264 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7265 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7266 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7270 if(This->depth_blt_texture) {
7271 glDeleteTextures(1, &This->depth_blt_texture);
7272 This->depth_blt_texture = 0;
7274 if (This->depth_blt_rb) {
7275 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7276 This->depth_blt_rb = 0;
7277 This->depth_blt_rb_w = 0;
7278 This->depth_blt_rb_h = 0;
7282 This->blitter->free_private(iface);
7283 This->frag_pipe->free_private(iface);
7284 This->shader_backend->shader_free_private(iface);
7287 for (i = 0; i < GL_LIMITS(textures); i++) {
7288 /* Textures are recreated below */
7289 glDeleteTextures(1, &This->dummyTextureName[i]);
7290 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7291 This->dummyTextureName[i] = 0;
7295 while(This->numContexts) {
7296 DestroyContext(This, This->contexts[0]);
7298 This->activeContext = NULL;
7299 HeapFree(GetProcessHeap(), 0, swapchain->context);
7300 swapchain->context = NULL;
7301 swapchain->num_contexts = 0;
7304 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7306 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7308 IWineD3DSurfaceImpl *target;
7310 /* Recreate the primary swapchain's context */
7311 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7312 if(swapchain->backBuffer) {
7313 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7315 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7317 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7318 &swapchain->presentParms);
7319 swapchain->num_contexts = 1;
7320 This->activeContext = swapchain->context[0];
7322 create_dummy_textures(This);
7324 hr = This->shader_backend->shader_alloc_private(iface);
7326 ERR("Failed to recreate shader private data\n");
7329 hr = This->frag_pipe->alloc_private(iface);
7331 TRACE("Fragment pipeline private data couldn't be allocated\n");
7334 hr = This->blitter->alloc_private(iface);
7336 TRACE("Blitter private data couldn't be allocated\n");
7343 This->blitter->free_private(iface);
7344 This->frag_pipe->free_private(iface);
7345 This->shader_backend->shader_free_private(iface);
7349 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7351 IWineD3DSwapChainImpl *swapchain;
7353 BOOL DisplayModeChanged = FALSE;
7354 WINED3DDISPLAYMODE mode;
7355 TRACE("(%p)\n", This);
7357 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7359 ERR("Failed to get the first implicit swapchain\n");
7363 if(!is_display_mode_supported(This, pPresentationParameters)) {
7364 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7365 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7366 pPresentationParameters->BackBufferHeight);
7367 return WINED3DERR_INVALIDCALL;
7370 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7371 * on an existing gl context, so there's no real need for recreation.
7373 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7375 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7377 TRACE("New params:\n");
7378 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7379 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7380 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7381 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7382 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7383 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7384 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7385 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7386 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7387 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7388 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7389 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7390 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7392 /* No special treatment of these parameters. Just store them */
7393 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7394 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7395 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7396 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7398 /* What to do about these? */
7399 if(pPresentationParameters->BackBufferCount != 0 &&
7400 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7401 ERR("Cannot change the back buffer count yet\n");
7403 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7404 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7405 ERR("Cannot change the back buffer format yet\n");
7407 if(pPresentationParameters->hDeviceWindow != NULL &&
7408 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7409 ERR("Cannot change the device window yet\n");
7411 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7412 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7413 return WINED3DERR_INVALIDCALL;
7416 /* Reset the depth stencil */
7417 if (pPresentationParameters->EnableAutoDepthStencil)
7418 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7420 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7422 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7424 if(pPresentationParameters->Windowed) {
7425 mode.Width = swapchain->orig_width;
7426 mode.Height = swapchain->orig_height;
7427 mode.RefreshRate = 0;
7428 mode.Format = swapchain->presentParms.BackBufferFormat;
7430 mode.Width = pPresentationParameters->BackBufferWidth;
7431 mode.Height = pPresentationParameters->BackBufferHeight;
7432 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7433 mode.Format = swapchain->presentParms.BackBufferFormat;
7436 /* Should Width == 800 && Height == 0 set 800x600? */
7437 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7438 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7439 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7443 if(!pPresentationParameters->Windowed) {
7444 DisplayModeChanged = TRUE;
7446 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7447 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7449 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7450 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7451 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7453 if(This->auto_depth_stencil_buffer) {
7454 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7458 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7459 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7460 DisplayModeChanged) {
7462 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7464 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7465 if(swapchain->presentParms.Windowed) {
7466 /* switch from windowed to fs */
7467 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7468 pPresentationParameters->BackBufferWidth,
7469 pPresentationParameters->BackBufferHeight);
7471 /* Fullscreen -> fullscreen mode change */
7472 MoveWindow(swapchain->win_handle, 0, 0,
7473 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7476 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7477 /* Fullscreen -> windowed switch */
7478 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7480 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7481 } else if(!pPresentationParameters->Windowed) {
7482 DWORD style = This->style, exStyle = This->exStyle;
7483 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7484 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7485 * Reset to clear up their mess. Guild Wars also loses the device during that.
7489 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7490 pPresentationParameters->BackBufferWidth,
7491 pPresentationParameters->BackBufferHeight);
7492 This->style = style;
7493 This->exStyle = exStyle;
7496 TRACE("Resetting stateblock\n");
7497 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7498 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7500 /* Note: No parent needed for initial internal stateblock */
7501 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7502 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7503 else TRACE("Created stateblock %p\n", This->stateBlock);
7504 This->updateStateBlock = This->stateBlock;
7505 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7507 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7509 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7512 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7513 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7515 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7521 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7523 /** FIXME: always true at the moment **/
7524 if(!bEnableDialogs) {
7525 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7531 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7533 TRACE("(%p) : pParameters %p\n", This, pParameters);
7535 *pParameters = This->createParms;
7539 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7540 IWineD3DSwapChain *swapchain;
7542 TRACE("Relaying to swapchain\n");
7544 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7545 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7546 IWineD3DSwapChain_Release(swapchain);
7551 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7552 IWineD3DSwapChain *swapchain;
7554 TRACE("Relaying to swapchain\n");
7556 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7557 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7558 IWineD3DSwapChain_Release(swapchain);
7564 /** ********************************************************
7565 * Notification functions
7566 ** ********************************************************/
7567 /** This function must be called in the release of a resource when ref == 0,
7568 * the contents of resource must still be correct,
7569 * any handles to other resource held by the caller must be closed
7570 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7571 *****************************************************/
7572 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7575 TRACE("(%p) : Adding Resource %p\n", This, resource);
7576 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7579 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7582 TRACE("(%p) : Removing resource %p\n", This, resource);
7584 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7588 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7590 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7593 TRACE("(%p) : resource %p\n", This, resource);
7595 context_resource_released(iface, resource, type);
7598 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7599 case WINED3DRTYPE_SURFACE: {
7602 /* Cleanup any FBO attachments if d3d is enabled */
7603 if(This->d3d_initialized) {
7604 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7605 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7607 TRACE("Last active render target destroyed\n");
7608 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7609 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7610 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7611 * and the lastActiveRenderTarget member shouldn't matter
7614 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7615 TRACE("Activating primary back buffer\n");
7616 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7617 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7618 /* Single buffering environment */
7619 TRACE("Activating primary front buffer\n");
7620 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7622 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7623 /* Implicit render target destroyed, that means the device is being destroyed
7624 * whatever we set here, it shouldn't matter
7626 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7629 /* May happen during ddraw uninitialization */
7630 TRACE("Render target set, but swapchain does not exist!\n");
7631 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7635 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7636 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7637 This->render_targets[i] = NULL;
7640 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7641 This->stencilBufferTarget = NULL;
7647 case WINED3DRTYPE_TEXTURE:
7648 case WINED3DRTYPE_CUBETEXTURE:
7649 case WINED3DRTYPE_VOLUMETEXTURE:
7650 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7651 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7652 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7653 This->stateBlock->textures[counter] = NULL;
7655 if (This->updateStateBlock != This->stateBlock ){
7656 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7657 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7658 This->updateStateBlock->textures[counter] = NULL;
7663 case WINED3DRTYPE_VOLUME:
7664 /* TODO: nothing really? */
7666 case WINED3DRTYPE_VERTEXBUFFER:
7669 TRACE("Cleaning up stream pointers\n");
7671 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7672 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7673 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7675 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7676 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7677 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7678 This->updateStateBlock->streamSource[streamNumber] = 0;
7679 /* Set changed flag? */
7682 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) */
7683 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7684 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7685 This->stateBlock->streamSource[streamNumber] = 0;
7691 case WINED3DRTYPE_INDEXBUFFER:
7692 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7693 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7694 This->updateStateBlock->pIndexData = NULL;
7697 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7698 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7699 This->stateBlock->pIndexData = NULL;
7704 case WINED3DRTYPE_BUFFER:
7705 /* Nothing to do, yet.*/
7709 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7714 /* Remove the resource from the resourceStore */
7715 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7717 TRACE("Resource released\n");
7721 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7723 IWineD3DResourceImpl *resource, *cursor;
7725 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7727 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7728 TRACE("enumerating resource %p\n", resource);
7729 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7730 ret = pCallback((IWineD3DResource *) resource, pData);
7731 if(ret == S_FALSE) {
7732 TRACE("Canceling enumeration\n");
7739 /**********************************************************
7740 * IWineD3DDevice VTbl follows
7741 **********************************************************/
7743 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7745 /*** IUnknown methods ***/
7746 IWineD3DDeviceImpl_QueryInterface,
7747 IWineD3DDeviceImpl_AddRef,
7748 IWineD3DDeviceImpl_Release,
7749 /*** IWineD3DDevice methods ***/
7750 IWineD3DDeviceImpl_GetParent,
7751 /*** Creation methods**/
7752 IWineD3DDeviceImpl_CreateBuffer,
7753 IWineD3DDeviceImpl_CreateVertexBuffer,
7754 IWineD3DDeviceImpl_CreateIndexBuffer,
7755 IWineD3DDeviceImpl_CreateStateBlock,
7756 IWineD3DDeviceImpl_CreateSurface,
7757 IWineD3DDeviceImpl_CreateRendertargetView,
7758 IWineD3DDeviceImpl_CreateTexture,
7759 IWineD3DDeviceImpl_CreateVolumeTexture,
7760 IWineD3DDeviceImpl_CreateVolume,
7761 IWineD3DDeviceImpl_CreateCubeTexture,
7762 IWineD3DDeviceImpl_CreateQuery,
7763 IWineD3DDeviceImpl_CreateSwapChain,
7764 IWineD3DDeviceImpl_CreateVertexDeclaration,
7765 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7766 IWineD3DDeviceImpl_CreateVertexShader,
7767 IWineD3DDeviceImpl_CreatePixelShader,
7768 IWineD3DDeviceImpl_CreatePalette,
7769 /*** Odd functions **/
7770 IWineD3DDeviceImpl_Init3D,
7771 IWineD3DDeviceImpl_InitGDI,
7772 IWineD3DDeviceImpl_Uninit3D,
7773 IWineD3DDeviceImpl_UninitGDI,
7774 IWineD3DDeviceImpl_SetMultithreaded,
7775 IWineD3DDeviceImpl_EvictManagedResources,
7776 IWineD3DDeviceImpl_GetAvailableTextureMem,
7777 IWineD3DDeviceImpl_GetBackBuffer,
7778 IWineD3DDeviceImpl_GetCreationParameters,
7779 IWineD3DDeviceImpl_GetDeviceCaps,
7780 IWineD3DDeviceImpl_GetDirect3D,
7781 IWineD3DDeviceImpl_GetDisplayMode,
7782 IWineD3DDeviceImpl_SetDisplayMode,
7783 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7784 IWineD3DDeviceImpl_GetRasterStatus,
7785 IWineD3DDeviceImpl_GetSwapChain,
7786 IWineD3DDeviceImpl_Reset,
7787 IWineD3DDeviceImpl_SetDialogBoxMode,
7788 IWineD3DDeviceImpl_SetCursorProperties,
7789 IWineD3DDeviceImpl_SetCursorPosition,
7790 IWineD3DDeviceImpl_ShowCursor,
7791 IWineD3DDeviceImpl_TestCooperativeLevel,
7792 /*** Getters and setters **/
7793 IWineD3DDeviceImpl_SetClipPlane,
7794 IWineD3DDeviceImpl_GetClipPlane,
7795 IWineD3DDeviceImpl_SetClipStatus,
7796 IWineD3DDeviceImpl_GetClipStatus,
7797 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7798 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7799 IWineD3DDeviceImpl_SetDepthStencilSurface,
7800 IWineD3DDeviceImpl_GetDepthStencilSurface,
7801 IWineD3DDeviceImpl_SetGammaRamp,
7802 IWineD3DDeviceImpl_GetGammaRamp,
7803 IWineD3DDeviceImpl_SetIndices,
7804 IWineD3DDeviceImpl_GetIndices,
7805 IWineD3DDeviceImpl_SetBaseVertexIndex,
7806 IWineD3DDeviceImpl_GetBaseVertexIndex,
7807 IWineD3DDeviceImpl_SetLight,
7808 IWineD3DDeviceImpl_GetLight,
7809 IWineD3DDeviceImpl_SetLightEnable,
7810 IWineD3DDeviceImpl_GetLightEnable,
7811 IWineD3DDeviceImpl_SetMaterial,
7812 IWineD3DDeviceImpl_GetMaterial,
7813 IWineD3DDeviceImpl_SetNPatchMode,
7814 IWineD3DDeviceImpl_GetNPatchMode,
7815 IWineD3DDeviceImpl_SetPaletteEntries,
7816 IWineD3DDeviceImpl_GetPaletteEntries,
7817 IWineD3DDeviceImpl_SetPixelShader,
7818 IWineD3DDeviceImpl_GetPixelShader,
7819 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7820 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7821 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7822 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7823 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7824 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7825 IWineD3DDeviceImpl_SetRenderState,
7826 IWineD3DDeviceImpl_GetRenderState,
7827 IWineD3DDeviceImpl_SetRenderTarget,
7828 IWineD3DDeviceImpl_GetRenderTarget,
7829 IWineD3DDeviceImpl_SetFrontBackBuffers,
7830 IWineD3DDeviceImpl_SetSamplerState,
7831 IWineD3DDeviceImpl_GetSamplerState,
7832 IWineD3DDeviceImpl_SetScissorRect,
7833 IWineD3DDeviceImpl_GetScissorRect,
7834 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7835 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7836 IWineD3DDeviceImpl_SetStreamSource,
7837 IWineD3DDeviceImpl_GetStreamSource,
7838 IWineD3DDeviceImpl_SetStreamSourceFreq,
7839 IWineD3DDeviceImpl_GetStreamSourceFreq,
7840 IWineD3DDeviceImpl_SetTexture,
7841 IWineD3DDeviceImpl_GetTexture,
7842 IWineD3DDeviceImpl_SetTextureStageState,
7843 IWineD3DDeviceImpl_GetTextureStageState,
7844 IWineD3DDeviceImpl_SetTransform,
7845 IWineD3DDeviceImpl_GetTransform,
7846 IWineD3DDeviceImpl_SetVertexDeclaration,
7847 IWineD3DDeviceImpl_GetVertexDeclaration,
7848 IWineD3DDeviceImpl_SetVertexShader,
7849 IWineD3DDeviceImpl_GetVertexShader,
7850 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7851 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7852 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7853 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7854 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7855 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7856 IWineD3DDeviceImpl_SetViewport,
7857 IWineD3DDeviceImpl_GetViewport,
7858 IWineD3DDeviceImpl_MultiplyTransform,
7859 IWineD3DDeviceImpl_ValidateDevice,
7860 IWineD3DDeviceImpl_ProcessVertices,
7861 /*** State block ***/
7862 IWineD3DDeviceImpl_BeginStateBlock,
7863 IWineD3DDeviceImpl_EndStateBlock,
7864 /*** Scene management ***/
7865 IWineD3DDeviceImpl_BeginScene,
7866 IWineD3DDeviceImpl_EndScene,
7867 IWineD3DDeviceImpl_Present,
7868 IWineD3DDeviceImpl_Clear,
7869 IWineD3DDeviceImpl_ClearRendertargetView,
7871 IWineD3DDeviceImpl_SetPrimitiveType,
7872 IWineD3DDeviceImpl_GetPrimitiveType,
7873 IWineD3DDeviceImpl_DrawPrimitive,
7874 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7875 IWineD3DDeviceImpl_DrawPrimitiveUP,
7876 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7877 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7878 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7879 IWineD3DDeviceImpl_DrawRectPatch,
7880 IWineD3DDeviceImpl_DrawTriPatch,
7881 IWineD3DDeviceImpl_DeletePatch,
7882 IWineD3DDeviceImpl_ColorFill,
7883 IWineD3DDeviceImpl_UpdateTexture,
7884 IWineD3DDeviceImpl_UpdateSurface,
7885 IWineD3DDeviceImpl_GetFrontBufferData,
7886 /*** object tracking ***/
7887 IWineD3DDeviceImpl_ResourceReleased,
7888 IWineD3DDeviceImpl_EnumResources
7891 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7892 WINED3DRS_ALPHABLENDENABLE ,
7893 WINED3DRS_ALPHAFUNC ,
7894 WINED3DRS_ALPHAREF ,
7895 WINED3DRS_ALPHATESTENABLE ,
7897 WINED3DRS_COLORWRITEENABLE ,
7898 WINED3DRS_DESTBLEND ,
7899 WINED3DRS_DITHERENABLE ,
7900 WINED3DRS_FILLMODE ,
7901 WINED3DRS_FOGDENSITY ,
7903 WINED3DRS_FOGSTART ,
7904 WINED3DRS_LASTPIXEL ,
7905 WINED3DRS_SHADEMODE ,
7906 WINED3DRS_SRCBLEND ,
7907 WINED3DRS_STENCILENABLE ,
7908 WINED3DRS_STENCILFAIL ,
7909 WINED3DRS_STENCILFUNC ,
7910 WINED3DRS_STENCILMASK ,
7911 WINED3DRS_STENCILPASS ,
7912 WINED3DRS_STENCILREF ,
7913 WINED3DRS_STENCILWRITEMASK ,
7914 WINED3DRS_STENCILZFAIL ,
7915 WINED3DRS_TEXTUREFACTOR ,
7926 WINED3DRS_ZWRITEENABLE
7929 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7930 WINED3DTSS_ALPHAARG0 ,
7931 WINED3DTSS_ALPHAARG1 ,
7932 WINED3DTSS_ALPHAARG2 ,
7933 WINED3DTSS_ALPHAOP ,
7934 WINED3DTSS_BUMPENVLOFFSET ,
7935 WINED3DTSS_BUMPENVLSCALE ,
7936 WINED3DTSS_BUMPENVMAT00 ,
7937 WINED3DTSS_BUMPENVMAT01 ,
7938 WINED3DTSS_BUMPENVMAT10 ,
7939 WINED3DTSS_BUMPENVMAT11 ,
7940 WINED3DTSS_COLORARG0 ,
7941 WINED3DTSS_COLORARG1 ,
7942 WINED3DTSS_COLORARG2 ,
7943 WINED3DTSS_COLOROP ,
7944 WINED3DTSS_RESULTARG ,
7945 WINED3DTSS_TEXCOORDINDEX ,
7946 WINED3DTSS_TEXTURETRANSFORMFLAGS
7949 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7950 WINED3DSAMP_ADDRESSU ,
7951 WINED3DSAMP_ADDRESSV ,
7952 WINED3DSAMP_ADDRESSW ,
7953 WINED3DSAMP_BORDERCOLOR ,
7954 WINED3DSAMP_MAGFILTER ,
7955 WINED3DSAMP_MINFILTER ,
7956 WINED3DSAMP_MIPFILTER ,
7957 WINED3DSAMP_MIPMAPLODBIAS ,
7958 WINED3DSAMP_MAXMIPLEVEL ,
7959 WINED3DSAMP_MAXANISOTROPY ,
7960 WINED3DSAMP_SRGBTEXTURE ,
7961 WINED3DSAMP_ELEMENTINDEX
7964 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7966 WINED3DRS_AMBIENTMATERIALSOURCE ,
7967 WINED3DRS_CLIPPING ,
7968 WINED3DRS_CLIPPLANEENABLE ,
7969 WINED3DRS_COLORVERTEX ,
7970 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7971 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7972 WINED3DRS_FOGDENSITY ,
7974 WINED3DRS_FOGSTART ,
7975 WINED3DRS_FOGTABLEMODE ,
7976 WINED3DRS_FOGVERTEXMODE ,
7977 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7978 WINED3DRS_LIGHTING ,
7979 WINED3DRS_LOCALVIEWER ,
7980 WINED3DRS_MULTISAMPLEANTIALIAS ,
7981 WINED3DRS_MULTISAMPLEMASK ,
7982 WINED3DRS_NORMALIZENORMALS ,
7983 WINED3DRS_PATCHEDGESTYLE ,
7984 WINED3DRS_POINTSCALE_A ,
7985 WINED3DRS_POINTSCALE_B ,
7986 WINED3DRS_POINTSCALE_C ,
7987 WINED3DRS_POINTSCALEENABLE ,
7988 WINED3DRS_POINTSIZE ,
7989 WINED3DRS_POINTSIZE_MAX ,
7990 WINED3DRS_POINTSIZE_MIN ,
7991 WINED3DRS_POINTSPRITEENABLE ,
7992 WINED3DRS_RANGEFOGENABLE ,
7993 WINED3DRS_SPECULARMATERIALSOURCE ,
7994 WINED3DRS_TWEENFACTOR ,
7995 WINED3DRS_VERTEXBLEND ,
7996 WINED3DRS_CULLMODE ,
8000 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8001 WINED3DTSS_TEXCOORDINDEX ,
8002 WINED3DTSS_TEXTURETRANSFORMFLAGS
8005 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8006 WINED3DSAMP_DMAPOFFSET
8009 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8010 DWORD rep = This->StateTable[state].representative;
8014 WineD3DContext *context;
8017 for(i = 0; i < This->numContexts; i++) {
8018 context = This->contexts[i];
8019 if(isStateDirty(context, rep)) continue;
8021 context->dirtyArray[context->numDirtyEntries++] = rep;
8024 context->isStateDirty[idx] |= (1 << shift);
8028 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8029 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8030 /* The drawable size of a pbuffer render target is the current pbuffer size
8032 *width = dev->pbufferWidth;
8033 *height = dev->pbufferHeight;
8036 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8037 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8039 *width = This->pow2Width;
8040 *height = This->pow2Height;
8043 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8044 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8045 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8046 * current context's drawable, which is the size of the back buffer of the swapchain
8047 * the active context belongs to. The back buffer of the swapchain is stored as the
8048 * surface the context belongs to.
8050 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8051 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;