d4a57c9eec3fe804e0fad9b8ad2cb663b0809389
[reactos.git] / reactos / dll / directx / wine / wined3d / device.c
1 /*
2 * IWineD3DDevice implementation
3 *
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
12 *
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.
17 *
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.
22 *
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
26 */
27
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
37
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
40
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
52 };
53
54 /* static function declarations */
55 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
56
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 */
61
62 /**********************************************************
63 * IUnknown parts follows
64 **********************************************************/
65
66 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
67 {
68 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
69
70 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
71 if (IsEqualGUID(riid, &IID_IUnknown)
72 || IsEqualGUID(riid, &IID_IWineD3DBase)
73 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
74 IUnknown_AddRef(iface);
75 *ppobj = This;
76 return S_OK;
77 }
78 *ppobj = NULL;
79 return E_NOINTERFACE;
80 }
81
82 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
83 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
84 ULONG refCount = InterlockedIncrement(&This->ref);
85
86 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
87 return refCount;
88 }
89
90 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
91 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
92 ULONG refCount = InterlockedDecrement(&This->ref);
93
94 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
95
96 if (!refCount) {
97 UINT i;
98
99 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
100 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
101 This->multistate_funcs[i] = NULL;
102 }
103
104 /* TODO: Clean up all the surfaces and textures! */
105 /* NOTE: You must release the parent if the object was created via a callback
106 ** ***************************/
107
108 if (!list_empty(&This->resources)) {
109 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
110 dumpResources(&This->resources);
111 }
112
113 if(This->contexts) ERR("Context array not freed!\n");
114 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
115 This->haveHardwareCursor = FALSE;
116
117 IWineD3D_Release(This->wineD3D);
118 This->wineD3D = NULL;
119 HeapFree(GetProcessHeap(), 0, This);
120 TRACE("Freed device %p\n", This);
121 This = NULL;
122 }
123 return refCount;
124 }
125
126 /**********************************************************
127 * IWineD3DDevice implementation follows
128 **********************************************************/
129 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
131 *pParent = This->parent;
132 IUnknown_AddRef(This->parent);
133 return WINED3D_OK;
134 }
135
136 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
137 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
138 IUnknown *parent) {
139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
140 IWineD3DVertexBufferImpl *object;
141 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
142 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
143 HRESULT hr;
144 BOOL conv;
145
146 if(Size == 0) {
147 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
148 *ppVertexBuffer = NULL;
149 return WINED3DERR_INVALIDCALL;
150 } else if(Pool == WINED3DPOOL_SCRATCH) {
151 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
152 * anyway, SCRATCH vertex buffers aren't usable anywhere
153 */
154 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
155 *ppVertexBuffer = NULL;
156 return WINED3DERR_INVALIDCALL;
157 }
158
159 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
160 if (!object)
161 {
162 ERR("Out of memory\n");
163 *ppVertexBuffer = NULL;
164 return WINED3DERR_OUTOFVIDEOMEMORY;
165 }
166
167 object->lpVtbl = &IWineD3DVertexBuffer_Vtbl;
168 hr = resource_init(&object->resource, WINED3DRTYPE_VERTEXBUFFER, This, Size, Usage, Format, Pool, parent);
169 if (FAILED(hr))
170 {
171 WARN("Failed to initialize resource, returning %#x\n", hr);
172 HeapFree(GetProcessHeap(), 0, object);
173 *ppVertexBuffer = NULL;
174 return hr;
175 }
176
177 TRACE("(%p) : Created resource %p\n", This, object);
178
179 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
180
181 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);
182 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
183
184 object->fvf = FVF;
185
186 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
187 * drawStridedFast (half-life 2).
188 *
189 * Basically converting the vertices in the buffer is quite expensive, and observations
190 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
191 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
192 *
193 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
194 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
195 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
196 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
197 * dx7 apps.
198 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
199 * more. In this call we can convert dx7 buffers too.
200 */
201 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
202 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
203 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
204 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
205 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
206 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
207 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
208 } else if(dxVersion <= 7 && conv) {
209 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
210 } else {
211 object->Flags |= VBFLAG_CREATEVBO;
212 }
213 return WINED3D_OK;
214 }
215
216 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
217 GLenum error, glUsage;
218 TRACE("Creating VBO for Index Buffer %p\n", object);
219
220 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
221 * restored on the next draw
222 */
223 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
224
225 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
226 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
227 ENTER_GL();
228
229 while(glGetError());
230
231 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
232 error = glGetError();
233 if(error != GL_NO_ERROR || object->vbo == 0) {
234 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
235 goto out;
236 }
237
238 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
239 error = glGetError();
240 if(error != GL_NO_ERROR) {
241 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
242 goto out;
243 }
244
245 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
246 * copy no readback will be needed
247 */
248 glUsage = GL_STATIC_DRAW_ARB;
249 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
250 error = glGetError();
251 if(error != GL_NO_ERROR) {
252 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
253 goto out;
254 }
255 LEAVE_GL();
256 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
257 return;
258
259 out:
260 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
261 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
262 LEAVE_GL();
263 object->vbo = 0;
264 }
265
266 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
267 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
268 HANDLE *sharedHandle, IUnknown *parent) {
269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
270 IWineD3DIndexBufferImpl *object;
271 HRESULT hr;
272
273 TRACE("(%p) Creating index buffer\n", This);
274
275 /* Allocate the storage for the device */
276 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
277 if (!object)
278 {
279 ERR("Out of memory\n");
280 *ppIndexBuffer = NULL;
281 return WINED3DERR_OUTOFVIDEOMEMORY;
282 }
283
284 object->lpVtbl = &IWineD3DIndexBuffer_Vtbl;
285 hr = resource_init(&object->resource, WINED3DRTYPE_INDEXBUFFER, This, Length, Usage, Format, Pool, parent);
286 if (FAILED(hr))
287 {
288 WARN("Failed to initialize resource, returning %#x\n", hr);
289 HeapFree(GetProcessHeap(), 0, object);
290 *ppIndexBuffer = NULL;
291 return hr;
292 }
293
294 TRACE("(%p) : Created resource %p\n", This, object);
295
296 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
297
298 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
299 CreateIndexBufferVBO(This, object);
300 }
301
302 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
303 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
304 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
305
306 return WINED3D_OK;
307 }
308
309 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
310
311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
312 IWineD3DStateBlockImpl *object;
313 int i, j;
314 HRESULT temp_result;
315
316 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
317 if(!object)
318 {
319 ERR("Out of memory\n");
320 *ppStateBlock = NULL;
321 return WINED3DERR_OUTOFVIDEOMEMORY;
322 }
323
324 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
325 object->wineD3DDevice = This;
326 object->parent = parent;
327 object->ref = 1;
328 object->blockType = Type;
329
330 *ppStateBlock = (IWineD3DStateBlock *)object;
331
332 for(i = 0; i < LIGHTMAP_SIZE; i++) {
333 list_init(&object->lightMap[i]);
334 }
335
336 temp_result = allocate_shader_constants(object);
337 if (FAILED(temp_result))
338 {
339 HeapFree(GetProcessHeap(), 0, object);
340 return temp_result;
341 }
342
343 /* Special case - Used during initialization to produce a placeholder stateblock
344 so other functions called can update a state block */
345 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
346 {
347 /* Don't bother increasing the reference count otherwise a device will never
348 be freed due to circular dependencies */
349 return WINED3D_OK;
350 }
351
352 /* Otherwise, might as well set the whole state block to the appropriate values */
353 if (This->stateBlock != NULL)
354 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
355 else
356 memset(object->streamFreq, 1, sizeof(object->streamFreq));
357
358 /* Reset the ref and type after kludging it */
359 object->wineD3DDevice = This;
360 object->ref = 1;
361 object->blockType = Type;
362
363 TRACE("Updating changed flags appropriate for type %d\n", Type);
364
365 if (Type == WINED3DSBT_ALL) {
366
367 TRACE("ALL => Pretend everything has changed\n");
368 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
369
370 /* Lights are not part of the changed / set structure */
371 for(j = 0; j < LIGHTMAP_SIZE; j++) {
372 struct list *e;
373 LIST_FOR_EACH(e, &object->lightMap[j]) {
374 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
375 light->changed = TRUE;
376 light->enabledChanged = TRUE;
377 }
378 }
379 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
380 object->contained_render_states[j - 1] = j;
381 }
382 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
383 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
384 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
385 object->contained_transform_states[j - 1] = j;
386 }
387 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
388 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
389 object->contained_vs_consts_f[j] = j;
390 }
391 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
392 for(j = 0; j < MAX_CONST_I; j++) {
393 object->contained_vs_consts_i[j] = j;
394 }
395 object->num_contained_vs_consts_i = MAX_CONST_I;
396 for(j = 0; j < MAX_CONST_B; j++) {
397 object->contained_vs_consts_b[j] = j;
398 }
399 object->num_contained_vs_consts_b = MAX_CONST_B;
400 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
401 object->contained_ps_consts_f[j] = j;
402 }
403 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
404 for(j = 0; j < MAX_CONST_I; j++) {
405 object->contained_ps_consts_i[j] = j;
406 }
407 object->num_contained_ps_consts_i = MAX_CONST_I;
408 for(j = 0; j < MAX_CONST_B; j++) {
409 object->contained_ps_consts_b[j] = j;
410 }
411 object->num_contained_ps_consts_b = MAX_CONST_B;
412 for(i = 0; i < MAX_TEXTURES; i++) {
413 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
414 {
415 object->contained_tss_states[object->num_contained_tss_states].stage = i;
416 object->contained_tss_states[object->num_contained_tss_states].state = j;
417 object->num_contained_tss_states++;
418 }
419 }
420 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
421 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
422 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
423 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
424 object->num_contained_sampler_states++;
425 }
426 }
427
428 for(i = 0; i < MAX_STREAMS; i++) {
429 if(object->streamSource[i]) {
430 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
431 }
432 }
433 if(object->pIndexData) {
434 IWineD3DIndexBuffer_AddRef(object->pIndexData);
435 }
436 if(object->vertexShader) {
437 IWineD3DVertexShader_AddRef(object->vertexShader);
438 }
439 if(object->pixelShader) {
440 IWineD3DPixelShader_AddRef(object->pixelShader);
441 }
442
443 } else if (Type == WINED3DSBT_PIXELSTATE) {
444
445 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
446 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
447
448 object->changed.pixelShader = TRUE;
449
450 /* Pixel Shader Constants */
451 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
452 object->contained_ps_consts_f[i] = i;
453 object->changed.pixelShaderConstantsF[i] = TRUE;
454 }
455 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
456 for (i = 0; i < MAX_CONST_B; ++i) {
457 object->contained_ps_consts_b[i] = i;
458 object->changed.pixelShaderConstantsB |= (1 << i);
459 }
460 object->num_contained_ps_consts_b = MAX_CONST_B;
461 for (i = 0; i < MAX_CONST_I; ++i) {
462 object->contained_ps_consts_i[i] = i;
463 object->changed.pixelShaderConstantsI |= (1 << i);
464 }
465 object->num_contained_ps_consts_i = MAX_CONST_I;
466
467 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
468 DWORD rs = SavedPixelStates_R[i];
469 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
470 object->contained_render_states[i] = rs;
471 }
472 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
473 for (j = 0; j < MAX_TEXTURES; j++) {
474 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
475 DWORD state = SavedPixelStates_T[i];
476 object->changed.textureState[j] |= 1 << state;
477 object->contained_tss_states[object->num_contained_tss_states].stage = j;
478 object->contained_tss_states[object->num_contained_tss_states].state = state;
479 object->num_contained_tss_states++;
480 }
481 }
482 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
483 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
484 DWORD state = SavedPixelStates_S[i];
485 object->changed.samplerState[j] |= 1 << state;
486 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
487 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
488 object->num_contained_sampler_states++;
489 }
490 }
491 if(object->pixelShader) {
492 IWineD3DPixelShader_AddRef(object->pixelShader);
493 }
494
495 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
496 * on them. This makes releasing the buffer easier
497 */
498 for(i = 0; i < MAX_STREAMS; i++) {
499 object->streamSource[i] = NULL;
500 }
501 object->pIndexData = NULL;
502 object->vertexShader = NULL;
503
504 } else if (Type == WINED3DSBT_VERTEXSTATE) {
505
506 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
507 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
508
509 object->changed.vertexShader = TRUE;
510
511 /* Vertex Shader Constants */
512 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
513 object->changed.vertexShaderConstantsF[i] = TRUE;
514 object->contained_vs_consts_f[i] = i;
515 }
516 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
517 for (i = 0; i < MAX_CONST_B; ++i) {
518 object->contained_vs_consts_b[i] = i;
519 object->changed.vertexShaderConstantsB |= (1 << i);
520 }
521 object->num_contained_vs_consts_b = MAX_CONST_B;
522 for (i = 0; i < MAX_CONST_I; ++i) {
523 object->contained_vs_consts_i[i] = i;
524 object->changed.vertexShaderConstantsI |= (1 << i);
525 }
526 object->num_contained_vs_consts_i = MAX_CONST_I;
527 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
528 DWORD rs = SavedVertexStates_R[i];
529 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
530 object->contained_render_states[i] = rs;
531 }
532 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
533 for (j = 0; j < MAX_TEXTURES; j++) {
534 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
535 DWORD state = SavedVertexStates_T[i];
536 object->changed.textureState[j] |= 1 << state;
537 object->contained_tss_states[object->num_contained_tss_states].stage = j;
538 object->contained_tss_states[object->num_contained_tss_states].state = state;
539 object->num_contained_tss_states++;
540 }
541 }
542 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
543 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
544 DWORD state = SavedVertexStates_S[i];
545 object->changed.samplerState[j] |= 1 << state;
546 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
547 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
548 object->num_contained_sampler_states++;
549 }
550 }
551
552 for(j = 0; j < LIGHTMAP_SIZE; j++) {
553 struct list *e;
554 LIST_FOR_EACH(e, &object->lightMap[j]) {
555 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
556 light->changed = TRUE;
557 light->enabledChanged = TRUE;
558 }
559 }
560
561 for(i = 0; i < MAX_STREAMS; i++) {
562 if(object->streamSource[i]) {
563 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
564 }
565 }
566 if(object->vertexShader) {
567 IWineD3DVertexShader_AddRef(object->vertexShader);
568 }
569 object->pIndexData = NULL;
570 object->pixelShader = NULL;
571 } else {
572 FIXME("Unrecognized state block type %d\n", Type);
573 }
574
575 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
576 return WINED3D_OK;
577 }
578
579 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) {
580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
581 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
582 unsigned int Size = 1;
583 const struct GlPixelFormatDesc *glDesc;
584 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
585 UINT mul_4w, mul_4h;
586 HRESULT hr;
587
588 TRACE("(%p) Create surface\n",This);
589
590 if(MultisampleQuality > 0) {
591 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
592 MultisampleQuality=0;
593 }
594
595 /** FIXME: Check that the format is supported
596 * by the device.
597 *******************************/
598
599 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
600 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
601 * space!
602 *********************************/
603 mul_4w = (Width + 3) & ~3;
604 mul_4h = (Height + 3) & ~3;
605 if (WINED3DFMT_UNKNOWN == Format) {
606 Size = 0;
607 } else if (Format == WINED3DFMT_DXT1) {
608 /* DXT1 is half byte per pixel */
609 Size = (mul_4w * tableEntry->bpp * mul_4h) >> 1;
610
611 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
612 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
613 Format == WINED3DFMT_ATI2N) {
614 Size = (mul_4w * tableEntry->bpp * mul_4h);
615 } else {
616 /* The pitch is a multiple of 4 bytes */
617 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
618 Size *= Height;
619 }
620
621 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
622
623 /** Create and initialise the surface resource **/
624 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
625 if (!object)
626 {
627 ERR("Out of memory\n");
628 *ppSurface = NULL;
629 return WINED3DERR_OUTOFVIDEOMEMORY;
630 }
631
632 /* Look at the implementation and set the correct Vtable */
633 switch(Impl)
634 {
635 case SURFACE_OPENGL:
636 /* Check if a 3D adapter is available when creating gl surfaces */
637 if (!This->adapter)
638 {
639 ERR("OpenGL surfaces are not available without opengl\n");
640 HeapFree(GetProcessHeap(), 0, object);
641 return WINED3DERR_NOTAVAILABLE;
642 }
643 object->lpVtbl = &IWineD3DSurface_Vtbl;
644 break;
645
646 case SURFACE_GDI:
647 object->lpVtbl = &IWineGDISurface_Vtbl;
648 break;
649
650 default:
651 /* To be sure to catch this */
652 ERR("Unknown requested surface implementation %d!\n", Impl);
653 HeapFree(GetProcessHeap(), 0, object);
654 return WINED3DERR_INVALIDCALL;
655 }
656
657 hr = resource_init(&object->resource, WINED3DRTYPE_SURFACE, This, Size, Usage, Format, Pool, parent);
658 if (FAILED(hr))
659 {
660 WARN("Failed to initialize resource, returning %#x\n", hr);
661 HeapFree(GetProcessHeap(), 0, object);
662 *ppSurface = NULL;
663 return hr;
664 }
665
666 TRACE("(%p) : Created resource %p\n", This, object);
667
668 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
669
670 *ppSurface = (IWineD3DSurface *)object;
671
672 /* "Standalone" surface */
673 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
674
675 object->currentDesc.Width = Width;
676 object->currentDesc.Height = Height;
677 object->currentDesc.MultiSampleType = MultiSample;
678 object->currentDesc.MultiSampleQuality = MultisampleQuality;
679 object->glDescription.level = Level;
680 object->heightscale = glDesc->heightscale != 0.0 ? glDesc->heightscale : 1.0;
681 list_init(&object->overlays);
682
683 /* Flags */
684 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
685 object->Flags |= Discard ? SFLAG_DISCARD : 0;
686 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
687 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
688
689
690 if (WINED3DFMT_UNKNOWN != Format) {
691 object->bytesPerPixel = tableEntry->bpp;
692 } else {
693 object->bytesPerPixel = 0;
694 }
695
696 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
697
698 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
699
700 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
701 * this function is too deep to need to care about things like this.
702 * Levels need to be checked too, and possibly Type since they all affect what can be done.
703 * ****************************************/
704 switch(Pool) {
705 case WINED3DPOOL_SCRATCH:
706 if(!Lockable)
707 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
708 "which are mutually exclusive, setting lockable to TRUE\n");
709 Lockable = TRUE;
710 break;
711 case WINED3DPOOL_SYSTEMMEM:
712 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
713 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
714 case WINED3DPOOL_MANAGED:
715 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
716 "Usage of DYNAMIC which are mutually exclusive, not doing "
717 "anything just telling you.\n");
718 break;
719 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
720 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
721 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
722 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
723 break;
724 default:
725 FIXME("(%p) Unknown pool %d\n", This, Pool);
726 break;
727 };
728
729 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
730 FIXME("Trying to create a render target that isn't in the default pool\n");
731 }
732
733 /* mark the texture as dirty so that it gets loaded first time around*/
734 surface_add_dirty_rect(*ppSurface, NULL);
735 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
736 This, Width, Height, Format, debug_d3dformat(Format),
737 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
738
739 list_init(&object->renderbuffers);
740
741 /* Call the private setup routine */
742 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)object);
743 if (FAILED(hr))
744 {
745 ERR("Private setup failed, returning %#x\n", hr);
746 IWineD3DSurface_Release(*ppSurface);
747 *ppSurface = NULL;
748 return hr;
749 }
750
751 return hr;
752 }
753
754 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
755 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
756 IWineD3DTexture **ppTexture, HANDLE *pSharedHandle, IUnknown *parent)
757 {
758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
759 IWineD3DTextureImpl *object;
760 unsigned int i;
761 UINT tmpW;
762 UINT tmpH;
763 HRESULT hr;
764 unsigned int pow2Width;
765 unsigned int pow2Height;
766 const struct GlPixelFormatDesc *glDesc;
767 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
768
769 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
770 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
771 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
772
773 /* TODO: It should only be possible to create textures for formats
774 that are reported as supported */
775 if (WINED3DFMT_UNKNOWN >= Format) {
776 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
777 return WINED3DERR_INVALIDCALL;
778 }
779
780 /* Non-power2 support */
781 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO))
782 {
783 pow2Width = Width;
784 pow2Height = Height;
785 }
786 else
787 {
788 /* Find the nearest pow2 match */
789 pow2Width = pow2Height = 1;
790 while (pow2Width < Width) pow2Width <<= 1;
791 while (pow2Height < Height) pow2Height <<= 1;
792
793 if (pow2Width != Width || pow2Height != Height)
794 {
795 if (Levels > 1)
796 {
797 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
798 return WINED3DERR_INVALIDCALL;
799 }
800 Levels = 1;
801 }
802 }
803
804 /* Calculate levels for mip mapping */
805 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
806 {
807 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
808 {
809 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
810 return WINED3DERR_INVALIDCALL;
811 }
812
813 if (Levels > 1)
814 {
815 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
816 return WINED3DERR_INVALIDCALL;
817 }
818
819 Levels = 1;
820 }
821 else if (!Levels)
822 {
823 Levels = wined3d_log2i(max(Width, Height)) + 1;
824 TRACE("Calculated levels = %d\n", Levels);
825 }
826
827 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
828 if (!object)
829 {
830 ERR("Out of memory\n");
831 *ppTexture = NULL;
832 return WINED3DERR_OUTOFVIDEOMEMORY;
833 }
834
835 object->lpVtbl = &IWineD3DTexture_Vtbl;
836 hr = resource_init(&object->resource, WINED3DRTYPE_TEXTURE, This, 0, Usage, Format, Pool, parent);
837 if (FAILED(hr))
838 {
839 WARN("Failed to initialize resource, returning %#x\n", hr);
840 HeapFree(GetProcessHeap(), 0, object);
841 *ppTexture = NULL;
842 return hr;
843 }
844
845 TRACE("(%p) : Created resource %p\n", This, object);
846
847 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
848
849 *ppTexture = (IWineD3DTexture *)object;
850
851 basetexture_init(&object->baseTexture, Levels, Usage);
852 object->width = Width;
853 object->height = Height;
854
855 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
856 object->baseTexture.minMipLookup = minMipLookup;
857 object->baseTexture.magLookup = magLookup;
858 } else {
859 object->baseTexture.minMipLookup = minMipLookup_noFilter;
860 object->baseTexture.magLookup = magLookup_noFilter;
861 }
862
863 /** FIXME: add support for real non-power-two if it's provided by the video card **/
864 /* Precalculated scaling for 'faked' non power of two texture coords.
865 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
866 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
867 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
868 */
869 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
870 object->baseTexture.pow2Matrix[0] = 1.0;
871 object->baseTexture.pow2Matrix[5] = 1.0;
872 object->baseTexture.pow2Matrix[10] = 1.0;
873 object->baseTexture.pow2Matrix[15] = 1.0;
874 object->target = GL_TEXTURE_2D;
875 object->cond_np2 = TRUE;
876 object->baseTexture.minMipLookup = minMipLookup_noFilter;
877 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
878 (Width != pow2Width || Height != pow2Height) &&
879 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
880 {
881 object->baseTexture.pow2Matrix[0] = (float)Width;
882 object->baseTexture.pow2Matrix[5] = (float)Height;
883 object->baseTexture.pow2Matrix[10] = 1.0;
884 object->baseTexture.pow2Matrix[15] = 1.0;
885 object->target = GL_TEXTURE_RECTANGLE_ARB;
886 object->cond_np2 = TRUE;
887 object->baseTexture.minMipLookup = minMipLookup_noFilter;
888 } else {
889 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
890 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
891 object->baseTexture.pow2Matrix[10] = 1.0;
892 object->baseTexture.pow2Matrix[15] = 1.0;
893 object->target = GL_TEXTURE_2D;
894 object->cond_np2 = FALSE;
895 }
896 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
897
898 /* Generate all the surfaces */
899 tmpW = Width;
900 tmpH = Height;
901 for (i = 0; i < object->baseTexture.levels; i++)
902 {
903 /* use the callback to create the texture surface */
904 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpH, Format,
905 Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i]);
906 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
907 FIXME("Failed to create surface %p\n", object);
908 /* clean up */
909 object->surfaces[i] = NULL;
910 IWineD3DTexture_Release((IWineD3DTexture *)object);
911
912 *ppTexture = NULL;
913 return hr;
914 }
915
916 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
917 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
918 surface_set_texture_target(object->surfaces[i], object->target);
919 /* calculate the next mipmap level */
920 tmpW = max(1, tmpW >> 1);
921 tmpH = max(1, tmpH >> 1);
922 }
923 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
924
925 TRACE("(%p) : Created texture %p\n", This, object);
926 return WINED3D_OK;
927 }
928
929 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
930 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
931 IWineD3DVolumeTexture **ppVolumeTexture, HANDLE *pSharedHandle, IUnknown *parent)
932 {
933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
934 IWineD3DVolumeTextureImpl *object;
935 unsigned int i;
936 UINT tmpW;
937 UINT tmpH;
938 UINT tmpD;
939 const struct GlPixelFormatDesc *glDesc;
940 HRESULT hr;
941
942 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
943
944 /* TODO: It should only be possible to create textures for formats
945 that are reported as supported */
946 if (WINED3DFMT_UNKNOWN >= Format) {
947 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
948 return WINED3DERR_INVALIDCALL;
949 }
950 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
951 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
952 return WINED3DERR_INVALIDCALL;
953 }
954
955 /* Calculate levels for mip mapping */
956 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
957 {
958 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
959 {
960 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
961 return WINED3DERR_INVALIDCALL;
962 }
963
964 if (Levels > 1)
965 {
966 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
967 return WINED3DERR_INVALIDCALL;
968 }
969
970 Levels = 1;
971 }
972 else if (!Levels)
973 {
974 Levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
975 TRACE("Calculated levels = %d\n", Levels);
976 }
977
978 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
979 if (!object)
980 {
981 ERR("Out of memory\n");
982 *ppVolumeTexture = NULL;
983 return WINED3DERR_OUTOFVIDEOMEMORY;
984 }
985
986 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
987 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUMETEXTURE, This, 0, Usage, Format, Pool, parent);
988 if (FAILED(hr))
989 {
990 WARN("Failed to initialize resource, returning %#x\n", hr);
991 HeapFree(GetProcessHeap(), 0, object);
992 *ppVolumeTexture = NULL;
993 return hr;
994 }
995
996 TRACE("(%p) : Created resource %p\n", This, object);
997
998 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
999
1000 basetexture_init(&object->baseTexture, Levels, Usage);
1001
1002 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1003 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1004
1005 /* Is NP2 support for volumes needed? */
1006 object->baseTexture.pow2Matrix[ 0] = 1.0;
1007 object->baseTexture.pow2Matrix[ 5] = 1.0;
1008 object->baseTexture.pow2Matrix[10] = 1.0;
1009 object->baseTexture.pow2Matrix[15] = 1.0;
1010
1011 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1012 object->baseTexture.minMipLookup = minMipLookup;
1013 object->baseTexture.magLookup = magLookup;
1014 } else {
1015 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1016 object->baseTexture.magLookup = magLookup_noFilter;
1017 }
1018
1019 /* Generate all the surfaces */
1020 tmpW = Width;
1021 tmpH = Height;
1022 tmpD = Depth;
1023
1024 for (i = 0; i < object->baseTexture.levels; i++)
1025 {
1026 HRESULT hr;
1027 /* Create the volume */
1028 hr = IWineD3DDeviceParent_CreateVolume(This->device_parent, parent,
1029 tmpW, tmpH, tmpD, Format, Pool, Usage, &object->volumes[i]);
1030 if(FAILED(hr)) {
1031 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1032 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1033 *ppVolumeTexture = NULL;
1034 return hr;
1035 }
1036
1037 /* Set its container to this object */
1038 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1039
1040 /* calculate the next mipmap level */
1041 tmpW = max(1, tmpW >> 1);
1042 tmpH = max(1, tmpH >> 1);
1043 tmpD = max(1, tmpD >> 1);
1044 }
1045 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
1046
1047 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1048 TRACE("(%p) : Created volume texture %p\n", This, object);
1049 return WINED3D_OK;
1050 }
1051
1052 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1053 UINT Width, UINT Height, UINT Depth,
1054 DWORD Usage,
1055 WINED3DFORMAT Format, WINED3DPOOL Pool,
1056 IWineD3DVolume** ppVolume,
1057 HANDLE* pSharedHandle, IUnknown *parent) {
1058
1059 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1060 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1061 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1062 HRESULT hr;
1063
1064 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1065 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1066 return WINED3DERR_INVALIDCALL;
1067 }
1068
1069 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1070 if (!object)
1071 {
1072 ERR("Out of memory\n");
1073 *ppVolume = NULL;
1074 return WINED3DERR_OUTOFVIDEOMEMORY;
1075 }
1076
1077 object->lpVtbl = &IWineD3DVolume_Vtbl;
1078 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUME, This,
1079 Width * Height * Depth * formatDesc->bpp, Usage, Format, Pool, parent);
1080 if (FAILED(hr))
1081 {
1082 WARN("Failed to initialize resource, returning %#x\n", hr);
1083 HeapFree(GetProcessHeap(), 0, object);
1084 *ppVolume = NULL;
1085 return hr;
1086 }
1087
1088 TRACE("(%p) : Created resource %p\n", This, object);
1089
1090 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1091
1092 *ppVolume = (IWineD3DVolume *)object;
1093
1094 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1095 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1096
1097 object->currentDesc.Width = Width;
1098 object->currentDesc.Height = Height;
1099 object->currentDesc.Depth = Depth;
1100 object->bytesPerPixel = formatDesc->bpp;
1101
1102 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1103 object->lockable = TRUE;
1104 object->locked = FALSE;
1105 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1106 object->dirty = TRUE;
1107
1108 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1109
1110 return WINED3D_OK;
1111 }
1112
1113 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1114 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1115 IWineD3DCubeTexture **ppCubeTexture, HANDLE *pSharedHandle, IUnknown *parent)
1116 {
1117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1118 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1119 unsigned int i, j;
1120 UINT tmpW;
1121 HRESULT hr;
1122 unsigned int pow2EdgeLength;
1123 const struct GlPixelFormatDesc *glDesc;
1124 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1125
1126 /* TODO: It should only be possible to create textures for formats
1127 that are reported as supported */
1128 if (WINED3DFMT_UNKNOWN >= Format) {
1129 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1130 return WINED3DERR_INVALIDCALL;
1131 }
1132
1133 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1134 WARN("(%p) : Tried to create not supported cube texture\n", This);
1135 return WINED3DERR_INVALIDCALL;
1136 }
1137
1138 /* Calculate levels for mip mapping */
1139 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1140 {
1141 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1142 {
1143 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1144 return WINED3DERR_INVALIDCALL;
1145 }
1146
1147 if (Levels > 1)
1148 {
1149 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1150 return WINED3DERR_INVALIDCALL;
1151 }
1152
1153 Levels = 1;
1154 }
1155 else if (!Levels)
1156 {
1157 Levels = wined3d_log2i(EdgeLength) + 1;
1158 TRACE("Calculated levels = %d\n", Levels);
1159 }
1160
1161 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1162 if (!object)
1163 {
1164 ERR("Out of memory\n");
1165 *ppCubeTexture = NULL;
1166 return WINED3DERR_OUTOFVIDEOMEMORY;
1167 }
1168
1169 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1170 hr = resource_init(&object->resource, WINED3DRTYPE_CUBETEXTURE, This, 0, Usage, Format, Pool, parent);
1171 if (FAILED(hr))
1172 {
1173 WARN("Failed to initialize resource, returning %#x\n", hr);
1174 HeapFree(GetProcessHeap(), 0, object);
1175 *ppCubeTexture = NULL;
1176 return hr;
1177 }
1178
1179 TRACE("(%p) : Created resource %p\n", This, object);
1180
1181 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1182
1183 basetexture_init(&object->baseTexture, Levels, Usage);
1184
1185 TRACE("(%p) Create Cube Texture\n", This);
1186
1187 /* Find the nearest pow2 match */
1188 pow2EdgeLength = 1;
1189 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1190
1191 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
1192 /* Precalculated scaling for 'faked' non power of two texture coords */
1193 object->baseTexture.pow2Matrix[ 0] = 1.0;
1194 object->baseTexture.pow2Matrix[ 5] = 1.0;
1195 object->baseTexture.pow2Matrix[10] = 1.0;
1196 object->baseTexture.pow2Matrix[15] = 1.0;
1197 } else {
1198 /* Precalculated scaling for 'faked' non power of two texture coords */
1199 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1200 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1201 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1202 object->baseTexture.pow2Matrix[15] = 1.0;
1203 }
1204
1205 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1206 object->baseTexture.minMipLookup = minMipLookup;
1207 object->baseTexture.magLookup = magLookup;
1208 } else {
1209 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1210 object->baseTexture.magLookup = magLookup_noFilter;
1211 }
1212
1213 /* Generate all the surfaces */
1214 tmpW = EdgeLength;
1215 for (i = 0; i < object->baseTexture.levels; i++) {
1216
1217 /* Create the 6 faces */
1218 for (j = 0; j < 6; j++) {
1219 static const GLenum cube_targets[6] = {
1220 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1221 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1222 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1223 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1224 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1225 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1226 };
1227
1228 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpW,
1229 Format, Usage, Pool, i /* Level */, j, &object->surfaces[j][i]);
1230 if (FAILED(hr))
1231 {
1232 FIXME("(%p) Failed to create surface\n",object);
1233 IWineD3DCubeTexture_Release((IWineD3DCubeTexture *)object);
1234 *ppCubeTexture = NULL;
1235 return hr;
1236 }
1237 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1238 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1239 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1240 }
1241 tmpW = max(1, tmpW >> 1);
1242 }
1243 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
1244
1245 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1246 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1247 return WINED3D_OK;
1248 }
1249
1250 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1252 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1253 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1254 const IWineD3DQueryVtbl *vtable;
1255
1256 /* Just a check to see if we support this type of query */
1257 switch(Type) {
1258 case WINED3DQUERYTYPE_OCCLUSION:
1259 TRACE("(%p) occlusion query\n", This);
1260 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1261 hr = WINED3D_OK;
1262 else
1263 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1264
1265 vtable = &IWineD3DOcclusionQuery_Vtbl;
1266 break;
1267
1268 case WINED3DQUERYTYPE_EVENT:
1269 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1270 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1271 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1272 */
1273 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1274 }
1275 vtable = &IWineD3DEventQuery_Vtbl;
1276 hr = WINED3D_OK;
1277 break;
1278
1279 case WINED3DQUERYTYPE_VCACHE:
1280 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1281 case WINED3DQUERYTYPE_VERTEXSTATS:
1282 case WINED3DQUERYTYPE_TIMESTAMP:
1283 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1284 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1285 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1286 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1287 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1288 case WINED3DQUERYTYPE_PIXELTIMINGS:
1289 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1290 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1291 default:
1292 /* Use the base Query vtable until we have a special one for each query */
1293 vtable = &IWineD3DQuery_Vtbl;
1294 FIXME("(%p) Unhandled query type %d\n", This, Type);
1295 }
1296 if(NULL == ppQuery || hr != WINED3D_OK) {
1297 return hr;
1298 }
1299
1300 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1301 if(!object)
1302 {
1303 ERR("Out of memory\n");
1304 *ppQuery = NULL;
1305 return WINED3DERR_OUTOFVIDEOMEMORY;
1306 }
1307
1308 object->lpVtbl = vtable;
1309 object->type = Type;
1310 object->state = QUERY_CREATED;
1311 object->wineD3DDevice = This;
1312 object->parent = parent;
1313 object->ref = 1;
1314
1315 *ppQuery = (IWineD3DQuery *)object;
1316
1317 /* allocated the 'extended' data based on the type of query requested */
1318 switch(Type){
1319 case WINED3DQUERYTYPE_OCCLUSION:
1320 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1321 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1322
1323 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1324 TRACE("(%p) Allocating data for an occlusion query\n", This);
1325
1326 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1327 ENTER_GL();
1328 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1329 LEAVE_GL();
1330 break;
1331 }
1332 case WINED3DQUERYTYPE_EVENT:
1333 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1334 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1335
1336 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1337 ENTER_GL();
1338 if(GL_SUPPORT(APPLE_FENCE)) {
1339 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1340 checkGLcall("glGenFencesAPPLE");
1341 } else if(GL_SUPPORT(NV_FENCE)) {
1342 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1343 checkGLcall("glGenFencesNV");
1344 }
1345 LEAVE_GL();
1346 break;
1347
1348 case WINED3DQUERYTYPE_VCACHE:
1349 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1350 case WINED3DQUERYTYPE_VERTEXSTATS:
1351 case WINED3DQUERYTYPE_TIMESTAMP:
1352 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1353 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1354 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1355 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1356 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1357 case WINED3DQUERYTYPE_PIXELTIMINGS:
1358 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1359 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1360 default:
1361 object->extendedData = 0;
1362 FIXME("(%p) Unhandled query type %d\n",This , Type);
1363 }
1364 TRACE("(%p) : Created Query %p\n", This, object);
1365 return WINED3D_OK;
1366 }
1367
1368 /*****************************************************************************
1369 * IWineD3DDeviceImpl_SetupFullscreenWindow
1370 *
1371 * Helper function that modifies a HWND's Style and ExStyle for proper
1372 * fullscreen use.
1373 *
1374 * Params:
1375 * iface: Pointer to the IWineD3DDevice interface
1376 * window: Window to setup
1377 *
1378 *****************************************************************************/
1379 static LONG fullscreen_style(LONG orig_style) {
1380 LONG style = orig_style;
1381 style &= ~WS_CAPTION;
1382 style &= ~WS_THICKFRAME;
1383
1384 /* Make sure the window is managed, otherwise we won't get keyboard input */
1385 style |= WS_POPUP | WS_SYSMENU;
1386
1387 return style;
1388 }
1389
1390 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1391 LONG exStyle = orig_exStyle;
1392
1393 /* Filter out window decorations */
1394 exStyle &= ~WS_EX_WINDOWEDGE;
1395 exStyle &= ~WS_EX_CLIENTEDGE;
1396
1397 return exStyle;
1398 }
1399
1400 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1402
1403 LONG style, exStyle;
1404 /* Don't do anything if an original style is stored.
1405 * That shouldn't happen
1406 */
1407 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1408 if (This->style || This->exStyle) {
1409 ERR("(%p): Want to change the window parameters of HWND %p, but "
1410 "another style is stored for restoration afterwards\n", This, window);
1411 }
1412
1413 /* Get the parameters and save them */
1414 style = GetWindowLongW(window, GWL_STYLE);
1415 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1416 This->style = style;
1417 This->exStyle = exStyle;
1418
1419 style = fullscreen_style(style);
1420 exStyle = fullscreen_exStyle(exStyle);
1421
1422 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1423 This->style, This->exStyle, style, exStyle);
1424
1425 SetWindowLongW(window, GWL_STYLE, style);
1426 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1427
1428 /* Inform the window about the update. */
1429 SetWindowPos(window, HWND_TOP, 0, 0,
1430 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1431 }
1432
1433 /*****************************************************************************
1434 * IWineD3DDeviceImpl_RestoreWindow
1435 *
1436 * Helper function that restores a windows' properties when taking it out
1437 * of fullscreen mode
1438 *
1439 * Params:
1440 * iface: Pointer to the IWineD3DDevice interface
1441 * window: Window to setup
1442 *
1443 *****************************************************************************/
1444 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1446 LONG style, exStyle;
1447
1448 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1449 * switch, do nothing
1450 */
1451 if (!This->style && !This->exStyle) return;
1452
1453 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1454 This, window, This->style, This->exStyle);
1455
1456 style = GetWindowLongW(window, GWL_STYLE);
1457 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1458
1459 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1460 * Some applications change it before calling Reset() when switching between windowed and
1461 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1462 */
1463 if(style == fullscreen_style(This->style) &&
1464 exStyle == fullscreen_style(This->exStyle)) {
1465 SetWindowLongW(window, GWL_STYLE, This->style);
1466 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1467 }
1468
1469 /* Delete the old values */
1470 This->style = 0;
1471 This->exStyle = 0;
1472
1473 /* Inform the window about the update */
1474 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1475 0, 0, 0, 0, /* Pos, Size, ignored */
1476 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1477 }
1478
1479 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1480 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1481 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1482 IUnknown *parent, WINED3DSURFTYPE surface_type)
1483 {
1484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1485
1486 HDC hDc;
1487 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1488 HRESULT hr;
1489 IUnknown *bufferParent;
1490 BOOL displaymode_set = FALSE;
1491 WINED3DDISPLAYMODE Mode;
1492 const StaticPixelFormatDesc *formatDesc;
1493
1494 TRACE("(%p) : Created Additional Swap Chain\n", This);
1495
1496 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1497 * does a device hold a reference to a swap chain giving them a lifetime of the device
1498 * or does the swap chain notify the device of its destruction.
1499 *******************************/
1500
1501 /* Check the params */
1502 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1503 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1504 return WINED3DERR_INVALIDCALL;
1505 } else if (pPresentationParameters->BackBufferCount > 1) {
1506 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");
1507 }
1508
1509 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1510 if(!object)
1511 {
1512 ERR("Out of memory\n");
1513 *ppSwapChain = NULL;
1514 return WINED3DERR_OUTOFVIDEOMEMORY;
1515 }
1516
1517 switch(surface_type) {
1518 case SURFACE_GDI:
1519 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1520 break;
1521 case SURFACE_OPENGL:
1522 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1523 break;
1524 case SURFACE_UNKNOWN:
1525 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1526 HeapFree(GetProcessHeap(), 0, object);
1527 return WINED3DERR_INVALIDCALL;
1528 }
1529 object->wineD3DDevice = This;
1530 object->parent = parent;
1531 object->ref = 1;
1532
1533 *ppSwapChain = (IWineD3DSwapChain *)object;
1534
1535 /*********************
1536 * Lookup the window Handle and the relating X window handle
1537 ********************/
1538
1539 /* Setup hwnd we are using, plus which display this equates to */
1540 object->win_handle = pPresentationParameters->hDeviceWindow;
1541 if (!object->win_handle) {
1542 object->win_handle = This->createParms.hFocusWindow;
1543 }
1544 if(!pPresentationParameters->Windowed && object->win_handle) {
1545 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1546 pPresentationParameters->BackBufferWidth,
1547 pPresentationParameters->BackBufferHeight);
1548 }
1549
1550 hDc = GetDC(object->win_handle);
1551 TRACE("Using hDc %p\n", hDc);
1552
1553 if (NULL == hDc) {
1554 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1555 return WINED3DERR_NOTAVAILABLE;
1556 }
1557
1558 /* Get info on the current display setup */
1559 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1560 object->orig_width = Mode.Width;
1561 object->orig_height = Mode.Height;
1562 object->orig_fmt = Mode.Format;
1563 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1564
1565 if (pPresentationParameters->Windowed &&
1566 ((pPresentationParameters->BackBufferWidth == 0) ||
1567 (pPresentationParameters->BackBufferHeight == 0) ||
1568 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1569
1570 RECT Rect;
1571 GetClientRect(object->win_handle, &Rect);
1572
1573 if (pPresentationParameters->BackBufferWidth == 0) {
1574 pPresentationParameters->BackBufferWidth = Rect.right;
1575 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1576 }
1577 if (pPresentationParameters->BackBufferHeight == 0) {
1578 pPresentationParameters->BackBufferHeight = Rect.bottom;
1579 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1580 }
1581 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1582 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1583 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1584 }
1585 }
1586
1587 /* Put the correct figures in the presentation parameters */
1588 TRACE("Copying across presentation parameters\n");
1589 object->presentParms = *pPresentationParameters;
1590
1591 TRACE("calling rendertarget CB\n");
1592 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1593 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1594 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1595 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1596 if (SUCCEEDED(hr)) {
1597 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1598 if(surface_type == SURFACE_OPENGL) {
1599 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1600 }
1601 } else {
1602 ERR("Failed to create the front buffer\n");
1603 goto error;
1604 }
1605
1606 /*********************
1607 * Windowed / Fullscreen
1608 *******************/
1609
1610 /**
1611 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1612 * so we should really check to see if there is a fullscreen swapchain already
1613 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1614 **************************************/
1615
1616 if (!pPresentationParameters->Windowed) {
1617 WINED3DDISPLAYMODE mode;
1618
1619
1620 /* Change the display settings */
1621 mode.Width = pPresentationParameters->BackBufferWidth;
1622 mode.Height = pPresentationParameters->BackBufferHeight;
1623 mode.Format = pPresentationParameters->BackBufferFormat;
1624 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1625
1626 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1627 displaymode_set = TRUE;
1628 }
1629
1630 /**
1631 * Create an opengl context for the display visual
1632 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1633 * use different properties after that point in time. FIXME: How to handle when requested format
1634 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1635 * it chooses is identical to the one already being used!
1636 **********************************/
1637 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1638
1639 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1640 if(!object->context) {
1641 ERR("Failed to create the context array\n");
1642 hr = E_OUTOFMEMORY;
1643 goto error;
1644 }
1645 object->num_contexts = 1;
1646
1647 if(surface_type == SURFACE_OPENGL) {
1648 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1649 if (!object->context[0]) {
1650 ERR("Failed to create a new context\n");
1651 hr = WINED3DERR_NOTAVAILABLE;
1652 goto error;
1653 } else {
1654 TRACE("Context created (HWND=%p, glContext=%p)\n",
1655 object->win_handle, object->context[0]->glCtx);
1656 }
1657 }
1658
1659 /*********************
1660 * Create the back, front and stencil buffers
1661 *******************/
1662 if(object->presentParms.BackBufferCount > 0) {
1663 UINT i;
1664
1665 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1666 if(!object->backBuffer) {
1667 ERR("Out of memory\n");
1668 hr = E_OUTOFMEMORY;
1669 goto error;
1670 }
1671
1672 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1673 TRACE("calling rendertarget CB\n");
1674 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1675 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1676 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1677 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1678 if(SUCCEEDED(hr)) {
1679 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1680 } else {
1681 ERR("Cannot create new back buffer\n");
1682 goto error;
1683 }
1684 if(surface_type == SURFACE_OPENGL) {
1685 ENTER_GL();
1686 glDrawBuffer(GL_BACK);
1687 checkGLcall("glDrawBuffer(GL_BACK)");
1688 LEAVE_GL();
1689 }
1690 }
1691 } else {
1692 object->backBuffer = NULL;
1693
1694 /* Single buffering - draw to front buffer */
1695 if(surface_type == SURFACE_OPENGL) {
1696 ENTER_GL();
1697 glDrawBuffer(GL_FRONT);
1698 checkGLcall("glDrawBuffer(GL_FRONT)");
1699 LEAVE_GL();
1700 }
1701 }
1702
1703 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1704 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1705 TRACE("Creating depth stencil buffer\n");
1706 if (This->auto_depth_stencil_buffer == NULL ) {
1707 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1708 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1709 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1710 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1711 &This->auto_depth_stencil_buffer);
1712 if (SUCCEEDED(hr)) {
1713 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1714 } else {
1715 ERR("Failed to create the auto depth stencil\n");
1716 goto error;
1717 }
1718 }
1719 }
1720
1721 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1722
1723 TRACE("Created swapchain %p\n", object);
1724 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1725 return WINED3D_OK;
1726
1727 error:
1728 if (displaymode_set) {
1729 DEVMODEW devmode;
1730 RECT clip_rc;
1731
1732 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1733 ClipCursor(NULL);
1734
1735 /* Change the display settings */
1736 memset(&devmode, 0, sizeof(devmode));
1737 devmode.dmSize = sizeof(devmode);
1738 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1739 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1740 devmode.dmPelsWidth = object->orig_width;
1741 devmode.dmPelsHeight = object->orig_height;
1742 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1743 }
1744
1745 if (object->backBuffer) {
1746 UINT i;
1747 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1748 if(object->backBuffer[i]) {
1749 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1750 IUnknown_Release(bufferParent); /* once for the get parent */
1751 if (IUnknown_Release(bufferParent) > 0) {
1752 FIXME("(%p) Something's still holding the back buffer\n",This);
1753 }
1754 }
1755 }
1756 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1757 object->backBuffer = NULL;
1758 }
1759 if(object->context && object->context[0])
1760 DestroyContext(This, object->context[0]);
1761 if(object->frontBuffer) {
1762 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1763 IUnknown_Release(bufferParent); /* once for the get parent */
1764 if (IUnknown_Release(bufferParent) > 0) {
1765 FIXME("(%p) Something's still holding the front buffer\n",This);
1766 }
1767 }
1768 HeapFree(GetProcessHeap(), 0, object);
1769 return hr;
1770 }
1771
1772 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1773 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1775 TRACE("(%p)\n", This);
1776
1777 return This->NumberOfSwapChains;
1778 }
1779
1780 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1782 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1783
1784 if(iSwapChain < This->NumberOfSwapChains) {
1785 *pSwapChain = This->swapchains[iSwapChain];
1786 IWineD3DSwapChain_AddRef(*pSwapChain);
1787 TRACE("(%p) returning %p\n", This, *pSwapChain);
1788 return WINED3D_OK;
1789 } else {
1790 TRACE("Swapchain out of range\n");
1791 *pSwapChain = NULL;
1792 return WINED3DERR_INVALIDCALL;
1793 }
1794 }
1795
1796 /*****
1797 * Vertex Declaration
1798 *****/
1799 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1800 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1802 IWineD3DVertexDeclarationImpl *object = NULL;
1803 HRESULT hr = WINED3D_OK;
1804
1805 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1806 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1807
1808 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1809 if(!object)
1810 {
1811 ERR("Out of memory\n");
1812 *ppVertexDeclaration = NULL;
1813 return WINED3DERR_OUTOFVIDEOMEMORY;
1814 }
1815
1816 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
1817 object->wineD3DDevice = This;
1818 object->parent = parent;
1819 object->ref = 1;
1820
1821 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1822
1823 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1824 if(FAILED(hr)) {
1825 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1826 *ppVertexDeclaration = NULL;
1827 }
1828
1829 return hr;
1830 }
1831
1832 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1833 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1834
1835 unsigned int idx, idx2;
1836 unsigned int offset;
1837 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1838 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1839 BOOL has_blend_idx = has_blend &&
1840 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1841 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1842 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1843 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1844 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1845 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1846 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1847
1848 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1849 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1850
1851 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1852 WINED3DVERTEXELEMENT *elements = NULL;
1853
1854 unsigned int size;
1855 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1856 if (has_blend_idx) num_blends--;
1857
1858 /* Compute declaration size */
1859 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1860 has_psize + has_diffuse + has_specular + num_textures + 1;
1861
1862 /* convert the declaration */
1863 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1864 if (!elements)
1865 return 0;
1866
1867 elements[size-1] = end_element;
1868 idx = 0;
1869 if (has_pos) {
1870 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1871 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1872 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1873 }
1874 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1875 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1876 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1877 }
1878 else {
1879 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1880 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1881 }
1882 elements[idx].UsageIndex = 0;
1883 idx++;
1884 }
1885 if (has_blend && (num_blends > 0)) {
1886 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1887 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1888 else {
1889 switch(num_blends) {
1890 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
1891 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
1892 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
1893 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
1894 default:
1895 ERR("Unexpected amount of blend values: %u\n", num_blends);
1896 }
1897 }
1898 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1899 elements[idx].UsageIndex = 0;
1900 idx++;
1901 }
1902 if (has_blend_idx) {
1903 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1904 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1905 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1906 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1907 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1908 else
1909 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1910 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1911 elements[idx].UsageIndex = 0;
1912 idx++;
1913 }
1914 if (has_normal) {
1915 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1916 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1917 elements[idx].UsageIndex = 0;
1918 idx++;
1919 }
1920 if (has_psize) {
1921 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1922 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1923 elements[idx].UsageIndex = 0;
1924 idx++;
1925 }
1926 if (has_diffuse) {
1927 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1928 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1929 elements[idx].UsageIndex = 0;
1930 idx++;
1931 }
1932 if (has_specular) {
1933 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1934 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1935 elements[idx].UsageIndex = 1;
1936 idx++;
1937 }
1938 for (idx2 = 0; idx2 < num_textures; idx2++) {
1939 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1940 switch (numcoords) {
1941 case WINED3DFVF_TEXTUREFORMAT1:
1942 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1943 break;
1944 case WINED3DFVF_TEXTUREFORMAT2:
1945 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1946 break;
1947 case WINED3DFVF_TEXTUREFORMAT3:
1948 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1949 break;
1950 case WINED3DFVF_TEXTUREFORMAT4:
1951 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1952 break;
1953 }
1954 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1955 elements[idx].UsageIndex = idx2;
1956 idx++;
1957 }
1958
1959 /* Now compute offsets, and initialize the rest of the fields */
1960 for (idx = 0, offset = 0; idx < size-1; idx++) {
1961 elements[idx].Stream = 0;
1962 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1963 elements[idx].Offset = offset;
1964 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1965 }
1966
1967 *ppVertexElements = elements;
1968 return size;
1969 }
1970
1971 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1972 WINED3DVERTEXELEMENT* elements = NULL;
1973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1974 unsigned int size;
1975 DWORD hr;
1976
1977 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1978 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1979
1980 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1981 HeapFree(GetProcessHeap(), 0, elements);
1982 if (hr != S_OK) return hr;
1983
1984 return WINED3D_OK;
1985 }
1986
1987 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1989 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1990 HRESULT hr = WINED3D_OK;
1991
1992 if (!pFunction) return WINED3DERR_INVALIDCALL;
1993
1994 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1995 if (!object)
1996 {
1997 ERR("Out of memory\n");
1998 *ppVertexShader = NULL;
1999 return WINED3DERR_OUTOFVIDEOMEMORY;
2000 }
2001
2002 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
2003 object->parent = parent;
2004 shader_init(&object->baseShader, iface, IWineD3DVertexShaderImpl_shader_ins);
2005 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2006 *ppVertexShader = (IWineD3DVertexShader *)object;
2007
2008 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
2009
2010 if (vertex_declaration) {
2011 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
2012 }
2013
2014 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
2015 if (FAILED(hr))
2016 {
2017 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2018 IWineD3DVertexShader_Release(*ppVertexShader);
2019 *ppVertexShader = NULL;
2020 return hr;
2021 }
2022
2023 return hr;
2024 }
2025
2026 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
2027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2028 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2029 HRESULT hr = WINED3D_OK;
2030
2031 if (!pFunction) return WINED3DERR_INVALIDCALL;
2032
2033 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2034 if (!object)
2035 {
2036 ERR("Out of memory\n");
2037 *ppPixelShader = NULL;
2038 return WINED3DERR_OUTOFVIDEOMEMORY;
2039 }
2040
2041 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2042 object->parent = parent;
2043 shader_init(&object->baseShader, iface, IWineD3DPixelShaderImpl_shader_ins);
2044 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2045 *ppPixelShader = (IWineD3DPixelShader *)object;
2046
2047 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2048
2049 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
2050 if (FAILED(hr))
2051 {
2052 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2053 IWineD3DPixelShader_Release(*ppPixelShader);
2054 *ppPixelShader = NULL;
2055 return hr;
2056 }
2057
2058 return hr;
2059 }
2060
2061 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2062 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2063 {
2064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2065 IWineD3DPaletteImpl *object;
2066 HRESULT hr;
2067 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2068
2069 /* Create the new object */
2070 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2071 if(!object) {
2072 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2073 return E_OUTOFMEMORY;
2074 }
2075
2076 object->lpVtbl = &IWineD3DPalette_Vtbl;
2077 object->ref = 1;
2078 object->Flags = Flags;
2079 object->parent = Parent;
2080 object->wineD3DDevice = This;
2081 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2082 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2083
2084 if(!object->hpal) {
2085 HeapFree( GetProcessHeap(), 0, object);
2086 return E_OUTOFMEMORY;
2087 }
2088
2089 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2090 if(FAILED(hr)) {
2091 IWineD3DPalette_Release((IWineD3DPalette *) object);
2092 return hr;
2093 }
2094
2095 *Palette = (IWineD3DPalette *) object;
2096
2097 return WINED3D_OK;
2098 }
2099
2100 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2101 HBITMAP hbm;
2102 BITMAP bm;
2103 HRESULT hr;
2104 HDC dcb = NULL, dcs = NULL;
2105 WINEDDCOLORKEY colorkey;
2106
2107 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2108 if(hbm)
2109 {
2110 GetObjectA(hbm, sizeof(BITMAP), &bm);
2111 dcb = CreateCompatibleDC(NULL);
2112 if(!dcb) goto out;
2113 SelectObject(dcb, hbm);
2114 }
2115 else
2116 {
2117 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2118 * couldn't be loaded
2119 */
2120 memset(&bm, 0, sizeof(bm));
2121 bm.bmWidth = 32;
2122 bm.bmHeight = 32;
2123 }
2124
2125 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2126 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2127 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
2128 if(FAILED(hr)) {
2129 ERR("Wine logo requested, but failed to create surface\n");
2130 goto out;
2131 }
2132
2133 if(dcb) {
2134 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2135 if(FAILED(hr)) goto out;
2136 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2137 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2138
2139 colorkey.dwColorSpaceLowValue = 0;
2140 colorkey.dwColorSpaceHighValue = 0;
2141 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2142 } else {
2143 /* Fill the surface with a white color to show that wined3d is there */
2144 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2145 }
2146
2147 out:
2148 if(dcb) {
2149 DeleteDC(dcb);
2150 }
2151 if(hbm) {
2152 DeleteObject(hbm);
2153 }
2154 return;
2155 }
2156
2157 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2158 unsigned int i;
2159 /* Under DirectX you can have texture stage operations even if no texture is
2160 bound, whereas opengl will only do texture operations when a valid texture is
2161 bound. We emulate this by creating dummy textures and binding them to each
2162 texture stage, but disable all stages by default. Hence if a stage is enabled
2163 then the default texture will kick in until replaced by a SetTexture call */
2164 ENTER_GL();
2165
2166 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2167 /* The dummy texture does not have client storage backing */
2168 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2169 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2170 }
2171 for (i = 0; i < GL_LIMITS(textures); i++) {
2172 GLubyte white = 255;
2173
2174 /* Make appropriate texture active */
2175 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2176 checkGLcall("glActiveTextureARB");
2177
2178 /* Generate an opengl texture name */
2179 glGenTextures(1, &This->dummyTextureName[i]);
2180 checkGLcall("glGenTextures");
2181 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2182
2183 /* Generate a dummy 2d texture (not using 1d because they cause many
2184 * DRI drivers fall back to sw) */
2185 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2186 checkGLcall("glBindTexture");
2187
2188 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2189 checkGLcall("glTexImage2D");
2190 }
2191 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2192 /* Reenable because if supported it is enabled by default */
2193 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2194 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2195 }
2196
2197 LEAVE_GL();
2198 }
2199
2200 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2201 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2202 {
2203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2204 IWineD3DSwapChainImpl *swapchain = NULL;
2205 HRESULT hr;
2206 DWORD state;
2207 unsigned int i;
2208
2209 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2210
2211 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2212 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2213
2214 /* TODO: Test if OpenGL is compiled in and loaded */
2215
2216 TRACE("(%p) : Creating stateblock\n", This);
2217 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2218 hr = IWineD3DDevice_CreateStateBlock(iface,
2219 WINED3DSBT_INIT,
2220 (IWineD3DStateBlock **)&This->stateBlock,
2221 NULL);
2222 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2223 WARN("Failed to create stateblock\n");
2224 goto err_out;
2225 }
2226 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2227 This->updateStateBlock = This->stateBlock;
2228 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2229
2230 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2231 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2232
2233 This->NumberOfPalettes = 1;
2234 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2235 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2236 ERR("Out of memory!\n");
2237 goto err_out;
2238 }
2239 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2240 if(!This->palettes[0]) {
2241 ERR("Out of memory!\n");
2242 goto err_out;
2243 }
2244 for (i = 0; i < 256; ++i) {
2245 This->palettes[0][i].peRed = 0xFF;
2246 This->palettes[0][i].peGreen = 0xFF;
2247 This->palettes[0][i].peBlue = 0xFF;
2248 This->palettes[0][i].peFlags = 0xFF;
2249 }
2250 This->currentPalette = 0;
2251
2252 /* Initialize the texture unit mapping to a 1:1 mapping */
2253 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2254 if (state < GL_LIMITS(fragment_samplers)) {
2255 This->texUnitMap[state] = state;
2256 This->rev_tex_unit_map[state] = state;
2257 } else {
2258 This->texUnitMap[state] = -1;
2259 This->rev_tex_unit_map[state] = -1;
2260 }
2261 }
2262
2263 /* Setup the implicit swapchain */
2264 TRACE("Creating implicit swapchain\n");
2265 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2266 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2267 if (FAILED(hr))
2268 {
2269 WARN("Failed to create implicit swapchain\n");
2270 goto err_out;
2271 }
2272
2273 This->NumberOfSwapChains = 1;
2274 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2275 if(!This->swapchains) {
2276 ERR("Out of memory!\n");
2277 goto err_out;
2278 }
2279 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2280
2281 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2282 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2283 This->render_targets[0] = swapchain->backBuffer[0];
2284 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2285 }
2286 else {
2287 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2288 This->render_targets[0] = swapchain->frontBuffer;
2289 This->lastActiveRenderTarget = swapchain->frontBuffer;
2290 }
2291 IWineD3DSurface_AddRef(This->render_targets[0]);
2292 This->activeContext = swapchain->context[0];
2293 This->lastThread = GetCurrentThreadId();
2294
2295 /* Depth Stencil support */
2296 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2297 if (NULL != This->stencilBufferTarget) {
2298 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2299 }
2300
2301 hr = This->shader_backend->shader_alloc_private(iface);
2302 if(FAILED(hr)) {
2303 TRACE("Shader private data couldn't be allocated\n");
2304 goto err_out;
2305 }
2306 hr = This->frag_pipe->alloc_private(iface);
2307 if(FAILED(hr)) {
2308 TRACE("Fragment pipeline private data couldn't be allocated\n");
2309 goto err_out;
2310 }
2311 hr = This->blitter->alloc_private(iface);
2312 if(FAILED(hr)) {
2313 TRACE("Blitter private data couldn't be allocated\n");
2314 goto err_out;
2315 }
2316
2317 /* Set up some starting GL setup */
2318
2319 /* Setup all the devices defaults */
2320 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2321 create_dummy_textures(This);
2322
2323 ENTER_GL();
2324
2325 /* Initialize the current view state */
2326 This->view_ident = 1;
2327 This->contexts[0]->last_was_rhw = 0;
2328 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2329 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2330
2331 switch(wined3d_settings.offscreen_rendering_mode) {
2332 case ORM_FBO:
2333 case ORM_PBUFFER:
2334 This->offscreenBuffer = GL_BACK;
2335 break;
2336
2337 case ORM_BACKBUFFER:
2338 {
2339 if(This->activeContext->aux_buffers > 0) {
2340 TRACE("Using auxilliary buffer for offscreen rendering\n");
2341 This->offscreenBuffer = GL_AUX0;
2342 } else {
2343 TRACE("Using back buffer for offscreen rendering\n");
2344 This->offscreenBuffer = GL_BACK;
2345 }
2346 }
2347 }
2348
2349 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2350 LEAVE_GL();
2351
2352 /* Clear the screen */
2353 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2354 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2355 0x00, 1.0, 0);
2356
2357 This->d3d_initialized = TRUE;
2358
2359 if(wined3d_settings.logo) {
2360 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2361 }
2362 This->highest_dirty_ps_const = 0;
2363 This->highest_dirty_vs_const = 0;
2364 return WINED3D_OK;
2365
2366 err_out:
2367 HeapFree(GetProcessHeap(), 0, This->render_targets);
2368 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2369 HeapFree(GetProcessHeap(), 0, This->swapchains);
2370 This->NumberOfSwapChains = 0;
2371 if(This->palettes) {
2372 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2373 HeapFree(GetProcessHeap(), 0, This->palettes);
2374 }
2375 This->NumberOfPalettes = 0;
2376 if(swapchain) {
2377 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2378 }
2379 if(This->stateBlock) {
2380 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2381 This->stateBlock = NULL;
2382 }
2383 if (This->blit_priv) {
2384 This->blitter->free_private(iface);
2385 }
2386 if (This->fragment_priv) {
2387 This->frag_pipe->free_private(iface);
2388 }
2389 if (This->shader_priv) {
2390 This->shader_backend->shader_free_private(iface);
2391 }
2392 return hr;
2393 }
2394
2395 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2396 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2397 {
2398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2399 IWineD3DSwapChainImpl *swapchain = NULL;
2400 HRESULT hr;
2401
2402 /* Setup the implicit swapchain */
2403 TRACE("Creating implicit swapchain\n");
2404 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2405 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2406 if (FAILED(hr))
2407 {
2408 WARN("Failed to create implicit swapchain\n");
2409 goto err_out;
2410 }
2411
2412 This->NumberOfSwapChains = 1;
2413 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2414 if(!This->swapchains) {
2415 ERR("Out of memory!\n");
2416 goto err_out;
2417 }
2418 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2419 return WINED3D_OK;
2420
2421 err_out:
2422 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2423 return hr;
2424 }
2425
2426 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2428 int sampler;
2429 UINT i;
2430 TRACE("(%p)\n", This);
2431
2432 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2433
2434 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2435 * it was created. Thus make sure a context is active for the glDelete* calls
2436 */
2437 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2438
2439 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2440
2441 TRACE("Deleting high order patches\n");
2442 for(i = 0; i < PATCHMAP_SIZE; i++) {
2443 struct list *e1, *e2;
2444 struct WineD3DRectPatch *patch;
2445 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2446 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2447 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2448 }
2449 }
2450
2451 /* Delete the palette conversion shader if it is around */
2452 if(This->paletteConversionShader) {
2453 ENTER_GL();
2454 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2455 LEAVE_GL();
2456 This->paletteConversionShader = 0;
2457 }
2458
2459 /* Delete the pbuffer context if there is any */
2460 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2461
2462 /* Delete the mouse cursor texture */
2463 if(This->cursorTexture) {
2464 ENTER_GL();
2465 glDeleteTextures(1, &This->cursorTexture);
2466 LEAVE_GL();
2467 This->cursorTexture = 0;
2468 }
2469
2470 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2471 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2472 }
2473 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2474 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2475 }
2476
2477 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2478 * private data, it might contain opengl pointers
2479 */
2480 if(This->depth_blt_texture) {
2481 glDeleteTextures(1, &This->depth_blt_texture);
2482 This->depth_blt_texture = 0;
2483 }
2484 if (This->depth_blt_rb) {
2485 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2486 This->depth_blt_rb = 0;
2487 This->depth_blt_rb_w = 0;
2488 This->depth_blt_rb_h = 0;
2489 }
2490
2491 /* Release the update stateblock */
2492 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2493 if(This->updateStateBlock != This->stateBlock)
2494 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2495 }
2496 This->updateStateBlock = NULL;
2497
2498 { /* because were not doing proper internal refcounts releasing the primary state block
2499 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2500 to set this->stateBlock = NULL; first */
2501 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2502 This->stateBlock = NULL;
2503
2504 /* Release the stateblock */
2505 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2506 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2507 }
2508 }
2509
2510 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2511 This->blitter->free_private(iface);
2512 This->frag_pipe->free_private(iface);
2513 This->shader_backend->shader_free_private(iface);
2514
2515 /* Release the buffers (with sanity checks)*/
2516 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2517 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2518 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2519 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2520 }
2521 This->stencilBufferTarget = NULL;
2522
2523 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2524 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2525 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2526 }
2527 TRACE("Setting rendertarget to NULL\n");
2528 This->render_targets[0] = NULL;
2529
2530 if (This->auto_depth_stencil_buffer) {
2531 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2532 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2533 }
2534 This->auto_depth_stencil_buffer = NULL;
2535 }
2536
2537 for(i=0; i < This->NumberOfSwapChains; i++) {
2538 TRACE("Releasing the implicit swapchain %d\n", i);
2539 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2540 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2541 }
2542 }
2543
2544 HeapFree(GetProcessHeap(), 0, This->swapchains);
2545 This->swapchains = NULL;
2546 This->NumberOfSwapChains = 0;
2547
2548 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2549 HeapFree(GetProcessHeap(), 0, This->palettes);
2550 This->palettes = NULL;
2551 This->NumberOfPalettes = 0;
2552
2553 HeapFree(GetProcessHeap(), 0, This->render_targets);
2554 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2555 This->render_targets = NULL;
2556 This->draw_buffers = NULL;
2557
2558 This->d3d_initialized = FALSE;
2559 return WINED3D_OK;
2560 }
2561
2562 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2564 unsigned int i;
2565
2566 for(i=0; i < This->NumberOfSwapChains; i++) {
2567 TRACE("Releasing the implicit swapchain %d\n", i);
2568 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2569 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2570 }
2571 }
2572
2573 HeapFree(GetProcessHeap(), 0, This->swapchains);
2574 This->swapchains = NULL;
2575 This->NumberOfSwapChains = 0;
2576 return WINED3D_OK;
2577 }
2578
2579 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2580 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2581 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2582 *
2583 * There is no way to deactivate thread safety once it is enabled.
2584 */
2585 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2587
2588 /*For now just store the flag(needed in case of ddraw) */
2589 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2590
2591 return;
2592 }
2593
2594 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2595 const WINED3DDISPLAYMODE* pMode) {
2596 DEVMODEW devmode;
2597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2598 LONG ret;
2599 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2600 RECT clip_rc;
2601
2602 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2603
2604 /* Resize the screen even without a window:
2605 * The app could have unset it with SetCooperativeLevel, but not called
2606 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2607 * but we don't have any hwnd
2608 */
2609
2610 memset(&devmode, 0, sizeof(devmode));
2611 devmode.dmSize = sizeof(devmode);
2612 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2613 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2614 devmode.dmPelsWidth = pMode->Width;
2615 devmode.dmPelsHeight = pMode->Height;
2616
2617 devmode.dmDisplayFrequency = pMode->RefreshRate;
2618 if (pMode->RefreshRate != 0) {
2619 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2620 }
2621
2622 /* Only change the mode if necessary */
2623 if( (This->ddraw_width == pMode->Width) &&
2624 (This->ddraw_height == pMode->Height) &&
2625 (This->ddraw_format == pMode->Format) &&
2626 (pMode->RefreshRate == 0) ) {
2627 return WINED3D_OK;
2628 }
2629
2630 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2631 if (ret != DISP_CHANGE_SUCCESSFUL) {
2632 if(devmode.dmDisplayFrequency != 0) {
2633 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2634 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2635 devmode.dmDisplayFrequency = 0;
2636 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2637 }
2638 if(ret != DISP_CHANGE_SUCCESSFUL) {
2639 return WINED3DERR_NOTAVAILABLE;
2640 }
2641 }
2642
2643 /* Store the new values */
2644 This->ddraw_width = pMode->Width;
2645 This->ddraw_height = pMode->Height;
2646 This->ddraw_format = pMode->Format;
2647
2648 /* And finally clip mouse to our screen */
2649 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2650 ClipCursor(&clip_rc);
2651
2652 return WINED3D_OK;
2653 }
2654
2655 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2657 *ppD3D= This->wineD3D;
2658 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2659 IWineD3D_AddRef(*ppD3D);
2660 return WINED3D_OK;
2661 }
2662
2663 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2665
2666 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2667 (This->adapter->TextureRam/(1024*1024)),
2668 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2669 /* return simulated texture memory left */
2670 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2671 }
2672
2673 /*****
2674 * Get / Set Stream Source
2675 *****/
2676 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2678 IWineD3DVertexBuffer *oldSrc;
2679
2680 if (StreamNumber >= MAX_STREAMS) {
2681 WARN("Stream out of range %d\n", StreamNumber);
2682 return WINED3DERR_INVALIDCALL;
2683 } else if(OffsetInBytes & 0x3) {
2684 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2685 return WINED3DERR_INVALIDCALL;
2686 }
2687
2688 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2689 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2690
2691 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2692
2693 if(oldSrc == pStreamData &&
2694 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2695 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2696 TRACE("Application is setting the old values over, nothing to do\n");
2697 return WINED3D_OK;
2698 }
2699
2700 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2701 if (pStreamData) {
2702 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2703 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2704 }
2705
2706 /* Handle recording of state blocks */
2707 if (This->isRecordingState) {
2708 TRACE("Recording... not performing anything\n");
2709 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2710 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2711 return WINED3D_OK;
2712 }
2713
2714 if (pStreamData != NULL) {
2715 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2716 InterlockedIncrement(&vbImpl->bindCount);
2717 IWineD3DVertexBuffer_AddRef(pStreamData);
2718 }
2719 if (oldSrc != NULL) {
2720 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2721 IWineD3DVertexBuffer_Release(oldSrc);
2722 }
2723
2724 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2725
2726 return WINED3D_OK;
2727 }
2728
2729 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2731
2732 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2733 This->stateBlock->streamSource[StreamNumber],
2734 This->stateBlock->streamOffset[StreamNumber],
2735 This->stateBlock->streamStride[StreamNumber]);
2736
2737 if (StreamNumber >= MAX_STREAMS) {
2738 WARN("Stream out of range %d\n", StreamNumber);
2739 return WINED3DERR_INVALIDCALL;
2740 }
2741 *pStream = This->stateBlock->streamSource[StreamNumber];
2742 *pStride = This->stateBlock->streamStride[StreamNumber];
2743 if (pOffset) {
2744 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2745 }
2746
2747 if (*pStream != NULL) {
2748 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2749 }
2750 return WINED3D_OK;
2751 }
2752
2753 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2755 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2756 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2757
2758 /* Verify input at least in d3d9 this is invalid*/
2759 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2760 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2761 return WINED3DERR_INVALIDCALL;
2762 }
2763 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2764 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2765 return WINED3DERR_INVALIDCALL;
2766 }
2767 if( Divider == 0 ){
2768 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2769 return WINED3DERR_INVALIDCALL;
2770 }
2771
2772 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2773 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2774
2775 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2776 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2777
2778 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2779 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2780 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2781 }
2782
2783 return WINED3D_OK;
2784 }
2785
2786 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2788
2789 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2790 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2791
2792 TRACE("(%p) : returning %d\n", This, *Divider);
2793
2794 return WINED3D_OK;
2795 }
2796
2797 /*****
2798 * Get / Set & Multiply Transform
2799 *****/
2800 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2802
2803 /* Most of this routine, comments included copied from ddraw tree initially: */
2804 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2805
2806 /* Handle recording of state blocks */
2807 if (This->isRecordingState) {
2808 TRACE("Recording... not performing anything\n");
2809 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2810 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2811 return WINED3D_OK;
2812 }
2813
2814 /*
2815 * If the new matrix is the same as the current one,
2816 * we cut off any further processing. this seems to be a reasonable
2817 * optimization because as was noticed, some apps (warcraft3 for example)
2818 * tend towards setting the same matrix repeatedly for some reason.
2819 *
2820 * From here on we assume that the new matrix is different, wherever it matters.
2821 */
2822 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2823 TRACE("The app is setting the same matrix over again\n");
2824 return WINED3D_OK;
2825 } else {
2826 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2827 }
2828
2829 /*
2830 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2831 where ViewMat = Camera space, WorldMat = world space.
2832
2833 In OpenGL, camera and world space is combined into GL_MODELVIEW
2834 matrix. The Projection matrix stay projection matrix.
2835 */
2836
2837 /* Capture the times we can just ignore the change for now */
2838 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2839 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2840 /* Handled by the state manager */
2841 }
2842
2843 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2844 return WINED3D_OK;
2845
2846 }
2847 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2849 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2850 *pMatrix = This->stateBlock->transforms[State];
2851 return WINED3D_OK;
2852 }
2853
2854 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2855 const WINED3DMATRIX *mat = NULL;
2856 WINED3DMATRIX temp;
2857
2858 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2859 * below means it will be recorded in a state block change, but it
2860 * works regardless where it is recorded.
2861 * If this is found to be wrong, change to StateBlock.
2862 */
2863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2864 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2865
2866 if (State <= HIGHEST_TRANSFORMSTATE)
2867 {
2868 mat = &This->updateStateBlock->transforms[State];
2869 } else {
2870 FIXME("Unhandled transform state!!\n");
2871 }
2872
2873 multiply_matrix(&temp, mat, pMatrix);
2874
2875 /* Apply change via set transform - will reapply to eg. lights this way */
2876 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2877 }
2878
2879 /*****
2880 * Get / Set Light
2881 *****/
2882 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2883 you can reference any indexes you want as long as that number max are enabled at any
2884 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2885 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2886 but when recording, just build a chain pretty much of commands to be replayed. */
2887
2888 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2889 float rho;
2890 PLIGHTINFOEL *object = NULL;
2891 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2892 struct list *e;
2893
2894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2895 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2896
2897 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2898 * the gl driver.
2899 */
2900 if(!pLight) {
2901 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2902 return WINED3DERR_INVALIDCALL;
2903 }
2904
2905 switch(pLight->Type) {
2906 case WINED3DLIGHT_POINT:
2907 case WINED3DLIGHT_SPOT:
2908 case WINED3DLIGHT_PARALLELPOINT:
2909 case WINED3DLIGHT_GLSPOT:
2910 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2911 * most wanted
2912 */
2913 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2914 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2915 return WINED3DERR_INVALIDCALL;
2916 }
2917 break;
2918
2919 case WINED3DLIGHT_DIRECTIONAL:
2920 /* Ignores attenuation */
2921 break;
2922
2923 default:
2924 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2925 return WINED3DERR_INVALIDCALL;
2926 }
2927
2928 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2929 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2930 if(object->OriginalIndex == Index) break;
2931 object = NULL;
2932 }
2933
2934 if(!object) {
2935 TRACE("Adding new light\n");
2936 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2937 if(!object) {
2938 ERR("Out of memory error when allocating a light\n");
2939 return E_OUTOFMEMORY;
2940 }
2941 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2942 object->glIndex = -1;
2943 object->OriginalIndex = Index;
2944 object->changed = TRUE;
2945 }
2946
2947 /* Initialize the object */
2948 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,
2949 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2950 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2951 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2952 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2953 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2954 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2955
2956 /* Save away the information */
2957 object->OriginalParms = *pLight;
2958
2959 switch (pLight->Type) {
2960 case WINED3DLIGHT_POINT:
2961 /* Position */
2962 object->lightPosn[0] = pLight->Position.x;
2963 object->lightPosn[1] = pLight->Position.y;
2964 object->lightPosn[2] = pLight->Position.z;
2965 object->lightPosn[3] = 1.0f;
2966 object->cutoff = 180.0f;
2967 /* FIXME: Range */
2968 break;
2969
2970 case WINED3DLIGHT_DIRECTIONAL:
2971 /* Direction */
2972 object->lightPosn[0] = -pLight->Direction.x;
2973 object->lightPosn[1] = -pLight->Direction.y;
2974 object->lightPosn[2] = -pLight->Direction.z;
2975 object->lightPosn[3] = 0.0;
2976 object->exponent = 0.0f;
2977 object->cutoff = 180.0f;
2978 break;
2979
2980 case WINED3DLIGHT_SPOT:
2981 /* Position */
2982 object->lightPosn[0] = pLight->Position.x;
2983 object->lightPosn[1] = pLight->Position.y;
2984 object->lightPosn[2] = pLight->Position.z;
2985 object->lightPosn[3] = 1.0;
2986
2987 /* Direction */
2988 object->lightDirn[0] = pLight->Direction.x;
2989 object->lightDirn[1] = pLight->Direction.y;
2990 object->lightDirn[2] = pLight->Direction.z;
2991 object->lightDirn[3] = 1.0;
2992
2993 /*
2994 * opengl-ish and d3d-ish spot lights use too different models for the
2995 * light "intensity" as a function of the angle towards the main light direction,
2996 * so we only can approximate very roughly.
2997 * however spot lights are rather rarely used in games (if ever used at all).
2998 * furthermore if still used, probably nobody pays attention to such details.
2999 */
3000 if (pLight->Falloff == 0) {
3001 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3002 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3003 * will always be 1.0 for both of them, and we don't have to care for the
3004 * rest of the rather complex calculation
3005 */
3006 object->exponent = 0;
3007 } else {
3008 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3009 if (rho < 0.0001) rho = 0.0001f;
3010 object->exponent = -0.3/log(cos(rho/2));
3011 }
3012 if (object->exponent > 128.0) {
3013 object->exponent = 128.0;
3014 }
3015 object->cutoff = pLight->Phi*90/M_PI;
3016
3017 /* FIXME: Range */
3018 break;
3019
3020 default:
3021 FIXME("Unrecognized light type %d\n", pLight->Type);
3022 }
3023
3024 /* Update the live definitions if the light is currently assigned a glIndex */
3025 if (object->glIndex != -1 && !This->isRecordingState) {
3026 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3027 }
3028 return WINED3D_OK;
3029 }
3030
3031 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3032 PLIGHTINFOEL *lightInfo = NULL;
3033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3034 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3035 struct list *e;
3036 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3037
3038 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3039 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3040 if(lightInfo->OriginalIndex == Index) break;
3041 lightInfo = NULL;
3042 }
3043
3044 if (lightInfo == NULL) {
3045 TRACE("Light information requested but light not defined\n");
3046 return WINED3DERR_INVALIDCALL;
3047 }
3048
3049 *pLight = lightInfo->OriginalParms;
3050 return WINED3D_OK;
3051 }
3052
3053 /*****
3054 * Get / Set Light Enable
3055 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3056 *****/
3057 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3058 PLIGHTINFOEL *lightInfo = NULL;
3059 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3060 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3061 struct list *e;
3062 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3063
3064 /* Tests show true = 128...not clear why */
3065 Enable = Enable? 128: 0;
3066
3067 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3068 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3069 if(lightInfo->OriginalIndex == Index) break;
3070 lightInfo = NULL;
3071 }
3072 TRACE("Found light: %p\n", lightInfo);
3073
3074 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3075 if (lightInfo == NULL) {
3076
3077 TRACE("Light enabled requested but light not defined, so defining one!\n");
3078 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3079
3080 /* Search for it again! Should be fairly quick as near head of list */
3081 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3082 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3083 if(lightInfo->OriginalIndex == Index) break;
3084 lightInfo = NULL;
3085 }
3086 if (lightInfo == NULL) {
3087 FIXME("Adding default lights has failed dismally\n");
3088 return WINED3DERR_INVALIDCALL;
3089 }
3090 }
3091
3092 lightInfo->enabledChanged = TRUE;
3093 if(!Enable) {
3094 if(lightInfo->glIndex != -1) {
3095 if(!This->isRecordingState) {
3096 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3097 }
3098
3099 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3100 lightInfo->glIndex = -1;
3101 } else {
3102 TRACE("Light already disabled, nothing to do\n");
3103 }
3104 lightInfo->enabled = FALSE;
3105 } else {
3106 lightInfo->enabled = TRUE;
3107 if (lightInfo->glIndex != -1) {
3108 /* nop */
3109 TRACE("Nothing to do as light was enabled\n");
3110 } else {
3111 int i;
3112 /* Find a free gl light */
3113 for(i = 0; i < This->maxConcurrentLights; i++) {
3114 if(This->updateStateBlock->activeLights[i] == NULL) {
3115 This->updateStateBlock->activeLights[i] = lightInfo;
3116 lightInfo->glIndex = i;
3117 break;
3118 }
3119 }
3120 if(lightInfo->glIndex == -1) {
3121 /* Our tests show that Windows returns D3D_OK in this situation, even with
3122 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3123 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3124 * as well for those lights.
3125 *
3126 * TODO: Test how this affects rendering
3127 */
3128 WARN("Too many concurrently active lights\n");
3129 return WINED3D_OK;
3130 }
3131
3132 /* i == lightInfo->glIndex */
3133 if(!This->isRecordingState) {
3134 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3135 }
3136 }
3137 }
3138
3139 return WINED3D_OK;
3140 }
3141
3142 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3143
3144 PLIGHTINFOEL *lightInfo = NULL;
3145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3146 struct list *e;
3147 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3148 TRACE("(%p) : for idx(%d)\n", This, Index);
3149
3150 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3151 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3152 if(lightInfo->OriginalIndex == Index) break;
3153 lightInfo = NULL;
3154 }
3155
3156 if (lightInfo == NULL) {
3157 TRACE("Light enabled state requested but light not defined\n");
3158 return WINED3DERR_INVALIDCALL;
3159 }
3160 /* true is 128 according to SetLightEnable */
3161 *pEnable = lightInfo->enabled ? 128 : 0;
3162 return WINED3D_OK;
3163 }
3164
3165 /*****
3166 * Get / Set Clip Planes
3167 *****/
3168 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3170 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3171
3172 /* Validate Index */
3173 if (Index >= GL_LIMITS(clipplanes)) {
3174 TRACE("Application has requested clipplane this device doesn't support\n");
3175 return WINED3DERR_INVALIDCALL;
3176 }
3177
3178 This->updateStateBlock->changed.clipplane |= 1 << Index;
3179
3180 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3181 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3182 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3183 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3184 TRACE("Application is setting old values over, nothing to do\n");
3185 return WINED3D_OK;
3186 }
3187
3188 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3189 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3190 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3191 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3192
3193 /* Handle recording of state blocks */
3194 if (This->isRecordingState) {
3195 TRACE("Recording... not performing anything\n");
3196 return WINED3D_OK;
3197 }
3198
3199 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3200
3201 return WINED3D_OK;
3202 }
3203
3204 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3206 TRACE("(%p) : for idx %d\n", This, Index);
3207
3208 /* Validate Index */
3209 if (Index >= GL_LIMITS(clipplanes)) {
3210 TRACE("Application has requested clipplane this device doesn't support\n");
3211 return WINED3DERR_INVALIDCALL;
3212 }
3213
3214 pPlane[0] = This->stateBlock->clipplane[Index][0];
3215 pPlane[1] = This->stateBlock->clipplane[Index][1];
3216 pPlane[2] = This->stateBlock->clipplane[Index][2];
3217 pPlane[3] = This->stateBlock->clipplane[Index][3];
3218 return WINED3D_OK;
3219 }
3220
3221 /*****
3222 * Get / Set Clip Plane Status
3223 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3224 *****/
3225 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3227 FIXME("(%p) : stub\n", This);
3228 if (NULL == pClipStatus) {
3229 return WINED3DERR_INVALIDCALL;
3230 }
3231 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3232 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3233 return WINED3D_OK;
3234 }
3235
3236 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3238 FIXME("(%p) : stub\n", This);
3239 if (NULL == pClipStatus) {
3240 return WINED3DERR_INVALIDCALL;
3241 }
3242 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3243 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3244 return WINED3D_OK;
3245 }
3246
3247 /*****
3248 * Get / Set Material
3249 *****/
3250 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3252
3253 This->updateStateBlock->changed.material = TRUE;
3254 This->updateStateBlock->material = *pMaterial;
3255
3256 /* Handle recording of state blocks */
3257 if (This->isRecordingState) {
3258 TRACE("Recording... not performing anything\n");
3259 return WINED3D_OK;
3260 }
3261
3262 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3263 return WINED3D_OK;
3264 }
3265
3266 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3268 *pMaterial = This->updateStateBlock->material;
3269 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3270 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3271 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3272 pMaterial->Ambient.b, pMaterial->Ambient.a);
3273 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3274 pMaterial->Specular.b, pMaterial->Specular.a);
3275 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3276 pMaterial->Emissive.b, pMaterial->Emissive.a);
3277 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3278
3279 return WINED3D_OK;
3280 }
3281
3282 /*****
3283 * Get / Set Indices
3284 *****/
3285 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3287 IWineD3DIndexBuffer *oldIdxs;
3288
3289 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3290 oldIdxs = This->updateStateBlock->pIndexData;
3291
3292 This->updateStateBlock->changed.indices = TRUE;
3293 This->updateStateBlock->pIndexData = pIndexData;
3294
3295 /* Handle recording of state blocks */
3296 if (This->isRecordingState) {
3297 TRACE("Recording... not performing anything\n");
3298 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3299 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3300 return WINED3D_OK;
3301 }
3302
3303 if(oldIdxs != pIndexData) {
3304 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3305 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3306 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3307 }
3308 return WINED3D_OK;
3309 }
3310
3311 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3313
3314 *ppIndexData = This->stateBlock->pIndexData;
3315
3316 /* up ref count on ppindexdata */
3317 if (*ppIndexData) {
3318 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3319 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3320 }else{
3321 TRACE("(%p) No index data set\n", This);
3322 }
3323 TRACE("Returning %p\n", *ppIndexData);
3324
3325 return WINED3D_OK;
3326 }
3327
3328 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3329 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3331 TRACE("(%p)->(%d)\n", This, BaseIndex);
3332
3333 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3334 TRACE("Application is setting the old value over, nothing to do\n");
3335 return WINED3D_OK;
3336 }
3337
3338 This->updateStateBlock->baseVertexIndex = BaseIndex;
3339
3340 if (This->isRecordingState) {
3341 TRACE("Recording... not performing anything\n");
3342 return WINED3D_OK;
3343 }
3344 /* The base vertex index affects the stream sources */
3345 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3346 return WINED3D_OK;
3347 }
3348
3349 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3351 TRACE("(%p) : base_index %p\n", This, base_index);
3352
3353 *base_index = This->stateBlock->baseVertexIndex;
3354
3355 TRACE("Returning %u\n", *base_index);
3356
3357 return WINED3D_OK;
3358 }
3359
3360 /*****
3361 * Get / Set Viewports
3362 *****/
3363 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3365
3366 TRACE("(%p)\n", This);
3367 This->updateStateBlock->changed.viewport = TRUE;
3368 This->updateStateBlock->viewport = *pViewport;
3369
3370 /* Handle recording of state blocks */
3371 if (This->isRecordingState) {
3372 TRACE("Recording... not performing anything\n");
3373 return WINED3D_OK;
3374 }
3375
3376 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3377 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3378
3379 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3380 return WINED3D_OK;
3381
3382 }
3383
3384 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3386 TRACE("(%p)\n", This);
3387 *pViewport = This->stateBlock->viewport;
3388 return WINED3D_OK;
3389 }
3390
3391 /*****
3392 * Get / Set Render States
3393 * TODO: Verify against dx9 definitions
3394 *****/
3395 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3396
3397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3398 DWORD oldValue = This->stateBlock->renderState[State];
3399
3400 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3401
3402 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3403 This->updateStateBlock->renderState[State] = Value;
3404
3405 /* Handle recording of state blocks */
3406 if (This->isRecordingState) {
3407 TRACE("Recording... not performing anything\n");
3408 return WINED3D_OK;
3409 }
3410
3411 /* Compared here and not before the assignment to allow proper stateblock recording */
3412 if(Value == oldValue) {
3413 TRACE("Application is setting the old value over, nothing to do\n");
3414 } else {
3415 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3416 }
3417
3418 return WINED3D_OK;
3419 }
3420
3421 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3423 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3424 *pValue = This->stateBlock->renderState[State];
3425 return WINED3D_OK;
3426 }
3427
3428 /*****
3429 * Get / Set Sampler States
3430 * TODO: Verify against dx9 definitions
3431 *****/
3432
3433 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3435 DWORD oldValue;
3436
3437 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3438 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3439
3440 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3441 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3442 }
3443
3444 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3445 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3446 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3447 }
3448 /**
3449 * SetSampler is designed to allow for more than the standard up to 8 textures
3450 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3451 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3452 *
3453 * http://developer.nvidia.com/object/General_FAQ.html#t6
3454 *
3455 * There are two new settings for GForce
3456 * the sampler one:
3457 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3458 * and the texture one:
3459 * GL_MAX_TEXTURE_COORDS_ARB.
3460 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3461 ******************/
3462
3463 oldValue = This->stateBlock->samplerState[Sampler][Type];
3464 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3465 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3466
3467 /* Handle recording of state blocks */
3468 if (This->isRecordingState) {
3469 TRACE("Recording... not performing anything\n");
3470 return WINED3D_OK;
3471 }
3472
3473 if(oldValue == Value) {
3474 TRACE("Application is setting the old value over, nothing to do\n");
3475 return WINED3D_OK;
3476 }
3477
3478 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3479
3480 return WINED3D_OK;
3481 }
3482
3483 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3485
3486 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3487 This, Sampler, debug_d3dsamplerstate(Type), Type);
3488
3489 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3490 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3491 }
3492
3493 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3494 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3495 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3496 }
3497 *Value = This->stateBlock->samplerState[Sampler][Type];
3498 TRACE("(%p) : Returning %#x\n", This, *Value);
3499
3500 return WINED3D_OK;
3501 }
3502
3503 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3505
3506 This->updateStateBlock->changed.scissorRect = TRUE;
3507 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3508 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3509 return WINED3D_OK;
3510 }
3511 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3512
3513 if(This->isRecordingState) {
3514 TRACE("Recording... not performing anything\n");
3515 return WINED3D_OK;
3516 }
3517
3518 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3519
3520 return WINED3D_OK;
3521 }
3522
3523 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3525
3526 *pRect = This->updateStateBlock->scissorRect;
3527 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3528 return WINED3D_OK;
3529 }
3530
3531 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3533 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3534
3535 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3536
3537 This->updateStateBlock->vertexDecl = pDecl;
3538 This->updateStateBlock->changed.vertexDecl = TRUE;
3539
3540 if (This->isRecordingState) {
3541 TRACE("Recording... not performing anything\n");
3542 return WINED3D_OK;
3543 } else if(pDecl == oldDecl) {
3544 /* Checked after the assignment to allow proper stateblock recording */
3545 TRACE("Application is setting the old declaration over, nothing to do\n");
3546 return WINED3D_OK;
3547 }
3548
3549 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3550 return WINED3D_OK;
3551 }
3552
3553 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3555
3556 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3557
3558 *ppDecl = This->stateBlock->vertexDecl;
3559 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3560 return WINED3D_OK;
3561 }
3562
3563 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3565 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3566
3567 This->updateStateBlock->vertexShader = pShader;
3568 This->updateStateBlock->changed.vertexShader = TRUE;
3569
3570 if (This->isRecordingState) {
3571 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3572 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3573 TRACE("Recording... not performing anything\n");
3574 return WINED3D_OK;
3575 } else if(oldShader == pShader) {
3576 /* Checked here to allow proper stateblock recording */
3577 TRACE("App is setting the old shader over, nothing to do\n");
3578 return WINED3D_OK;
3579 }
3580
3581 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3582 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3583 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3584
3585 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3586
3587 return WINED3D_OK;
3588 }
3589
3590 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3592
3593 if (NULL == ppShader) {
3594 return WINED3DERR_INVALIDCALL;
3595 }
3596 *ppShader = This->stateBlock->vertexShader;
3597 if( NULL != *ppShader)
3598 IWineD3DVertexShader_AddRef(*ppShader);
3599
3600 TRACE("(%p) : returning %p\n", This, *ppShader);
3601 return WINED3D_OK;
3602 }
3603
3604 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3605 IWineD3DDevice *iface,
3606 UINT start,
3607 CONST BOOL *srcData,
3608 UINT count) {
3609
3610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3611 int i, cnt = min(count, MAX_CONST_B - start);
3612
3613 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3614 iface, srcData, start, count);
3615
3616 if (srcData == NULL || cnt < 0)
3617 return WINED3DERR_INVALIDCALL;
3618
3619 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3620 for (i = 0; i < cnt; i++)
3621 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3622
3623 for (i = start; i < cnt + start; ++i) {
3624 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3625 }
3626
3627 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3628
3629 return WINED3D_OK;
3630 }
3631
3632 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3633 IWineD3DDevice *iface,
3634 UINT start,
3635 BOOL *dstData,
3636 UINT count) {
3637
3638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3639 int cnt = min(count, MAX_CONST_B - start);
3640
3641 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3642 iface, dstData, start, count);
3643
3644 if (dstData == NULL || cnt < 0)
3645 return WINED3DERR_INVALIDCALL;
3646
3647 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3648 return WINED3D_OK;
3649 }
3650
3651 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3652 IWineD3DDevice *iface,
3653 UINT start,
3654 CONST int *srcData,
3655 UINT count) {
3656
3657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3658 int i, cnt = min(count, MAX_CONST_I - start);
3659
3660 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3661 iface, srcData, start, count);
3662
3663 if (srcData == NULL || cnt < 0)
3664 return WINED3DERR_INVALIDCALL;
3665
3666 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3667 for (i = 0; i < cnt; i++)
3668 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3669 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3670
3671 for (i = start; i < cnt + start; ++i) {
3672 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3673 }
3674
3675 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3676
3677 return WINED3D_OK;
3678 }
3679
3680 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3681 IWineD3DDevice *iface,
3682 UINT start,
3683 int *dstData,
3684 UINT count) {
3685
3686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3687 int cnt = min(count, MAX_CONST_I - start);
3688
3689 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3690 iface, dstData, start, count);
3691
3692 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3693 return WINED3DERR_INVALIDCALL;
3694
3695 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3696 return WINED3D_OK;
3697 }
3698
3699 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3700 IWineD3DDevice *iface,
3701 UINT start,
3702 CONST float *srcData,
3703 UINT count) {
3704
3705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3706 UINT i;
3707
3708 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3709 iface, srcData, start, count);
3710
3711 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3712 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3713 return WINED3DERR_INVALIDCALL;
3714
3715 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3716 if(TRACE_ON(d3d)) {
3717 for (i = 0; i < count; i++)
3718 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3719 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3720 }
3721
3722 if (!This->isRecordingState)
3723 {
3724 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3725 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3726 }
3727
3728 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3729 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3730
3731 return WINED3D_OK;
3732 }
3733
3734 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3735 IWineD3DDevice *iface,
3736 UINT start,
3737 float *dstData,
3738 UINT count) {
3739
3740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3741 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3742
3743 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3744 iface, dstData, start, count);
3745
3746 if (dstData == NULL || cnt < 0)
3747 return WINED3DERR_INVALIDCALL;
3748
3749 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3750 return WINED3D_OK;
3751 }
3752
3753 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3754 DWORD i;
3755 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3756 {
3757 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3758 }
3759 }
3760
3761 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3762 int i = This->rev_tex_unit_map[unit];
3763 int j = This->texUnitMap[stage];
3764
3765 This->texUnitMap[stage] = unit;
3766 if (i != -1 && i != stage) {
3767 This->texUnitMap[i] = -1;
3768 }
3769
3770 This->rev_tex_unit_map[unit] = stage;
3771 if (j != -1 && j != unit) {
3772 This->rev_tex_unit_map[j] = -1;
3773 }
3774 }
3775
3776 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3777 int i;
3778
3779 This->fixed_function_usage_map = 0;
3780 for (i = 0; i < MAX_TEXTURES; ++i) {
3781 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3782 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3783 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3784 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3785 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3786 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3787 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3788 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3789
3790 if (color_op == WINED3DTOP_DISABLE) {
3791 /* Not used, and disable higher stages */
3792 break;
3793 }
3794
3795 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3796 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3797 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3798 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3799 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3800 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3801 This->fixed_function_usage_map |= (1 << i);
3802 }
3803
3804 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3805 This->fixed_function_usage_map |= (1 << (i + 1));
3806 }
3807 }
3808 }
3809
3810 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3811 int i, tex;
3812 WORD ffu_map;
3813
3814 device_update_fixed_function_usage_map(This);
3815 ffu_map = This->fixed_function_usage_map;
3816
3817 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3818 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3819 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3820 {
3821 if (!(ffu_map & 1)) continue;
3822
3823 if (This->texUnitMap[i] != i) {
3824 device_map_stage(This, i, i);
3825 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3826 markTextureStagesDirty(This, i);
3827 }
3828 }
3829 return;
3830 }
3831
3832 /* Now work out the mapping */
3833 tex = 0;
3834 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3835 {
3836 if (!(ffu_map & 1)) continue;
3837
3838 if (This->texUnitMap[i] != tex) {
3839 device_map_stage(This, i, tex);
3840 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3841 markTextureStagesDirty(This, i);
3842 }
3843
3844 ++tex;
3845 }
3846 }
3847
3848 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3849 const DWORD *sampler_tokens =
3850 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3851 int i;
3852
3853 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3854 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3855 device_map_stage(This, i, i);
3856 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3857 if (i < MAX_TEXTURES) {
3858 markTextureStagesDirty(This, i);
3859 }
3860 }
3861 }
3862 }
3863
3864 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3865 const DWORD *vshader_sampler_tokens, int unit)
3866 {
3867 int current_mapping = This->rev_tex_unit_map[unit];
3868
3869 if (current_mapping == -1) {
3870 /* Not currently used */
3871 return TRUE;
3872 }
3873
3874 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3875 /* Used by a fragment sampler */
3876
3877 if (!pshader_sampler_tokens) {
3878 /* No pixel shader, check fixed function */
3879 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3880 }
3881
3882 /* Pixel shader, check the shader's sampler map */
3883 return !pshader_sampler_tokens[current_mapping];
3884 }
3885
3886 /* Used by a vertex sampler */
3887 return !vshader_sampler_tokens[current_mapping];
3888 }
3889
3890 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3891 const DWORD *vshader_sampler_tokens =
3892 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3893 const DWORD *pshader_sampler_tokens = NULL;
3894 int start = GL_LIMITS(combined_samplers) - 1;
3895 int i;
3896
3897 if (ps) {
3898 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3899
3900 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3901 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3902 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3903 }
3904
3905 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3906 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3907 if (vshader_sampler_tokens[i]) {
3908 if (This->texUnitMap[vsampler_idx] != -1) {
3909 /* Already mapped somewhere */
3910 continue;
3911 }
3912
3913 while (start >= 0) {
3914 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3915 device_map_stage(This, vsampler_idx, start);
3916 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3917
3918 --start;
3919 break;
3920 }
3921
3922 --start;
3923 }
3924 }
3925 }
3926 }
3927
3928 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3929 BOOL vs = use_vs(This->stateBlock);
3930 BOOL ps = use_ps(This->stateBlock);
3931 /*
3932 * Rules are:
3933 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3934 * that would be really messy and require shader recompilation
3935 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3936 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3937 */
3938 if (ps) {
3939 device_map_psamplers(This);
3940 } else {
3941 device_map_fixed_function_samplers(This);
3942 }
3943
3944 if (vs) {
3945 device_map_vsamplers(This, ps);
3946 }
3947 }
3948
3949 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3951 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3952 This->updateStateBlock->pixelShader = pShader;
3953 This->updateStateBlock->changed.pixelShader = TRUE;
3954
3955 /* Handle recording of state blocks */
3956 if (This->isRecordingState) {
3957 TRACE("Recording... not performing anything\n");
3958 }
3959
3960 if (This->isRecordingState) {
3961 TRACE("Recording... not performing anything\n");
3962 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3963 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3964 return WINED3D_OK;
3965 }
3966
3967 if(pShader == oldShader) {
3968 TRACE("App is setting the old pixel shader over, nothing to do\n");
3969 return WINED3D_OK;
3970 }
3971
3972 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3973 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3974
3975 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3976 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3977
3978 return WINED3D_OK;
3979 }
3980
3981 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3983
3984 if (NULL == ppShader) {
3985 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3986 return WINED3DERR_INVALIDCALL;
3987 }
3988
3989 *ppShader = This->stateBlock->pixelShader;
3990 if (NULL != *ppShader) {
3991 IWineD3DPixelShader_AddRef(*ppShader);
3992 }
3993 TRACE("(%p) : returning %p\n", This, *ppShader);
3994 return WINED3D_OK;
3995 }
3996
3997 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3998 IWineD3DDevice *iface,
3999 UINT start,
4000 CONST BOOL *srcData,
4001 UINT count) {
4002
4003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4004 int i, cnt = min(count, MAX_CONST_B - start);
4005
4006 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4007 iface, srcData, start, count);
4008
4009 if (srcData == NULL || cnt < 0)
4010 return WINED3DERR_INVALIDCALL;
4011
4012 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4013 for (i = 0; i < cnt; i++)
4014 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4015
4016 for (i = start; i < cnt + start; ++i) {
4017 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4018 }
4019
4020 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4021
4022 return WINED3D_OK;
4023 }
4024
4025 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4026 IWineD3DDevice *iface,
4027 UINT start,
4028 BOOL *dstData,
4029 UINT count) {
4030
4031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4032 int cnt = min(count, MAX_CONST_B - start);
4033
4034 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4035 iface, dstData, start, count);
4036
4037 if (dstData == NULL || cnt < 0)
4038 return WINED3DERR_INVALIDCALL;
4039
4040 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4041 return WINED3D_OK;
4042 }
4043
4044 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4045 IWineD3DDevice *iface,
4046 UINT start,
4047 CONST int *srcData,
4048 UINT count) {
4049
4050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4051 int i, cnt = min(count, MAX_CONST_I - start);
4052
4053 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4054 iface, srcData, start, count);
4055
4056 if (srcData == NULL || cnt < 0)
4057 return WINED3DERR_INVALIDCALL;
4058
4059 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4060 for (i = 0; i < cnt; i++)
4061 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4062 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4063
4064 for (i = start; i < cnt + start; ++i) {
4065 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4066 }
4067
4068 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4069
4070 return WINED3D_OK;
4071 }
4072
4073 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4074 IWineD3DDevice *iface,
4075 UINT start,
4076 int *dstData,
4077 UINT count) {
4078
4079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4080 int cnt = min(count, MAX_CONST_I - start);
4081
4082 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4083 iface, dstData, start, count);
4084
4085 if (dstData == NULL || cnt < 0)
4086 return WINED3DERR_INVALIDCALL;
4087
4088 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4089 return WINED3D_OK;
4090 }
4091
4092 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4093 IWineD3DDevice *iface,
4094 UINT start,
4095 CONST float *srcData,
4096 UINT count) {
4097
4098 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4099 UINT i;
4100
4101 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4102 iface, srcData, start, count);
4103
4104 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4105 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4106 return WINED3DERR_INVALIDCALL;
4107
4108 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4109 if(TRACE_ON(d3d)) {
4110 for (i = 0; i < count; i++)
4111 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4112 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4113 }
4114
4115 if (!This->isRecordingState)
4116 {
4117 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4118 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4119 }
4120
4121 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4122 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4123
4124 return WINED3D_OK;
4125 }
4126
4127 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4128 IWineD3DDevice *iface,
4129 UINT start,
4130 float *dstData,
4131 UINT count) {
4132
4133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4134 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4135
4136 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4137 iface, dstData, start, count);
4138
4139 if (dstData == NULL || cnt < 0)
4140 return WINED3DERR_INVALIDCALL;
4141
4142 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4143 return WINED3D_OK;
4144 }
4145
4146 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4147 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4148 const WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags)
4149 {
4150 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4151 unsigned int i;
4152 DWORD DestFVF = dest->fvf;
4153 WINED3DVIEWPORT vp;
4154 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4155 BOOL doClip;
4156 DWORD numTextures;
4157
4158 if (lpStrideData->u.s.normal.lpData) {
4159 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4160 }
4161
4162 if (lpStrideData->u.s.position.lpData == NULL) {
4163 ERR("Source has no position mask\n");
4164 return WINED3DERR_INVALIDCALL;
4165 }
4166
4167 /* We might access VBOs from this code, so hold the lock */
4168 ENTER_GL();
4169
4170 if (dest->resource.allocatedMemory == NULL) {
4171 /* This may happen if we do direct locking into a vbo. Unlikely,
4172 * but theoretically possible(ddraw processvertices test)
4173 */
4174 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4175 if(!dest->resource.allocatedMemory) {
4176 LEAVE_GL();
4177 ERR("Out of memory\n");
4178 return E_OUTOFMEMORY;
4179 }
4180 if(dest->vbo) {
4181 const void *src;
4182 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4183 checkGLcall("glBindBufferARB");
4184 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4185 if(src) {
4186 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4187 }
4188 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4189 checkGLcall("glUnmapBufferARB");
4190 }
4191 }
4192
4193 /* Get a pointer into the destination vbo(create one if none exists) and
4194 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4195 */
4196 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4197 dest->Flags |= VBFLAG_CREATEVBO;
4198 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4199 }
4200
4201 if(dest->vbo) {
4202 unsigned char extrabytes = 0;
4203 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4204 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4205 * this may write 4 extra bytes beyond the area that should be written
4206 */
4207 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4208 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4209 if(!dest_conv_addr) {
4210 ERR("Out of memory\n");
4211 /* Continue without storing converted vertices */
4212 }
4213 dest_conv = dest_conv_addr;
4214 }
4215
4216 /* Should I clip?
4217 * a) WINED3DRS_CLIPPING is enabled
4218 * b) WINED3DVOP_CLIP is passed
4219 */
4220 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4221 static BOOL warned = FALSE;
4222 /*
4223 * The clipping code is not quite correct. Some things need
4224 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4225 * so disable clipping for now.
4226 * (The graphics in Half-Life are broken, and my processvertices
4227 * test crashes with IDirect3DDevice3)
4228 doClip = TRUE;
4229 */
4230 doClip = FALSE;
4231 if(!warned) {
4232 warned = TRUE;
4233 FIXME("Clipping is broken and disabled for now\n");
4234 }
4235 } else doClip = FALSE;
4236 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4237
4238 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4239 WINED3DTS_VIEW,
4240 &view_mat);
4241 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4242 WINED3DTS_PROJECTION,
4243 &proj_mat);
4244 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4245 WINED3DTS_WORLDMATRIX(0),
4246 &world_mat);
4247
4248 TRACE("View mat:\n");
4249 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);
4250 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);
4251 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);
4252 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);
4253
4254 TRACE("Proj mat:\n");
4255 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);
4256 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);
4257 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);
4258 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);
4259
4260 TRACE("World mat:\n");
4261 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);
4262 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);
4263 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);
4264 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);
4265
4266 /* Get the viewport */
4267 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4268 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4269 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4270
4271 multiply_matrix(&mat,&view_mat,&world_mat);
4272 multiply_matrix(&mat,&proj_mat,&mat);
4273
4274 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4275
4276 for (i = 0; i < dwCount; i+= 1) {
4277 unsigned int tex_index;
4278
4279 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4280 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4281 /* The position first */
4282 const float *p =
4283 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4284 float x, y, z, rhw;
4285 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4286
4287 /* Multiplication with world, view and projection matrix */
4288 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);
4289 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);
4290 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);
4291 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);
4292
4293 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4294
4295 /* WARNING: The following things are taken from d3d7 and were not yet checked
4296 * against d3d8 or d3d9!
4297 */
4298
4299 /* Clipping conditions: From msdn
4300 *
4301 * A vertex is clipped if it does not match the following requirements
4302 * -rhw < x <= rhw
4303 * -rhw < y <= rhw
4304 * 0 < z <= rhw
4305 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4306 *
4307 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4308 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4309 *
4310 */
4311
4312 if( !doClip ||
4313 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4314 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4315 ( rhw > eps ) ) ) {
4316
4317 /* "Normal" viewport transformation (not clipped)
4318 * 1) The values are divided by rhw
4319 * 2) The y axis is negative, so multiply it with -1
4320 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4321 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4322 * 4) Multiply x with Width/2 and add Width/2
4323 * 5) The same for the height
4324 * 6) Add the viewpoint X and Y to the 2D coordinates and
4325 * The minimum Z value to z
4326 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4327 *
4328 * Well, basically it's simply a linear transformation into viewport
4329 * coordinates
4330 */
4331
4332 x /= rhw;
4333 y /= rhw;
4334 z /= rhw;
4335
4336 y *= -1;
4337
4338 x *= vp.Width / 2;
4339 y *= vp.Height / 2;
4340 z *= vp.MaxZ - vp.MinZ;
4341
4342 x += vp.Width / 2 + vp.X;
4343 y += vp.Height / 2 + vp.Y;
4344 z += vp.MinZ;
4345
4346 rhw = 1 / rhw;
4347 } else {
4348 /* That vertex got clipped
4349 * Contrary to OpenGL it is not dropped completely, it just
4350 * undergoes a different calculation.
4351 */
4352 TRACE("Vertex got clipped\n");
4353 x += rhw;
4354 y += rhw;
4355
4356 x /= 2;
4357 y /= 2;
4358
4359 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4360 * outside of the main vertex buffer memory. That needs some more
4361 * investigation...
4362 */
4363 }
4364
4365 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4366
4367
4368 ( (float *) dest_ptr)[0] = x;
4369 ( (float *) dest_ptr)[1] = y;
4370 ( (float *) dest_ptr)[2] = z;
4371 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4372
4373 dest_ptr += 3 * sizeof(float);
4374
4375 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4376 dest_ptr += sizeof(float);
4377 }
4378
4379 if(dest_conv) {
4380 float w = 1 / rhw;
4381 ( (float *) dest_conv)[0] = x * w;
4382 ( (float *) dest_conv)[1] = y * w;
4383 ( (float *) dest_conv)[2] = z * w;
4384 ( (float *) dest_conv)[3] = w;
4385
4386 dest_conv += 3 * sizeof(float);
4387
4388 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4389 dest_conv += sizeof(float);
4390 }
4391 }
4392 }
4393 if (DestFVF & WINED3DFVF_PSIZE) {
4394 dest_ptr += sizeof(DWORD);
4395 if(dest_conv) dest_conv += sizeof(DWORD);
4396 }
4397 if (DestFVF & WINED3DFVF_NORMAL) {
4398 const float *normal =
4399 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4400 /* AFAIK this should go into the lighting information */
4401 FIXME("Didn't expect the destination to have a normal\n");
4402 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4403 if(dest_conv) {
4404 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4405 }
4406 }
4407
4408 if (DestFVF & WINED3DFVF_DIFFUSE) {
4409 const DWORD *color_d =
4410 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4411 if(!color_d) {
4412 static BOOL warned = FALSE;
4413
4414 if(!warned) {
4415 ERR("No diffuse color in source, but destination has one\n");
4416 warned = TRUE;
4417 }
4418
4419 *( (DWORD *) dest_ptr) = 0xffffffff;
4420 dest_ptr += sizeof(DWORD);
4421
4422 if(dest_conv) {
4423 *( (DWORD *) dest_conv) = 0xffffffff;
4424 dest_conv += sizeof(DWORD);
4425 }
4426 }
4427 else {
4428 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4429 if(dest_conv) {
4430 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4431 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4432 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4433 dest_conv += sizeof(DWORD);
4434 }
4435 }
4436 }
4437
4438 if (DestFVF & WINED3DFVF_SPECULAR) {
4439 /* What's the color value in the feedback buffer? */
4440 const DWORD *color_s =
4441 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4442 if(!color_s) {
4443 static BOOL warned = FALSE;
4444
4445 if(!warned) {
4446 ERR("No specular color in source, but destination has one\n");
4447 warned = TRUE;
4448 }
4449
4450 *( (DWORD *) dest_ptr) = 0xFF000000;
4451 dest_ptr += sizeof(DWORD);
4452
4453 if(dest_conv) {
4454 *( (DWORD *) dest_conv) = 0xFF000000;
4455 dest_conv += sizeof(DWORD);
4456 }
4457 }
4458 else {
4459 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4460 if(dest_conv) {
4461 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4462 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4463 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4464 dest_conv += sizeof(DWORD);
4465 }
4466 }
4467 }
4468
4469 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4470 const float *tex_coord =
4471 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4472 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4473 if(!tex_coord) {
4474 ERR("No source texture, but destination requests one\n");
4475 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4476 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4477 }
4478 else {
4479 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4480 if(dest_conv) {
4481 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4482 }
4483 }
4484 }
4485 }
4486
4487 if(dest_conv) {
4488 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4489 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4490 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4491 dwCount * get_flexible_vertex_size(DestFVF),
4492 dest_conv_addr));
4493 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4494 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4495 }
4496
4497 LEAVE_GL();
4498
4499 return WINED3D_OK;
4500 }
4501 #undef copy_and_next
4502
4503 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4505 WineDirect3DVertexStridedData strided;
4506 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4507 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4508
4509 if(pVertexDecl) {
4510 ERR("Output vertex declaration not implemented yet\n");
4511 }
4512
4513 /* Need any context to write to the vbo. */
4514 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4515
4516 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4517 * control the streamIsUP flag, thus restore it afterwards.
4518 */
4519 This->stateBlock->streamIsUP = FALSE;
4520 memset(&strided, 0, sizeof(strided));
4521 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4522 This->stateBlock->streamIsUP = streamWasUP;
4523
4524 if(vbo || SrcStartIndex) {
4525 unsigned int i;
4526 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4527 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4528 *
4529 * Also get the start index in, but only loop over all elements if there's something to add at all.
4530 */
4531 #define FIXSRC(type) \
4532 if(strided.u.s.type.VBO) { \
4533 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4534 strided.u.s.type.VBO = 0; \
4535 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4536 ENTER_GL(); \
4537 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4538 vb->vbo = 0; \
4539 LEAVE_GL(); \
4540 } \
4541 if(strided.u.s.type.lpData) { \
4542 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4543 }
4544 FIXSRC(position);
4545 FIXSRC(blendWeights);
4546 FIXSRC(blendMatrixIndices);
4547 FIXSRC(normal);
4548 FIXSRC(pSize);
4549 FIXSRC(diffuse);
4550 FIXSRC(specular);
4551 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4552 FIXSRC(texCoords[i]);
4553 }
4554 FIXSRC(position2);
4555 FIXSRC(normal2);
4556 FIXSRC(tangent);
4557 FIXSRC(binormal);
4558 FIXSRC(tessFactor);
4559 FIXSRC(fog);
4560 FIXSRC(depth);
4561 FIXSRC(sample);
4562 #undef FIXSRC
4563 }
4564
4565 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4566 }
4567
4568 /*****
4569 * Get / Set Texture Stage States
4570 * TODO: Verify against dx9 definitions
4571 *****/
4572 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4574 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4575
4576 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4577
4578 if (Stage >= MAX_TEXTURES) {
4579 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4580 return WINED3D_OK;
4581 }
4582
4583 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4584 This->updateStateBlock->textureState[Stage][Type] = Value;
4585
4586 if (This->isRecordingState) {
4587 TRACE("Recording... not performing anything\n");
4588 return WINED3D_OK;
4589 }
4590
4591 /* Checked after the assignments to allow proper stateblock recording */
4592 if(oldValue == Value) {
4593 TRACE("App is setting the old value over, nothing to do\n");
4594 return WINED3D_OK;
4595 }
4596
4597 if(Stage > This->stateBlock->lowest_disabled_stage &&
4598 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4599 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4600 * Changes in other states are important on disabled stages too
4601 */
4602 return WINED3D_OK;
4603 }
4604
4605 if(Type == WINED3DTSS_COLOROP) {
4606 int i;
4607
4608 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4609 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4610 * they have to be disabled
4611 *
4612 * The current stage is dirtified below.
4613 */
4614 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4615 TRACE("Additionally dirtifying stage %d\n", i);
4616 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4617 }
4618 This->stateBlock->lowest_disabled_stage = Stage;
4619 TRACE("New lowest disabled: %d\n", Stage);
4620 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4621 /* Previously disabled stage enabled. Stages above it may need enabling
4622 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4623 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4624 *
4625 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4626 */
4627
4628 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4629 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4630 break;
4631 }
4632 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4633 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4634 }
4635 This->stateBlock->lowest_disabled_stage = i;
4636 TRACE("New lowest disabled: %d\n", i);
4637 }
4638 }
4639
4640 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4641
4642 return WINED3D_OK;
4643 }
4644
4645 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4647 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4648 *pValue = This->updateStateBlock->textureState[Stage][Type];
4649 return WINED3D_OK;
4650 }
4651
4652 /*****
4653 * Get / Set Texture
4654 *****/
4655 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4657 IWineD3DBaseTexture *oldTexture;
4658
4659 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4660
4661 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4662 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4663 }
4664
4665 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4666 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4667 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4668 }
4669
4670 oldTexture = This->updateStateBlock->textures[Stage];
4671
4672 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4673 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4674 {
4675 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4676 return WINED3DERR_INVALIDCALL;
4677 }
4678
4679 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4680 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4681
4682 This->updateStateBlock->changed.textures |= 1 << Stage;
4683 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4684 This->updateStateBlock->textures[Stage] = pTexture;
4685
4686 /* Handle recording of state blocks */
4687 if (This->isRecordingState) {
4688 TRACE("Recording... not performing anything\n");
4689 return WINED3D_OK;
4690 }
4691
4692 if(oldTexture == pTexture) {
4693 TRACE("App is setting the same texture again, nothing to do\n");
4694 return WINED3D_OK;
4695 }
4696
4697 /** NOTE: MSDN says that setTexture increases the reference count,
4698 * and that the application must set the texture back to null (or have a leaky application),
4699 * This means we should pass the refcount up to the parent
4700 *******************************/
4701 if (NULL != This->updateStateBlock->textures[Stage]) {
4702 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4703 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4704 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4705
4706 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4707
4708 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4709 {
4710 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4711 }
4712
4713 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4714 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4715 * so the COLOROP and ALPHAOP have to be dirtified.
4716 */
4717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4718 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4719 }
4720 if(bindCount == 1) {
4721 new->baseTexture.sampler = Stage;
4722 }
4723 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4724
4725 }
4726
4727 if (NULL != oldTexture) {
4728 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4729 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4730
4731 IWineD3DBaseTexture_Release(oldTexture);
4732 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4733 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4734 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4735 }
4736
4737 if(bindCount && old->baseTexture.sampler == Stage) {
4738 int i;
4739 /* Have to do a search for the other sampler(s) where the texture is bound to
4740 * Shouldn't happen as long as apps bind a texture only to one stage
4741 */
4742 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4743 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4744 if(This->updateStateBlock->textures[i] == oldTexture) {
4745 old->baseTexture.sampler = i;
4746 break;
4747 }
4748 }
4749 }
4750 }
4751
4752 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4753
4754 return WINED3D_OK;
4755 }
4756
4757 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4759
4760 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4761
4762 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4763 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4764 }
4765
4766 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4767 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4768 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4769 }
4770
4771 *ppTexture=This->stateBlock->textures[Stage];
4772 if (*ppTexture)
4773 IWineD3DBaseTexture_AddRef(*ppTexture);
4774
4775 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4776
4777 return WINED3D_OK;
4778 }
4779
4780 /*****
4781 * Get Back Buffer
4782 *****/
4783 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4784 IWineD3DSurface **ppBackBuffer) {
4785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4786 IWineD3DSwapChain *swapChain;
4787 HRESULT hr;
4788
4789 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4790
4791 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4792 if (hr == WINED3D_OK) {
4793 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4794 IWineD3DSwapChain_Release(swapChain);
4795 } else {
4796 *ppBackBuffer = NULL;
4797 }
4798 return hr;
4799 }
4800
4801 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4803 WARN("(%p) : stub, calling idirect3d for now\n", This);
4804 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4805 }
4806
4807 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4809 IWineD3DSwapChain *swapChain;
4810 HRESULT hr;
4811
4812 if(iSwapChain > 0) {
4813 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4814 if (hr == WINED3D_OK) {
4815 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4816 IWineD3DSwapChain_Release(swapChain);
4817 } else {
4818 FIXME("(%p) Error getting display mode\n", This);
4819 }
4820 } else {
4821 /* Don't read the real display mode,
4822 but return the stored mode instead. X11 can't change the color
4823 depth, and some apps are pretty angry if they SetDisplayMode from
4824 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4825
4826 Also don't relay to the swapchain because with ddraw it's possible
4827 that there isn't a swapchain at all */
4828 pMode->Width = This->ddraw_width;
4829 pMode->Height = This->ddraw_height;
4830 pMode->Format = This->ddraw_format;
4831 pMode->RefreshRate = 0;
4832 hr = WINED3D_OK;
4833 }
4834
4835 return hr;
4836 }
4837
4838 /*****
4839 * Stateblock related functions
4840 *****/
4841
4842 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4844 IWineD3DStateBlock *stateblock;
4845 HRESULT hr;
4846
4847 TRACE("(%p)\n", This);
4848
4849 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4850
4851 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4852 if (FAILED(hr)) return hr;
4853
4854 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4855 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4856 This->isRecordingState = TRUE;
4857
4858 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4859
4860 return WINED3D_OK;
4861 }
4862
4863 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4865 unsigned int i, j;
4866 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4867
4868 if (!This->isRecordingState) {
4869 WARN("(%p) not recording! returning error\n", This);
4870 *ppStateBlock = NULL;
4871 return WINED3DERR_INVALIDCALL;
4872 }
4873
4874 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
4875 {
4876 DWORD map = object->changed.renderState[i];
4877 for (j = 0; map; map >>= 1, ++j)
4878 {
4879 if (!(map & 1)) continue;
4880
4881 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
4882 }
4883 }
4884
4885 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
4886 {
4887 DWORD map = object->changed.transform[i];
4888 for (j = 0; map; map >>= 1, ++j)
4889 {
4890 if (!(map & 1)) continue;
4891
4892 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
4893 }
4894 }
4895 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4896 if(object->changed.vertexShaderConstantsF[i]) {
4897 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4898 object->num_contained_vs_consts_f++;
4899 }
4900 }
4901 for(i = 0; i < MAX_CONST_I; i++) {
4902 if (object->changed.vertexShaderConstantsI & (1 << i))
4903 {
4904 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4905 object->num_contained_vs_consts_i++;
4906 }
4907 }
4908 for(i = 0; i < MAX_CONST_B; i++) {
4909 if (object->changed.vertexShaderConstantsB & (1 << i))
4910 {
4911 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4912 object->num_contained_vs_consts_b++;
4913 }
4914 }
4915 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4916 {
4917 if (object->changed.pixelShaderConstantsF[i])
4918 {
4919 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4920 ++object->num_contained_ps_consts_f;
4921 }
4922 }
4923 for(i = 0; i < MAX_CONST_I; i++) {
4924 if (object->changed.pixelShaderConstantsI & (1 << i))
4925 {
4926 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4927 object->num_contained_ps_consts_i++;
4928 }
4929 }
4930 for(i = 0; i < MAX_CONST_B; i++) {
4931 if (object->changed.pixelShaderConstantsB & (1 << i))
4932 {
4933 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4934 object->num_contained_ps_consts_b++;
4935 }
4936 }
4937 for(i = 0; i < MAX_TEXTURES; i++) {
4938 DWORD map = object->changed.textureState[i];
4939
4940 for(j = 0; map; map >>= 1, ++j)
4941 {
4942 if (!(map & 1)) continue;
4943
4944 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4945 object->contained_tss_states[object->num_contained_tss_states].state = j;
4946 ++object->num_contained_tss_states;
4947 }
4948 }
4949 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4950 DWORD map = object->changed.samplerState[i];
4951
4952 for (j = 0; map; map >>= 1, ++j)
4953 {
4954 if (!(map & 1)) continue;
4955
4956 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4957 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4958 ++object->num_contained_sampler_states;
4959 }
4960 }
4961
4962 *ppStateBlock = (IWineD3DStateBlock*) object;
4963 This->isRecordingState = FALSE;
4964 This->updateStateBlock = This->stateBlock;
4965 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4966 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4967 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4968 return WINED3D_OK;
4969 }
4970
4971 /*****
4972 * Scene related functions
4973 *****/
4974 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4975 /* At the moment we have no need for any functionality at the beginning
4976 of a scene */
4977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4978 TRACE("(%p)\n", This);
4979
4980 if(This->inScene) {
4981 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4982 return WINED3DERR_INVALIDCALL;
4983 }
4984 This->inScene = TRUE;
4985 return WINED3D_OK;
4986 }
4987
4988 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4990 TRACE("(%p)\n", This);
4991
4992 if(!This->inScene) {
4993 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4994 return WINED3DERR_INVALIDCALL;
4995 }
4996
4997 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4998 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4999 glFlush();
5000 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5001 * fails
5002 */
5003
5004 This->inScene = FALSE;
5005 return WINED3D_OK;
5006 }
5007
5008 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5009 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5010 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5012 IWineD3DSwapChain *swapChain = NULL;
5013 int i;
5014 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5015
5016 TRACE("(%p) Presenting the frame\n", This);
5017
5018 for(i = 0 ; i < swapchains ; i ++) {
5019
5020 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5021 TRACE("presentinng chain %d, %p\n", i, swapChain);
5022 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5023 IWineD3DSwapChain_Release(swapChain);
5024 }
5025
5026 return WINED3D_OK;
5027 }
5028
5029 /* Not called from the VTable (internal subroutine) */
5030 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5031 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5032 float Z, DWORD Stencil) {
5033 GLbitfield glMask = 0;
5034 unsigned int i;
5035 WINED3DRECT curRect;
5036 RECT vp_rect;
5037 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5038 UINT drawable_width, drawable_height;
5039 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5040 IWineD3DSwapChainImpl *swapchain = NULL;
5041
5042 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5043 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5044 * for the cleared parts, and the untouched parts.
5045 *
5046 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5047 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5048 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5049 * checking all this if the dest surface is in the drawable anyway.
5050 */
5051 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5052 while(1) {
5053 if(vp->X != 0 || vp->Y != 0 ||
5054 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5055 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5056 break;
5057 }
5058 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5059 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5060 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5061 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5062 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5063 break;
5064 }
5065 if(Count > 0 && pRects && (
5066 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5067 pRects[0].x2 < target->currentDesc.Width ||
5068 pRects[0].y2 < target->currentDesc.Height)) {
5069 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5070 break;
5071 }
5072 break;
5073 }
5074 }
5075
5076 target->get_drawable_size(target, &drawable_width, &drawable_height);
5077
5078 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5079 ENTER_GL();
5080
5081 /* Only set the values up once, as they are not changing */
5082 if (Flags & WINED3DCLEAR_STENCIL) {
5083 glClearStencil(Stencil);
5084 checkGLcall("glClearStencil");
5085 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5086 glStencilMask(0xFFFFFFFF);
5087 }
5088
5089 if (Flags & WINED3DCLEAR_ZBUFFER) {
5090 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5091 glDepthMask(GL_TRUE);
5092 glClearDepth(Z);
5093 checkGLcall("glClearDepth");
5094 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5095 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5096
5097 if (vp->X != 0 || vp->Y != 0 ||
5098 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5099 surface_load_ds_location(This->stencilBufferTarget, location);
5100 }
5101 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5102 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5103 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5104 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5105 surface_load_ds_location(This->stencilBufferTarget, location);
5106 }
5107 else if (Count > 0 && pRects && (
5108 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5109 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5110 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5111 surface_load_ds_location(This->stencilBufferTarget, location);
5112 }
5113 }
5114
5115 if (Flags & WINED3DCLEAR_TARGET) {
5116 TRACE("Clearing screen with glClear to color %x\n", Color);
5117 glClearColor(D3DCOLOR_R(Color),
5118 D3DCOLOR_G(Color),
5119 D3DCOLOR_B(Color),
5120 D3DCOLOR_A(Color));
5121 checkGLcall("glClearColor");
5122
5123 /* Clear ALL colors! */
5124 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5125 glMask = glMask | GL_COLOR_BUFFER_BIT;
5126 }
5127
5128 vp_rect.left = vp->X;
5129 vp_rect.top = vp->Y;
5130 vp_rect.right = vp->X + vp->Width;
5131 vp_rect.bottom = vp->Y + vp->Height;
5132 if (!(Count > 0 && pRects)) {
5133 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5134 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5135 }
5136 if(This->render_offscreen) {
5137 glScissor(vp_rect.left, vp_rect.top,
5138 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5139 } else {
5140 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5141 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5142 }
5143 checkGLcall("glScissor");
5144 glClear(glMask);
5145 checkGLcall("glClear");
5146 } else {
5147 /* Now process each rect in turn */
5148 for (i = 0; i < Count; i++) {
5149 /* Note gl uses lower left, width/height */
5150 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5151 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5152 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5153 }
5154 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5155 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5156 curRect.x1, (target->currentDesc.Height - curRect.y2),
5157 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5158
5159 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5160 * The rectangle is not cleared, no error is returned, but further rectanlges are
5161 * still cleared if they are valid
5162 */
5163 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5164 TRACE("Rectangle with negative dimensions, ignoring\n");
5165 continue;
5166 }
5167
5168 if(This->render_offscreen) {
5169 glScissor(curRect.x1, curRect.y1,
5170 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5171 } else {
5172 glScissor(curRect.x1, drawable_height - curRect.y2,
5173 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5174 }
5175 checkGLcall("glScissor");
5176
5177 glClear(glMask);
5178 checkGLcall("glClear");
5179 }
5180 }
5181
5182 /* Restore the old values (why..?) */
5183 if (Flags & WINED3DCLEAR_STENCIL) {
5184 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5185 }
5186 if (Flags & WINED3DCLEAR_TARGET) {
5187 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5188 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5189 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5190 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5191 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5192
5193 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5194 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5195 */
5196 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5197 }
5198 if (Flags & WINED3DCLEAR_ZBUFFER) {
5199 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5200 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5201 surface_modify_ds_location(This->stencilBufferTarget, location);
5202 }
5203
5204 LEAVE_GL();
5205
5206 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5207 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5208 glFlush();
5209 }
5210 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5211 }
5212
5213 return WINED3D_OK;
5214 }
5215
5216 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5217 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5219 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5220
5221 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5222 Count, pRects, Flags, Color, Z, Stencil);
5223
5224 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5225 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5226 /* TODO: What about depth stencil buffers without stencil bits? */
5227 return WINED3DERR_INVALIDCALL;
5228 }
5229
5230 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5231 }
5232
5233 /*****
5234 * Drawing functions
5235 *****/
5236 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5237 UINT PrimitiveCount) {
5238
5239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5240
5241 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5242 debug_d3dprimitivetype(PrimitiveType),
5243 StartVertex, PrimitiveCount);
5244
5245 if(!This->stateBlock->vertexDecl) {
5246 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5247 return WINED3DERR_INVALIDCALL;
5248 }
5249
5250 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5251 if(This->stateBlock->streamIsUP) {
5252 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5253 This->stateBlock->streamIsUP = FALSE;
5254 }
5255
5256 if(This->stateBlock->loadBaseVertexIndex != 0) {
5257 This->stateBlock->loadBaseVertexIndex = 0;
5258 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5259 }
5260 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5261 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0/* NumVertices */, StartVertex /* start_idx */,
5262 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5263 return WINED3D_OK;
5264 }
5265
5266 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5267 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5268 WINED3DPRIMITIVETYPE PrimitiveType,
5269 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5270
5271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5272 UINT idxStride = 2;
5273 IWineD3DIndexBuffer *pIB;
5274 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5275 GLuint vbo;
5276
5277 pIB = This->stateBlock->pIndexData;
5278 if (!pIB) {
5279 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5280 * without an index buffer set. (The first time at least...)
5281 * D3D8 simply dies, but I doubt it can do much harm to return
5282 * D3DERR_INVALIDCALL there as well. */
5283 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5284 return WINED3DERR_INVALIDCALL;
5285 }
5286
5287 if(!This->stateBlock->vertexDecl) {
5288 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5289 return WINED3DERR_INVALIDCALL;
5290 }
5291
5292 if(This->stateBlock->streamIsUP) {
5293 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5294 This->stateBlock->streamIsUP = FALSE;
5295 }
5296 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5297
5298 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5299 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5300 minIndex, NumVertices, startIndex, primCount);
5301
5302 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5303 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5304 idxStride = 2;
5305 } else {
5306 idxStride = 4;
5307 }
5308
5309 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5310 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5311 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5312 }
5313
5314 drawPrimitive(iface, PrimitiveType, primCount, NumVertices, startIndex,
5315 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5316
5317 return WINED3D_OK;
5318 }
5319
5320 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5321 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5322 UINT VertexStreamZeroStride) {
5323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5324 IWineD3DVertexBuffer *vb;
5325
5326 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5327 debug_d3dprimitivetype(PrimitiveType),
5328 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5329
5330 if(!This->stateBlock->vertexDecl) {
5331 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5332 return WINED3DERR_INVALIDCALL;
5333 }
5334
5335 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5336 vb = This->stateBlock->streamSource[0];
5337 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5338 if(vb) IWineD3DVertexBuffer_Release(vb);
5339 This->stateBlock->streamOffset[0] = 0;
5340 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5341 This->stateBlock->streamIsUP = TRUE;
5342 This->stateBlock->loadBaseVertexIndex = 0;
5343
5344 /* TODO: Only mark dirty if drawing from a different UP address */
5345 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5346
5347 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* NumVertices */,
5348 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5349
5350 /* MSDN specifies stream zero settings must be set to NULL */
5351 This->stateBlock->streamStride[0] = 0;
5352 This->stateBlock->streamSource[0] = NULL;
5353
5354 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5355 * the new stream sources or use UP drawing again
5356 */
5357 return WINED3D_OK;
5358 }
5359
5360 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5361 UINT MinVertexIndex, UINT NumVertices,
5362 UINT PrimitiveCount, CONST void* pIndexData,
5363 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5364 UINT VertexStreamZeroStride) {
5365 int idxStride;
5366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5367 IWineD3DVertexBuffer *vb;
5368 IWineD3DIndexBuffer *ib;
5369
5370 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5371 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5372 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5373 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5374
5375 if(!This->stateBlock->vertexDecl) {
5376 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5377 return WINED3DERR_INVALIDCALL;
5378 }
5379
5380 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5381 idxStride = 2;
5382 } else {
5383 idxStride = 4;
5384 }
5385
5386 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5387 vb = This->stateBlock->streamSource[0];
5388 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5389 if(vb) IWineD3DVertexBuffer_Release(vb);
5390 This->stateBlock->streamIsUP = TRUE;
5391 This->stateBlock->streamOffset[0] = 0;
5392 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5393
5394 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5395 This->stateBlock->baseVertexIndex = 0;
5396 This->stateBlock->loadBaseVertexIndex = 0;
5397 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5398 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5399 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5400
5401 drawPrimitive(iface, PrimitiveType, PrimitiveCount, NumVertices, 0 /* start_idx */, idxStride, pIndexData, MinVertexIndex);
5402
5403 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5404 This->stateBlock->streamSource[0] = NULL;
5405 This->stateBlock->streamStride[0] = 0;
5406 ib = This->stateBlock->pIndexData;
5407 if(ib) {
5408 IWineD3DIndexBuffer_Release(ib);
5409 This->stateBlock->pIndexData = NULL;
5410 }
5411 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5412 * SetStreamSource to specify a vertex buffer
5413 */
5414
5415 return WINED3D_OK;
5416 }
5417
5418 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5419 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5420 const WineDirect3DVertexStridedData *DrawPrimStrideData)
5421 {
5422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5423
5424 /* Mark the state dirty until we have nicer tracking
5425 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5426 * that value.
5427 */
5428 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5429 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5430 This->stateBlock->baseVertexIndex = 0;
5431 This->up_strided = DrawPrimStrideData;
5432 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, NULL, 0);
5433 This->up_strided = NULL;
5434 return WINED3D_OK;
5435 }
5436
5437 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5438 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5439 const WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, const void *pIndexData,
5440 WINED3DFORMAT IndexDataFormat)
5441 {
5442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5443 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5444
5445 /* Mark the state dirty until we have nicer tracking
5446 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5447 * that value.
5448 */
5449 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5450 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5451 This->stateBlock->streamIsUP = TRUE;
5452 This->stateBlock->baseVertexIndex = 0;
5453 This->up_strided = DrawPrimStrideData;
5454 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5455 This->up_strided = NULL;
5456 return WINED3D_OK;
5457 }
5458
5459 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5460 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5461 * not callable by the app directly no parameter validation checks are needed here.
5462 */
5463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5464 WINED3DLOCKED_BOX src;
5465 WINED3DLOCKED_BOX dst;
5466 HRESULT hr;
5467 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5468
5469 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5470 * dirtification to improve loading performance.
5471 */
5472 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5473 if(FAILED(hr)) return hr;
5474 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5475 if(FAILED(hr)) {
5476 IWineD3DVolume_UnlockBox(pSourceVolume);
5477 return hr;
5478 }
5479
5480 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5481
5482 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5483 if(FAILED(hr)) {
5484 IWineD3DVolume_UnlockBox(pSourceVolume);
5485 } else {
5486 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5487 }
5488 return hr;
5489 }
5490
5491 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5492 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5494 HRESULT hr = WINED3D_OK;
5495 WINED3DRESOURCETYPE sourceType;
5496 WINED3DRESOURCETYPE destinationType;
5497 int i ,levels;
5498
5499 /* TODO: think about moving the code into IWineD3DBaseTexture */
5500
5501 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5502
5503 /* verify that the source and destination textures aren't NULL */
5504 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5505 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5506 This, pSourceTexture, pDestinationTexture);
5507 hr = WINED3DERR_INVALIDCALL;
5508 }
5509
5510 if (pSourceTexture == pDestinationTexture) {
5511 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5512 This, pSourceTexture, pDestinationTexture);
5513 hr = WINED3DERR_INVALIDCALL;
5514 }
5515 /* Verify that the source and destination textures are the same type */
5516 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5517 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5518
5519 if (sourceType != destinationType) {
5520 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5521 This);
5522 hr = WINED3DERR_INVALIDCALL;
5523 }
5524
5525 /* check that both textures have the identical numbers of levels */
5526 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5527 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5528 hr = WINED3DERR_INVALIDCALL;
5529 }
5530
5531 if (WINED3D_OK == hr) {
5532
5533 /* Make sure that the destination texture is loaded */
5534 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5535
5536 /* Update every surface level of the texture */
5537 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5538
5539 switch (sourceType) {
5540 case WINED3DRTYPE_TEXTURE:
5541 {
5542 IWineD3DSurface *srcSurface;
5543 IWineD3DSurface *destSurface;
5544
5545 for (i = 0 ; i < levels ; ++i) {
5546 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5547 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5548 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5549 IWineD3DSurface_Release(srcSurface);
5550 IWineD3DSurface_Release(destSurface);
5551 if (WINED3D_OK != hr) {
5552 WARN("(%p) : Call to update surface failed\n", This);
5553 return hr;
5554 }
5555 }
5556 }
5557 break;
5558 case WINED3DRTYPE_CUBETEXTURE:
5559 {
5560 IWineD3DSurface *srcSurface;
5561 IWineD3DSurface *destSurface;
5562 WINED3DCUBEMAP_FACES faceType;
5563
5564 for (i = 0 ; i < levels ; ++i) {
5565 /* Update each cube face */
5566 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5567 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5568 if (WINED3D_OK != hr) {
5569 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5570 } else {
5571 TRACE("Got srcSurface %p\n", srcSurface);
5572 }
5573 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5574 if (WINED3D_OK != hr) {
5575 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5576 } else {
5577 TRACE("Got desrSurface %p\n", destSurface);
5578 }
5579 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5580 IWineD3DSurface_Release(srcSurface);
5581 IWineD3DSurface_Release(destSurface);
5582 if (WINED3D_OK != hr) {
5583 WARN("(%p) : Call to update surface failed\n", This);
5584 return hr;
5585 }
5586 }
5587 }
5588 }
5589 break;
5590
5591 case WINED3DRTYPE_VOLUMETEXTURE:
5592 {
5593 IWineD3DVolume *srcVolume = NULL;
5594 IWineD3DVolume *destVolume = NULL;
5595
5596 for (i = 0 ; i < levels ; ++i) {
5597 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5598 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5599 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5600 IWineD3DVolume_Release(srcVolume);
5601 IWineD3DVolume_Release(destVolume);
5602 if (WINED3D_OK != hr) {
5603 WARN("(%p) : Call to update volume failed\n", This);
5604 return hr;
5605 }
5606 }
5607 }
5608 break;
5609
5610 default:
5611 FIXME("(%p) : Unsupported source and destination type\n", This);
5612 hr = WINED3DERR_INVALIDCALL;
5613 }
5614 }
5615
5616 return hr;
5617 }
5618
5619 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5620 IWineD3DSwapChain *swapChain;
5621 HRESULT hr;
5622 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5623 if(hr == WINED3D_OK) {
5624 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5625 IWineD3DSwapChain_Release(swapChain);
5626 }
5627 return hr;
5628 }
5629
5630 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5632 IWineD3DBaseTextureImpl *texture;
5633 const struct GlPixelFormatDesc *gl_info;
5634 DWORD i;
5635
5636 TRACE("(%p) : %p\n", This, pNumPasses);
5637
5638 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5639 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5640 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5641 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5642 }
5643 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5644 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5645 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5646 }
5647
5648 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5649 if(!texture) continue;
5650 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5651 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5652
5653 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5654 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5655 return E_FAIL;
5656 }
5657 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5658 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5659 return E_FAIL;
5660 }
5661 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5662 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5663 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5664 return E_FAIL;
5665 }
5666 }
5667
5668 /* return a sensible default */
5669 *pNumPasses = 1;
5670
5671 TRACE("returning D3D_OK\n");
5672 return WINED3D_OK;
5673 }
5674
5675 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5676 {
5677 int i;
5678
5679 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5680 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5681 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5682 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5683 }
5684 }
5685 }
5686
5687 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5689 int j;
5690 UINT NewSize;
5691 PALETTEENTRY **palettes;
5692
5693 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5694
5695 if (PaletteNumber >= MAX_PALETTES) {
5696 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5697 return WINED3DERR_INVALIDCALL;
5698 }
5699
5700 if (PaletteNumber >= This->NumberOfPalettes) {
5701 NewSize = This->NumberOfPalettes;
5702 do {
5703 NewSize *= 2;
5704 } while(PaletteNumber >= NewSize);
5705 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5706 if (!palettes) {
5707 ERR("Out of memory!\n");
5708 return E_OUTOFMEMORY;
5709 }
5710 This->palettes = palettes;
5711 This->NumberOfPalettes = NewSize;
5712 }
5713
5714 if (!This->palettes[PaletteNumber]) {
5715 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5716 if (!This->palettes[PaletteNumber]) {
5717 ERR("Out of memory!\n");
5718 return E_OUTOFMEMORY;
5719 }
5720 }
5721
5722 for (j = 0; j < 256; ++j) {
5723 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5724 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5725 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5726 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5727 }
5728 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5729 TRACE("(%p) : returning\n", This);
5730 return WINED3D_OK;
5731 }
5732
5733 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5735 int j;
5736 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5737 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5738 /* What happens in such situation isn't documented; Native seems to silently abort
5739 on such conditions. Return Invalid Call. */
5740 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5741 return WINED3DERR_INVALIDCALL;
5742 }
5743 for (j = 0; j < 256; ++j) {
5744 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5745 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5746 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5747 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5748 }
5749 TRACE("(%p) : returning\n", This);
5750 return WINED3D_OK;
5751 }
5752
5753 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5755 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5756 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5757 (tested with reference rasterizer). Return Invalid Call. */
5758 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5759 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5760 return WINED3DERR_INVALIDCALL;
5761 }
5762 /*TODO: stateblocks */
5763 if (This->currentPalette != PaletteNumber) {
5764 This->currentPalette = PaletteNumber;
5765 dirtify_p8_texture_samplers(This);
5766 }
5767 TRACE("(%p) : returning\n", This);
5768 return WINED3D_OK;
5769 }
5770
5771 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5773 if (PaletteNumber == NULL) {
5774 WARN("(%p) : returning Invalid Call\n", This);
5775 return WINED3DERR_INVALIDCALL;
5776 }
5777 /*TODO: stateblocks */
5778 *PaletteNumber = This->currentPalette;
5779 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5780 return WINED3D_OK;
5781 }
5782
5783 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5785 static BOOL warned;
5786 if (!warned)
5787 {
5788 FIXME("(%p) : stub\n", This);
5789 warned = TRUE;
5790 }
5791
5792 This->softwareVertexProcessing = bSoftware;
5793 return WINED3D_OK;
5794 }
5795
5796
5797 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5799 static BOOL warned;
5800 if (!warned)
5801 {
5802 FIXME("(%p) : stub\n", This);
5803 warned = TRUE;
5804 }
5805 return This->softwareVertexProcessing;
5806 }
5807
5808
5809 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5811 IWineD3DSwapChain *swapChain;
5812 HRESULT hr;
5813
5814 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5815
5816 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5817 if(hr == WINED3D_OK){
5818 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5819 IWineD3DSwapChain_Release(swapChain);
5820 }else{
5821 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5822 }
5823 return hr;
5824 }
5825
5826
5827 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5828 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5829 static BOOL warned;
5830 if(nSegments != 0.0f) {
5831 if (!warned)
5832 {
5833 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5834 warned = TRUE;
5835 }
5836 }
5837 return WINED3D_OK;
5838 }
5839
5840 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5842 static BOOL warned;
5843 if (!warned)
5844 {
5845 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5846 warned = TRUE;
5847 }
5848 return 0.0f;
5849 }
5850
5851 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5853 /** TODO: remove casts to IWineD3DSurfaceImpl
5854 * NOTE: move code to surface to accomplish this
5855 ****************************************/
5856 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5857 int srcWidth, srcHeight;
5858 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5859 WINED3DFORMAT destFormat, srcFormat;
5860 UINT destSize;
5861 int srcLeft, destLeft, destTop;
5862 WINED3DPOOL srcPool, destPool;
5863 int offset = 0;
5864 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5865 glDescriptor *glDescription = NULL;
5866 GLenum dummy;
5867 int sampler;
5868 int bpp;
5869 CONVERT_TYPES convert = NO_CONVERSION;
5870
5871 WINED3DSURFACE_DESC winedesc;
5872
5873 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5874 memset(&winedesc, 0, sizeof(winedesc));
5875 winedesc.Width = &srcSurfaceWidth;
5876 winedesc.Height = &srcSurfaceHeight;
5877 winedesc.Pool = &srcPool;
5878 winedesc.Format = &srcFormat;
5879
5880 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5881
5882 winedesc.Width = &destSurfaceWidth;
5883 winedesc.Height = &destSurfaceHeight;
5884 winedesc.Pool = &destPool;
5885 winedesc.Format = &destFormat;
5886 winedesc.Size = &destSize;
5887
5888 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5889
5890 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5891 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5892 return WINED3DERR_INVALIDCALL;
5893 }
5894
5895 /* This call loads the opengl surface directly, instead of copying the surface to the
5896 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5897 * copy in sysmem and use regular surface loading.
5898 */
5899 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5900 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5901 if(convert != NO_CONVERSION) {
5902 return IWineD3DSurface_BltFast(pDestinationSurface,
5903 pDestPoint ? pDestPoint->x : 0,
5904 pDestPoint ? pDestPoint->y : 0,
5905 pSourceSurface, pSourceRect, 0);
5906 }
5907
5908 if (destFormat == WINED3DFMT_UNKNOWN) {
5909 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5910 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5911
5912 /* Get the update surface description */
5913 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5914 }
5915
5916 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5917
5918 ENTER_GL();
5919 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5920 checkGLcall("glActiveTextureARB");
5921 LEAVE_GL();
5922
5923 /* Make sure the surface is loaded and up to date */
5924 IWineD3DSurface_PreLoad(pDestinationSurface);
5925 IWineD3DSurface_BindTexture(pDestinationSurface);
5926
5927 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5928
5929 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5930 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5931 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5932 srcLeft = pSourceRect ? pSourceRect->left : 0;
5933 destLeft = pDestPoint ? pDestPoint->x : 0;
5934 destTop = pDestPoint ? pDestPoint->y : 0;
5935
5936
5937 /* This function doesn't support compressed textures
5938 the pitch is just bytesPerPixel * width */
5939 if(srcWidth != srcSurfaceWidth || srcLeft ){
5940 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5941 offset += srcLeft * pSrcSurface->bytesPerPixel;
5942 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5943 }
5944 /* TODO DXT formats */
5945
5946 if(pSourceRect != NULL && pSourceRect->top != 0){
5947 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5948 }
5949 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5950 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
5951 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5952
5953 /* Sanity check */
5954 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5955
5956 /* need to lock the surface to get the data */
5957 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5958 }
5959
5960 ENTER_GL();
5961
5962 /* TODO: Cube and volume support */
5963 if(rowoffset != 0){
5964 /* not a whole row so we have to do it a line at a time */
5965 int j;
5966
5967 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5968 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5969
5970 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5971
5972 glTexSubImage2D(glDescription->target
5973 ,glDescription->level
5974 ,destLeft
5975 ,j
5976 ,srcWidth
5977 ,1
5978 ,glDescription->glFormat
5979 ,glDescription->glType
5980 ,data /* could be quicker using */
5981 );
5982 data += rowoffset;
5983 }
5984
5985 } else { /* Full width, so just write out the whole texture */
5986 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5987
5988 if (WINED3DFMT_DXT1 == destFormat ||
5989 WINED3DFMT_DXT2 == destFormat ||
5990 WINED3DFMT_DXT3 == destFormat ||
5991 WINED3DFMT_DXT4 == destFormat ||
5992 WINED3DFMT_DXT5 == destFormat) {
5993 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5994 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5995 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5996 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5997 } if (destFormat != srcFormat) {
5998 FIXME("Updating mixed format compressed texture is not curretly support\n");
5999 } else {
6000 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6001 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
6002 }
6003 } else {
6004 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6005 }
6006
6007
6008 } else {
6009 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6010 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
6011 }
6012 }
6013 checkGLcall("glTexSubImage2D");
6014
6015 LEAVE_GL();
6016
6017 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6018 sampler = This->rev_tex_unit_map[0];
6019 if (sampler != -1) {
6020 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6021 }
6022
6023 return WINED3D_OK;
6024 }
6025
6026 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6028 struct WineD3DRectPatch *patch;
6029 unsigned int i;
6030 struct list *e;
6031 BOOL found;
6032 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6033
6034 if(!(Handle || pRectPatchInfo)) {
6035 /* TODO: Write a test for the return value, thus the FIXME */
6036 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6037 return WINED3DERR_INVALIDCALL;
6038 }
6039
6040 if(Handle) {
6041 i = PATCHMAP_HASHFUNC(Handle);
6042 found = FALSE;
6043 LIST_FOR_EACH(e, &This->patches[i]) {
6044 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6045 if(patch->Handle == Handle) {
6046 found = TRUE;
6047 break;
6048 }
6049 }
6050
6051 if(!found) {
6052 TRACE("Patch does not exist. Creating a new one\n");
6053 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6054 patch->Handle = Handle;
6055 list_add_head(&This->patches[i], &patch->entry);
6056 } else {
6057 TRACE("Found existing patch %p\n", patch);
6058 }
6059 } else {
6060 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6061 * attributes we have to tesselate, read back, and draw. This needs a patch
6062 * management structure instance. Create one.
6063 *
6064 * A possible improvement is to check if a vertex shader is used, and if not directly
6065 * draw the patch.
6066 */
6067 FIXME("Drawing an uncached patch. This is slow\n");
6068 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6069 }
6070
6071 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6072 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6073 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6074 HRESULT hr;
6075 TRACE("Tesselation density or patch info changed, retesselating\n");
6076
6077 if(pRectPatchInfo) {
6078 patch->RectPatchInfo = *pRectPatchInfo;
6079 }
6080 patch->numSegs[0] = pNumSegs[0];
6081 patch->numSegs[1] = pNumSegs[1];
6082 patch->numSegs[2] = pNumSegs[2];
6083 patch->numSegs[3] = pNumSegs[3];
6084
6085 hr = tesselate_rectpatch(This, patch);
6086 if(FAILED(hr)) {
6087 WARN("Patch tesselation failed\n");
6088
6089 /* Do not release the handle to store the params of the patch */
6090 if(!Handle) {
6091 HeapFree(GetProcessHeap(), 0, patch);
6092 }
6093 return hr;
6094 }
6095 }
6096
6097 This->currentPatch = patch;
6098 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6099 This->currentPatch = NULL;
6100
6101 /* Destroy uncached patches */
6102 if(!Handle) {
6103 HeapFree(GetProcessHeap(), 0, patch->mem);
6104 HeapFree(GetProcessHeap(), 0, patch);
6105 }
6106 return WINED3D_OK;
6107 }
6108
6109 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6111 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6112 FIXME("(%p) : Stub\n", This);
6113 return WINED3D_OK;
6114 }
6115
6116 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6118 int i;
6119 struct WineD3DRectPatch *patch;
6120 struct list *e;
6121 TRACE("(%p) Handle(%d)\n", This, Handle);
6122
6123 i = PATCHMAP_HASHFUNC(Handle);
6124 LIST_FOR_EACH(e, &This->patches[i]) {
6125 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6126 if(patch->Handle == Handle) {
6127 TRACE("Deleting patch %p\n", patch);
6128 list_remove(&patch->entry);
6129 HeapFree(GetProcessHeap(), 0, patch->mem);
6130 HeapFree(GetProcessHeap(), 0, patch);
6131 return WINED3D_OK;
6132 }
6133 }
6134
6135 /* TODO: Write a test for the return value */
6136 FIXME("Attempt to destroy nonexistent patch\n");
6137 return WINED3DERR_INVALIDCALL;
6138 }
6139
6140 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6141 HRESULT hr;
6142 IWineD3DSwapChain *swapchain;
6143
6144 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6145 if (SUCCEEDED(hr)) {
6146 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6147 return swapchain;
6148 }
6149
6150 return NULL;
6151 }
6152
6153 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6155 IWineD3DSwapChain *swapchain;
6156
6157 swapchain = get_swapchain(surface);
6158 if (swapchain) {
6159 GLenum buffer;
6160
6161 TRACE("Surface %p is onscreen\n", surface);
6162
6163 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6164 ENTER_GL();
6165 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6166 buffer = surface_get_gl_buffer(surface, swapchain);
6167 glDrawBuffer(buffer);
6168 checkGLcall("glDrawBuffer()");
6169 } else {
6170 TRACE("Surface %p is offscreen\n", surface);
6171
6172 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6173 ENTER_GL();
6174 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6175 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6176 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6177 checkGLcall("glFramebufferRenderbufferEXT");
6178 }
6179
6180 if (rect) {
6181 glEnable(GL_SCISSOR_TEST);
6182 if(!swapchain) {
6183 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6184 } else {
6185 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6186 rect->x2 - rect->x1, rect->y2 - rect->y1);
6187 }
6188 checkGLcall("glScissor");
6189 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6190 } else {
6191 glDisable(GL_SCISSOR_TEST);
6192 }
6193 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6194
6195 glDisable(GL_BLEND);
6196 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6197
6198 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6199 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6200
6201 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6202 glClear(GL_COLOR_BUFFER_BIT);
6203 checkGLcall("glClear");
6204
6205 if (This->activeContext->current_fbo) {
6206 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6207 } else {
6208 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6209 checkGLcall("glBindFramebuffer()");
6210 }
6211
6212 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6213 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6214 glDrawBuffer(GL_BACK);
6215 checkGLcall("glDrawBuffer()");
6216 }
6217
6218 LEAVE_GL();
6219 }
6220
6221 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6222 unsigned int r, g, b, a;
6223 DWORD ret;
6224
6225 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6226 destfmt == WINED3DFMT_R8G8B8)
6227 return color;
6228
6229 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6230
6231 a = (color & 0xff000000) >> 24;
6232 r = (color & 0x00ff0000) >> 16;
6233 g = (color & 0x0000ff00) >> 8;
6234 b = (color & 0x000000ff) >> 0;
6235
6236 switch(destfmt)
6237 {
6238 case WINED3DFMT_R5G6B5:
6239 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6240 r = (r * 32) / 256;
6241 g = (g * 64) / 256;
6242 b = (b * 32) / 256;
6243 ret = r << 11;
6244 ret |= g << 5;
6245 ret |= b;
6246 TRACE("Returning %08x\n", ret);
6247 return ret;
6248
6249 case WINED3DFMT_X1R5G5B5:
6250 case WINED3DFMT_A1R5G5B5:
6251 a = (a * 2) / 256;
6252 r = (r * 32) / 256;
6253 g = (g * 32) / 256;
6254 b = (b * 32) / 256;
6255 ret = a << 15;
6256 ret |= r << 10;
6257 ret |= g << 5;
6258 ret |= b << 0;
6259 TRACE("Returning %08x\n", ret);
6260 return ret;
6261
6262 case WINED3DFMT_A8:
6263 TRACE("Returning %08x\n", a);
6264 return a;
6265
6266 case WINED3DFMT_X4R4G4B4:
6267 case WINED3DFMT_A4R4G4B4:
6268 a = (a * 16) / 256;
6269 r = (r * 16) / 256;
6270 g = (g * 16) / 256;
6271 b = (b * 16) / 256;
6272 ret = a << 12;
6273 ret |= r << 8;
6274 ret |= g << 4;
6275 ret |= b << 0;
6276 TRACE("Returning %08x\n", ret);
6277 return ret;
6278
6279 case WINED3DFMT_R3G3B2:
6280 r = (r * 8) / 256;
6281 g = (g * 8) / 256;
6282 b = (b * 4) / 256;
6283 ret = r << 5;
6284 ret |= g << 2;
6285 ret |= b << 0;
6286 TRACE("Returning %08x\n", ret);
6287 return ret;
6288
6289 case WINED3DFMT_X8B8G8R8:
6290 case WINED3DFMT_A8B8G8R8:
6291 ret = a << 24;
6292 ret |= b << 16;
6293 ret |= g << 8;
6294 ret |= r << 0;
6295 TRACE("Returning %08x\n", ret);
6296 return ret;
6297
6298 case WINED3DFMT_A2R10G10B10:
6299 a = (a * 4) / 256;
6300 r = (r * 1024) / 256;
6301 g = (g * 1024) / 256;
6302 b = (b * 1024) / 256;
6303 ret = a << 30;
6304 ret |= r << 20;
6305 ret |= g << 10;
6306 ret |= b << 0;
6307 TRACE("Returning %08x\n", ret);
6308 return ret;
6309
6310 case WINED3DFMT_A2B10G10R10:
6311 a = (a * 4) / 256;
6312 r = (r * 1024) / 256;
6313 g = (g * 1024) / 256;
6314 b = (b * 1024) / 256;
6315 ret = a << 30;
6316 ret |= b << 20;
6317 ret |= g << 10;
6318 ret |= r << 0;
6319 TRACE("Returning %08x\n", ret);
6320 return ret;
6321
6322 default:
6323 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6324 return 0;
6325 }
6326 }
6327
6328 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6330 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6331 WINEDDBLTFX BltFx;
6332 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6333
6334 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6335 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6336 return WINED3DERR_INVALIDCALL;
6337 }
6338
6339 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6340 color_fill_fbo(iface, pSurface, pRect, color);
6341 return WINED3D_OK;
6342 } else {
6343 /* Just forward this to the DirectDraw blitting engine */
6344 memset(&BltFx, 0, sizeof(BltFx));
6345 BltFx.dwSize = sizeof(BltFx);
6346 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6347 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6348 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6349 }
6350 }
6351
6352 /* rendertarget and depth stencil functions */
6353 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6355
6356 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6357 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6358 return WINED3DERR_INVALIDCALL;
6359 }
6360
6361 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6362 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6363 /* Note inc ref on returned surface */
6364 if(*ppRenderTarget != NULL)
6365 IWineD3DSurface_AddRef(*ppRenderTarget);
6366 return WINED3D_OK;
6367 }
6368
6369 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6370 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6371 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6372 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6373 IWineD3DSwapChainImpl *Swapchain;
6374 HRESULT hr;
6375
6376 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6377
6378 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6379 if(hr != WINED3D_OK) {
6380 ERR("Can't get the swapchain\n");
6381 return hr;
6382 }
6383
6384 /* Make sure to release the swapchain */
6385 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6386
6387 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6388 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6389 return WINED3DERR_INVALIDCALL;
6390 }
6391 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6392 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6393 return WINED3DERR_INVALIDCALL;
6394 }
6395
6396 if(Swapchain->frontBuffer != Front) {
6397 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6398
6399 if(Swapchain->frontBuffer)
6400 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6401 Swapchain->frontBuffer = Front;
6402
6403 if(Swapchain->frontBuffer) {
6404 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6405 }
6406 }
6407
6408 if(Back && !Swapchain->backBuffer) {
6409 /* We need memory for the back buffer array - only one back buffer this way */
6410 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6411 if(!Swapchain->backBuffer) {
6412 ERR("Out of memory\n");
6413 return E_OUTOFMEMORY;
6414 }
6415 }
6416
6417 if(Swapchain->backBuffer[0] != Back) {
6418 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6419
6420 /* What to do about the context here in the case of multithreading? Not sure.
6421 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6422 */
6423 ENTER_GL();
6424 if(!Swapchain->backBuffer[0]) {
6425 /* GL was told to draw to the front buffer at creation,
6426 * undo that
6427 */
6428 glDrawBuffer(GL_BACK);
6429 checkGLcall("glDrawBuffer(GL_BACK)");
6430 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6431 Swapchain->presentParms.BackBufferCount = 1;
6432 } else if (!Back) {
6433 /* That makes problems - disable for now */
6434 /* glDrawBuffer(GL_FRONT); */
6435 checkGLcall("glDrawBuffer(GL_FRONT)");
6436 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6437 Swapchain->presentParms.BackBufferCount = 0;
6438 }
6439 LEAVE_GL();
6440
6441 if(Swapchain->backBuffer[0])
6442 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6443 Swapchain->backBuffer[0] = Back;
6444
6445 if(Swapchain->backBuffer[0]) {
6446 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6447 } else {
6448 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6449 Swapchain->backBuffer = NULL;
6450 }
6451
6452 }
6453
6454 return WINED3D_OK;
6455 }
6456
6457 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6459 *ppZStencilSurface = This->stencilBufferTarget;
6460 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6461
6462 if(*ppZStencilSurface != NULL) {
6463 /* Note inc ref on returned surface */
6464 IWineD3DSurface_AddRef(*ppZStencilSurface);
6465 return WINED3D_OK;
6466 } else {
6467 return WINED3DERR_NOTFOUND;
6468 }
6469 }
6470
6471 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6472 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6473 {
6474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6475 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6476 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6477 GLenum gl_filter;
6478 POINT offset = {0, 0};
6479
6480 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6481 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6482 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6483 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6484
6485 switch (filter) {
6486 case WINED3DTEXF_LINEAR:
6487 gl_filter = GL_LINEAR;
6488 break;
6489
6490 default:
6491 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6492 case WINED3DTEXF_NONE:
6493 case WINED3DTEXF_POINT:
6494 gl_filter = GL_NEAREST;
6495 break;
6496 }
6497
6498 /* Attach src surface to src fbo */
6499 src_swapchain = get_swapchain(src_surface);
6500 if (src_swapchain) {
6501 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6502
6503 TRACE("Source surface %p is onscreen\n", src_surface);
6504 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6505 /* Make sure the drawable is up to date. In the offscreen case
6506 * attach_surface_fbo() implicitly takes care of this. */
6507 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6508
6509 if(buffer == GL_FRONT) {
6510 RECT windowsize;
6511 UINT h;
6512 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6513 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6514 h = windowsize.bottom - windowsize.top;
6515 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6516 src_rect->y1 = offset.y + h - src_rect->y1;
6517 src_rect->y2 = offset.y + h - src_rect->y2;
6518 } else {
6519 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6520 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6521 }
6522
6523 ENTER_GL();
6524 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6525 glReadBuffer(buffer);
6526 checkGLcall("glReadBuffer()");
6527 } else {
6528 TRACE("Source surface %p is offscreen\n", src_surface);
6529 ENTER_GL();
6530 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6531 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6532 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6533 checkGLcall("glReadBuffer()");
6534 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6535 checkGLcall("glFramebufferRenderbufferEXT");
6536 }
6537 LEAVE_GL();
6538
6539 /* Attach dst surface to dst fbo */
6540 dst_swapchain = get_swapchain(dst_surface);
6541 if (dst_swapchain) {
6542 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6543
6544 TRACE("Destination surface %p is onscreen\n", dst_surface);
6545 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6546 /* Make sure the drawable is up to date. In the offscreen case
6547 * attach_surface_fbo() implicitly takes care of this. */
6548 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6549
6550 if(buffer == GL_FRONT) {
6551 RECT windowsize;
6552 UINT h;
6553 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6554 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6555 h = windowsize.bottom - windowsize.top;
6556 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6557 dst_rect->y1 = offset.y + h - dst_rect->y1;
6558 dst_rect->y2 = offset.y + h - dst_rect->y2;
6559 } else {
6560 /* Screen coords = window coords, surface height = window height */
6561 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6562 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6563 }
6564
6565 ENTER_GL();
6566 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6567 glDrawBuffer(buffer);
6568 checkGLcall("glDrawBuffer()");
6569 } else {
6570 TRACE("Destination surface %p is offscreen\n", dst_surface);
6571
6572 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6573 if(!src_swapchain) {
6574 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6575 }
6576
6577 ENTER_GL();
6578 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6579 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6580 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6581 checkGLcall("glDrawBuffer()");
6582 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6583 checkGLcall("glFramebufferRenderbufferEXT");
6584 }
6585 glDisable(GL_SCISSOR_TEST);
6586 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6587
6588 if (flip) {
6589 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6590 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6591 checkGLcall("glBlitFramebuffer()");
6592 } else {
6593 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6594 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6595 checkGLcall("glBlitFramebuffer()");
6596 }
6597
6598 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6599
6600 if (This->activeContext->current_fbo) {
6601 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6602 } else {
6603 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6604 checkGLcall("glBindFramebuffer()");
6605 }
6606
6607 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6608 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6609 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6610 glDrawBuffer(GL_BACK);
6611 checkGLcall("glDrawBuffer()");
6612 }
6613 LEAVE_GL();
6614 }
6615
6616 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6618 WINED3DVIEWPORT viewport;
6619
6620 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6621
6622 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6623 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6624 This, RenderTargetIndex, GL_LIMITS(buffers));
6625 return WINED3DERR_INVALIDCALL;
6626 }
6627
6628 /* MSDN says that null disables the render target
6629 but a device must always be associated with a render target
6630 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6631 */
6632 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6633 FIXME("Trying to set render target 0 to NULL\n");
6634 return WINED3DERR_INVALIDCALL;
6635 }
6636 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6637 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);
6638 return WINED3DERR_INVALIDCALL;
6639 }
6640
6641 /* If we are trying to set what we already have, don't bother */
6642 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6643 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6644 return WINED3D_OK;
6645 }
6646 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6647 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6648 This->render_targets[RenderTargetIndex] = pRenderTarget;
6649
6650 /* Render target 0 is special */
6651 if(RenderTargetIndex == 0) {
6652 /* Finally, reset the viewport as the MSDN states. */
6653 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6654 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6655 viewport.X = 0;
6656 viewport.Y = 0;
6657 viewport.MaxZ = 1.0f;
6658 viewport.MinZ = 0.0f;
6659 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6660 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6661 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6662 */
6663 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6664 }
6665 return WINED3D_OK;
6666 }
6667
6668 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6670 HRESULT hr = WINED3D_OK;
6671 IWineD3DSurface *tmp;
6672
6673 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6674
6675 if (pNewZStencil == This->stencilBufferTarget) {
6676 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6677 } else {
6678 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6679 * depending on the renter target implementation being used.
6680 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6681 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6682 * stencil buffer and incur an extra memory overhead
6683 ******************************************************/
6684
6685 if (This->stencilBufferTarget) {
6686 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6687 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6688 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6689 } else {
6690 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6691 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6692 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6693 }
6694 }
6695
6696 tmp = This->stencilBufferTarget;
6697 This->stencilBufferTarget = pNewZStencil;
6698 /* should we be calling the parent or the wined3d surface? */
6699 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6700 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6701 hr = WINED3D_OK;
6702
6703 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6704 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6705 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6706 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6707 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6708 }
6709 }
6710
6711 return hr;
6712 }
6713
6714 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6715 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6717 /* TODO: the use of Impl is deprecated. */
6718 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6719 WINED3DLOCKED_RECT lockedRect;
6720
6721 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6722
6723 /* some basic validation checks */
6724 if(This->cursorTexture) {
6725 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6726 ENTER_GL();
6727 glDeleteTextures(1, &This->cursorTexture);
6728 LEAVE_GL();
6729 This->cursorTexture = 0;
6730 }
6731
6732 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6733 This->haveHardwareCursor = TRUE;
6734 else
6735 This->haveHardwareCursor = FALSE;
6736
6737 if(pCursorBitmap) {
6738 WINED3DLOCKED_RECT rect;
6739
6740 /* MSDN: Cursor must be A8R8G8B8 */
6741 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6742 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6743 return WINED3DERR_INVALIDCALL;
6744 }
6745
6746 /* MSDN: Cursor must be smaller than the display mode */
6747 if(pSur->currentDesc.Width > This->ddraw_width ||
6748 pSur->currentDesc.Height > This->ddraw_height) {
6749 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);
6750 return WINED3DERR_INVALIDCALL;
6751 }
6752
6753 if (!This->haveHardwareCursor) {
6754 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6755
6756 /* Do not store the surface's pointer because the application may
6757 * release it after setting the cursor image. Windows doesn't
6758 * addref the set surface, so we can't do this either without
6759 * creating circular refcount dependencies. Copy out the gl texture
6760 * instead.
6761 */
6762 This->cursorWidth = pSur->currentDesc.Width;
6763 This->cursorHeight = pSur->currentDesc.Height;
6764 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6765 {
6766 const struct GlPixelFormatDesc *glDesc;
6767 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6768 char *mem, *bits = (char *)rect.pBits;
6769 GLint intfmt = glDesc->glInternal;
6770 GLint format = glDesc->glFormat;
6771 GLint type = glDesc->glType;
6772 INT height = This->cursorHeight;
6773 INT width = This->cursorWidth;
6774 INT bpp = tableEntry->bpp;
6775 INT i, sampler;
6776
6777 /* Reformat the texture memory (pitch and width can be
6778 * different) */
6779 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6780 for(i = 0; i < height; i++)
6781 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6782 IWineD3DSurface_UnlockRect(pCursorBitmap);
6783 ENTER_GL();
6784
6785 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6786 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6787 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6788 }
6789
6790 /* Make sure that a proper texture unit is selected */
6791 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6792 checkGLcall("glActiveTextureARB");
6793 sampler = This->rev_tex_unit_map[0];
6794 if (sampler != -1) {
6795 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6796 }
6797 /* Create a new cursor texture */
6798 glGenTextures(1, &This->cursorTexture);
6799 checkGLcall("glGenTextures");
6800 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6801 checkGLcall("glBindTexture");
6802 /* Copy the bitmap memory into the cursor texture */
6803 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6804 HeapFree(GetProcessHeap(), 0, mem);
6805 checkGLcall("glTexImage2D");
6806
6807 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6808 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6809 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6810 }
6811
6812 LEAVE_GL();
6813 }
6814 else
6815 {
6816 FIXME("A cursor texture was not returned.\n");
6817 This->cursorTexture = 0;
6818 }
6819 }
6820 else
6821 {
6822 /* Draw a hardware cursor */
6823 ICONINFO cursorInfo;
6824 HCURSOR cursor;
6825 /* Create and clear maskBits because it is not needed for
6826 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6827 * chunks. */
6828 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6829 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6830 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6831 WINED3DLOCK_NO_DIRTY_UPDATE |
6832 WINED3DLOCK_READONLY
6833 );
6834 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6835 pSur->currentDesc.Height);
6836
6837 cursorInfo.fIcon = FALSE;
6838 cursorInfo.xHotspot = XHotSpot;
6839 cursorInfo.yHotspot = YHotSpot;
6840 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6841 pSur->currentDesc.Height, 1,
6842 1, &maskBits);
6843 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6844 pSur->currentDesc.Height, 1,
6845 32, lockedRect.pBits);
6846 IWineD3DSurface_UnlockRect(pCursorBitmap);
6847 /* Create our cursor and clean up. */
6848 cursor = CreateIconIndirect(&cursorInfo);
6849 SetCursor(cursor);
6850 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6851 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6852 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6853 This->hardwareCursor = cursor;
6854 HeapFree(GetProcessHeap(), 0, maskBits);
6855 }
6856 }
6857
6858 This->xHotSpot = XHotSpot;
6859 This->yHotSpot = YHotSpot;
6860 return WINED3D_OK;
6861 }
6862
6863 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6865 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6866
6867 This->xScreenSpace = XScreenSpace;
6868 This->yScreenSpace = YScreenSpace;
6869
6870 return;
6871
6872 }
6873
6874 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6876 BOOL oldVisible = This->bCursorVisible;
6877 POINT pt;
6878
6879 TRACE("(%p) : visible(%d)\n", This, bShow);
6880
6881 /*
6882 * When ShowCursor is first called it should make the cursor appear at the OS's last
6883 * known cursor position. Because of this, some applications just repetitively call
6884 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6885 */
6886 GetCursorPos(&pt);
6887 This->xScreenSpace = pt.x;
6888 This->yScreenSpace = pt.y;
6889
6890 if (This->haveHardwareCursor) {
6891 This->bCursorVisible = bShow;
6892 if (bShow)
6893 SetCursor(This->hardwareCursor);
6894 else
6895 SetCursor(NULL);
6896 }
6897 else
6898 {
6899 if (This->cursorTexture)
6900 This->bCursorVisible = bShow;
6901 }
6902
6903 return oldVisible;
6904 }
6905
6906 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6907 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6908 IWineD3DResourceImpl *resource;
6909 TRACE("(%p) : state (%u)\n", This, This->state);
6910
6911 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6912 switch (This->state) {
6913 case WINED3D_OK:
6914 return WINED3D_OK;
6915 case WINED3DERR_DEVICELOST:
6916 {
6917 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6918 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6919 return WINED3DERR_DEVICENOTRESET;
6920 }
6921 return WINED3DERR_DEVICELOST;
6922 }
6923 case WINED3DERR_DRIVERINTERNALERROR:
6924 return WINED3DERR_DRIVERINTERNALERROR;
6925 }
6926
6927 /* Unknown state */
6928 return WINED3DERR_DRIVERINTERNALERROR;
6929 }
6930
6931
6932 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6934 /** FIXME: Resource tracking needs to be done,
6935 * The closes we can do to this is set the priorities of all managed textures low
6936 * and then reset them.
6937 ***********************************************************/
6938 FIXME("(%p) : stub\n", This);
6939 return WINED3D_OK;
6940 }
6941
6942 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6943 {
6944 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6945
6946 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6947 if(surface->Flags & SFLAG_DIBSECTION) {
6948 /* Release the DC */
6949 SelectObject(surface->hDC, surface->dib.holdbitmap);
6950 DeleteDC(surface->hDC);
6951 /* Release the DIB section */
6952 DeleteObject(surface->dib.DIBsection);
6953 surface->dib.bitmap_data = NULL;
6954 surface->resource.allocatedMemory = NULL;
6955 surface->Flags &= ~SFLAG_DIBSECTION;
6956 }
6957 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6958 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6959 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6960 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6961 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6962 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6963 } else {
6964 surface->pow2Width = surface->pow2Height = 1;
6965 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6966 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6967 }
6968 surface->glRect.left = 0;
6969 surface->glRect.top = 0;
6970 surface->glRect.right = surface->pow2Width;
6971 surface->glRect.bottom = surface->pow2Height;
6972
6973 if(surface->glDescription.textureName) {
6974 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6975 ENTER_GL();
6976 glDeleteTextures(1, &surface->glDescription.textureName);
6977 LEAVE_GL();
6978 surface->glDescription.textureName = 0;
6979 surface->Flags &= ~SFLAG_CLIENT;
6980 }
6981 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6982 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6983 surface->Flags |= SFLAG_NONPOW2;
6984 } else {
6985 surface->Flags &= ~SFLAG_NONPOW2;
6986 }
6987 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6988 surface->resource.allocatedMemory = NULL;
6989 surface->resource.heapMemory = NULL;
6990 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6991 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6992 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6993 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6994 } else {
6995 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6996 }
6997 }
6998
6999 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7000 TRACE("Unloading resource %p\n", resource);
7001 IWineD3DResource_UnLoad(resource);
7002 IWineD3DResource_Release(resource);
7003 return S_OK;
7004 }
7005
7006 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7007 {
7008 UINT i, count;
7009 WINED3DDISPLAYMODE m;
7010 HRESULT hr;
7011
7012 /* All Windowed modes are supported, as is leaving the current mode */
7013 if(pp->Windowed) return TRUE;
7014 if(!pp->BackBufferWidth) return TRUE;
7015 if(!pp->BackBufferHeight) return TRUE;
7016
7017 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7018 for(i = 0; i < count; i++) {
7019 memset(&m, 0, sizeof(m));
7020 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7021 if(FAILED(hr)) {
7022 ERR("EnumAdapterModes failed\n");
7023 }
7024 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7025 /* Mode found, it is supported */
7026 return TRUE;
7027 }
7028 }
7029 /* Mode not found -> not supported */
7030 return FALSE;
7031 }
7032
7033 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7035 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7036 UINT i;
7037 IWineD3DBaseShaderImpl *shader;
7038
7039 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7040 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7041 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7042 }
7043
7044 ENTER_GL();
7045 if(This->depth_blt_texture) {
7046 glDeleteTextures(1, &This->depth_blt_texture);
7047 This->depth_blt_texture = 0;
7048 }
7049 if (This->depth_blt_rb) {
7050 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7051 This->depth_blt_rb = 0;
7052 This->depth_blt_rb_w = 0;
7053 This->depth_blt_rb_h = 0;
7054 }
7055 LEAVE_GL();
7056
7057 This->blitter->free_private(iface);
7058 This->frag_pipe->free_private(iface);
7059 This->shader_backend->shader_free_private(iface);
7060
7061 ENTER_GL();
7062 for (i = 0; i < GL_LIMITS(textures); i++) {
7063 /* Textures are recreated below */
7064 glDeleteTextures(1, &This->dummyTextureName[i]);
7065 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7066 This->dummyTextureName[i] = 0;
7067 }
7068 LEAVE_GL();
7069
7070 while(This->numContexts) {
7071 DestroyContext(This, This->contexts[0]);
7072 }
7073 This->activeContext = NULL;
7074 HeapFree(GetProcessHeap(), 0, swapchain->context);
7075 swapchain->context = NULL;
7076 swapchain->num_contexts = 0;
7077 }
7078
7079 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7080 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7081 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7082 HRESULT hr;
7083 IWineD3DSurfaceImpl *target;
7084
7085 /* Recreate the primary swapchain's context */
7086 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7087 if(swapchain->backBuffer) {
7088 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7089 } else {
7090 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7091 }
7092 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7093 &swapchain->presentParms);
7094 swapchain->num_contexts = 1;
7095 This->activeContext = swapchain->context[0];
7096
7097 create_dummy_textures(This);
7098
7099 hr = This->shader_backend->shader_alloc_private(iface);
7100 if(FAILED(hr)) {
7101 ERR("Failed to recreate shader private data\n");
7102 goto err_out;
7103 }
7104 hr = This->frag_pipe->alloc_private(iface);
7105 if(FAILED(hr)) {
7106 TRACE("Fragment pipeline private data couldn't be allocated\n");
7107 goto err_out;
7108 }
7109 hr = This->blitter->alloc_private(iface);
7110 if(FAILED(hr)) {
7111 TRACE("Blitter private data couldn't be allocated\n");
7112 goto err_out;
7113 }
7114
7115 return WINED3D_OK;
7116
7117 err_out:
7118 This->blitter->free_private(iface);
7119 This->frag_pipe->free_private(iface);
7120 This->shader_backend->shader_free_private(iface);
7121 return hr;
7122 }
7123
7124 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7126 IWineD3DSwapChainImpl *swapchain;
7127 HRESULT hr;
7128 BOOL DisplayModeChanged = FALSE;
7129 WINED3DDISPLAYMODE mode;
7130 TRACE("(%p)\n", This);
7131
7132 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7133 if(FAILED(hr)) {
7134 ERR("Failed to get the first implicit swapchain\n");
7135 return hr;
7136 }
7137
7138 if(!is_display_mode_supported(This, pPresentationParameters)) {
7139 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7140 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7141 pPresentationParameters->BackBufferHeight);
7142 return WINED3DERR_INVALIDCALL;
7143 }
7144
7145 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7146 * on an existing gl context, so there's no real need for recreation.
7147 *
7148 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7149 *
7150 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7151 */
7152 TRACE("New params:\n");
7153 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7154 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7155 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7156 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7157 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7158 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7159 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7160 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7161 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7162 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7163 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7164 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7165 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7166
7167 /* No special treatment of these parameters. Just store them */
7168 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7169 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7170 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7171 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7172
7173 /* What to do about these? */
7174 if(pPresentationParameters->BackBufferCount != 0 &&
7175 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7176 ERR("Cannot change the back buffer count yet\n");
7177 }
7178 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7179 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7180 ERR("Cannot change the back buffer format yet\n");
7181 }
7182 if(pPresentationParameters->hDeviceWindow != NULL &&
7183 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7184 ERR("Cannot change the device window yet\n");
7185 }
7186 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7187 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7188 return WINED3DERR_INVALIDCALL;
7189 }
7190
7191 /* Reset the depth stencil */
7192 if (pPresentationParameters->EnableAutoDepthStencil)
7193 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7194 else
7195 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7196
7197 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7198
7199 if(pPresentationParameters->Windowed) {
7200 mode.Width = swapchain->orig_width;
7201 mode.Height = swapchain->orig_height;
7202 mode.RefreshRate = 0;
7203 mode.Format = swapchain->presentParms.BackBufferFormat;
7204 } else {
7205 mode.Width = pPresentationParameters->BackBufferWidth;
7206 mode.Height = pPresentationParameters->BackBufferHeight;
7207 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7208 mode.Format = swapchain->presentParms.BackBufferFormat;
7209 }
7210
7211 /* Should Width == 800 && Height == 0 set 800x600? */
7212 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7213 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7214 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7215 {
7216 UINT i;
7217
7218 if(!pPresentationParameters->Windowed) {
7219 DisplayModeChanged = TRUE;
7220 }
7221 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7222 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7223
7224 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7225 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7226 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7227 }
7228 if(This->auto_depth_stencil_buffer) {
7229 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7230 }
7231 }
7232
7233 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7234 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7235 DisplayModeChanged) {
7236
7237 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7238
7239 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7240 if(swapchain->presentParms.Windowed) {
7241 /* switch from windowed to fs */
7242 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7243 pPresentationParameters->BackBufferWidth,
7244 pPresentationParameters->BackBufferHeight);
7245 } else {
7246 /* Fullscreen -> fullscreen mode change */
7247 MoveWindow(swapchain->win_handle, 0, 0,
7248 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7249 TRUE);
7250 }
7251 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7252 /* Fullscreen -> windowed switch */
7253 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7254 }
7255 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7256 } else if(!pPresentationParameters->Windowed) {
7257 DWORD style = This->style, exStyle = This->exStyle;
7258 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7259 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7260 * Reset to clear up their mess. Guild Wars also loses the device during that.
7261 */
7262 This->style = 0;
7263 This->exStyle = 0;
7264 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7265 pPresentationParameters->BackBufferWidth,
7266 pPresentationParameters->BackBufferHeight);
7267 This->style = style;
7268 This->exStyle = exStyle;
7269 }
7270
7271 TRACE("Resetting stateblock\n");
7272 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7273 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7274
7275 /* Note: No parent needed for initial internal stateblock */
7276 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7277 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7278 else TRACE("Created stateblock %p\n", This->stateBlock);
7279 This->updateStateBlock = This->stateBlock;
7280 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7281
7282 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7283 if(FAILED(hr)) {
7284 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7285 }
7286
7287 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7288 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7289
7290 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7291 * first use
7292 */
7293 return hr;
7294 }
7295
7296 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7298 /** FIXME: always true at the moment **/
7299 if(!bEnableDialogs) {
7300 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7301 }
7302 return WINED3D_OK;
7303 }
7304
7305
7306 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7308 TRACE("(%p) : pParameters %p\n", This, pParameters);
7309
7310 *pParameters = This->createParms;
7311 return WINED3D_OK;
7312 }
7313
7314 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7315 IWineD3DSwapChain *swapchain;
7316
7317 TRACE("Relaying to swapchain\n");
7318
7319 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7320 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7321 IWineD3DSwapChain_Release(swapchain);
7322 }
7323 return;
7324 }
7325
7326 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7327 IWineD3DSwapChain *swapchain;
7328
7329 TRACE("Relaying to swapchain\n");
7330
7331 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7332 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7333 IWineD3DSwapChain_Release(swapchain);
7334 }
7335 return;
7336 }
7337
7338
7339 /** ********************************************************
7340 * Notification functions
7341 ** ********************************************************/
7342 /** This function must be called in the release of a resource when ref == 0,
7343 * the contents of resource must still be correct,
7344 * any handles to other resource held by the caller must be closed
7345 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7346 *****************************************************/
7347 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7349
7350 TRACE("(%p) : Adding Resource %p\n", This, resource);
7351 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7352 }
7353
7354 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7356
7357 TRACE("(%p) : Removing resource %p\n", This, resource);
7358
7359 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7360 }
7361
7362
7363 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7365 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7366 int counter;
7367
7368 TRACE("(%p) : resource %p\n", This, resource);
7369
7370 context_resource_released(iface, resource, type);
7371
7372 switch (type) {
7373 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7374 case WINED3DRTYPE_SURFACE: {
7375 unsigned int i;
7376
7377 /* Cleanup any FBO attachments if d3d is enabled */
7378 if(This->d3d_initialized) {
7379 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7380 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7381
7382 TRACE("Last active render target destroyed\n");
7383 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7384 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7385 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7386 * and the lastActiveRenderTarget member shouldn't matter
7387 */
7388 if(swapchain) {
7389 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7390 TRACE("Activating primary back buffer\n");
7391 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7392 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7393 /* Single buffering environment */
7394 TRACE("Activating primary front buffer\n");
7395 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7396 } else {
7397 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7398 /* Implicit render target destroyed, that means the device is being destroyed
7399 * whatever we set here, it shouldn't matter
7400 */
7401 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7402 }
7403 } else {
7404 /* May happen during ddraw uninitialization */
7405 TRACE("Render target set, but swapchain does not exist!\n");
7406 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7407 }
7408 }
7409
7410 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7411 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7412 This->render_targets[i] = NULL;
7413 }
7414 }
7415 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7416 This->stencilBufferTarget = NULL;
7417 }
7418 }
7419
7420 break;
7421 }
7422 case WINED3DRTYPE_TEXTURE:
7423 case WINED3DRTYPE_CUBETEXTURE:
7424 case WINED3DRTYPE_VOLUMETEXTURE:
7425 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7426 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7427 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7428 This->stateBlock->textures[counter] = NULL;
7429 }
7430 if (This->updateStateBlock != This->stateBlock ){
7431 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7432 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7433 This->updateStateBlock->textures[counter] = NULL;
7434 }
7435 }
7436 }
7437 break;
7438 case WINED3DRTYPE_VOLUME:
7439 /* TODO: nothing really? */
7440 break;
7441 case WINED3DRTYPE_VERTEXBUFFER:
7442 {
7443 int streamNumber;
7444 TRACE("Cleaning up stream pointers\n");
7445
7446 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7447 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7448 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7449 */
7450 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7451 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7452 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7453 This->updateStateBlock->streamSource[streamNumber] = 0;
7454 /* Set changed flag? */
7455 }
7456 }
7457 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) */
7458 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7459 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7460 This->stateBlock->streamSource[streamNumber] = 0;
7461 }
7462 }
7463 }
7464 }
7465 break;
7466 case WINED3DRTYPE_INDEXBUFFER:
7467 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7468 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7469 This->updateStateBlock->pIndexData = NULL;
7470 }
7471 }
7472 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7473 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7474 This->stateBlock->pIndexData = NULL;
7475 }
7476 }
7477
7478 break;
7479 default:
7480 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7481 break;
7482 }
7483
7484
7485 /* Remove the resource from the resourceStore */
7486 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7487
7488 TRACE("Resource released\n");
7489
7490 }
7491
7492 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7494 IWineD3DResourceImpl *resource, *cursor;
7495 HRESULT ret;
7496 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7497
7498 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7499 TRACE("enumerating resource %p\n", resource);
7500 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7501 ret = pCallback((IWineD3DResource *) resource, pData);
7502 if(ret == S_FALSE) {
7503 TRACE("Canceling enumeration\n");
7504 break;
7505 }
7506 }
7507 return WINED3D_OK;
7508 }
7509
7510 /**********************************************************
7511 * IWineD3DDevice VTbl follows
7512 **********************************************************/
7513
7514 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7515 {
7516 /*** IUnknown methods ***/
7517 IWineD3DDeviceImpl_QueryInterface,
7518 IWineD3DDeviceImpl_AddRef,
7519 IWineD3DDeviceImpl_Release,
7520 /*** IWineD3DDevice methods ***/
7521 IWineD3DDeviceImpl_GetParent,
7522 /*** Creation methods**/
7523 IWineD3DDeviceImpl_CreateVertexBuffer,
7524 IWineD3DDeviceImpl_CreateIndexBuffer,
7525 IWineD3DDeviceImpl_CreateStateBlock,
7526 IWineD3DDeviceImpl_CreateSurface,
7527 IWineD3DDeviceImpl_CreateTexture,
7528 IWineD3DDeviceImpl_CreateVolumeTexture,
7529 IWineD3DDeviceImpl_CreateVolume,
7530 IWineD3DDeviceImpl_CreateCubeTexture,
7531 IWineD3DDeviceImpl_CreateQuery,
7532 IWineD3DDeviceImpl_CreateSwapChain,
7533 IWineD3DDeviceImpl_CreateVertexDeclaration,
7534 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7535 IWineD3DDeviceImpl_CreateVertexShader,
7536 IWineD3DDeviceImpl_CreatePixelShader,
7537 IWineD3DDeviceImpl_CreatePalette,
7538 /*** Odd functions **/
7539 IWineD3DDeviceImpl_Init3D,
7540 IWineD3DDeviceImpl_InitGDI,
7541 IWineD3DDeviceImpl_Uninit3D,
7542 IWineD3DDeviceImpl_UninitGDI,
7543 IWineD3DDeviceImpl_SetMultithreaded,
7544 IWineD3DDeviceImpl_EvictManagedResources,
7545 IWineD3DDeviceImpl_GetAvailableTextureMem,
7546 IWineD3DDeviceImpl_GetBackBuffer,
7547 IWineD3DDeviceImpl_GetCreationParameters,
7548 IWineD3DDeviceImpl_GetDeviceCaps,
7549 IWineD3DDeviceImpl_GetDirect3D,
7550 IWineD3DDeviceImpl_GetDisplayMode,
7551 IWineD3DDeviceImpl_SetDisplayMode,
7552 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7553 IWineD3DDeviceImpl_GetRasterStatus,
7554 IWineD3DDeviceImpl_GetSwapChain,
7555 IWineD3DDeviceImpl_Reset,
7556 IWineD3DDeviceImpl_SetDialogBoxMode,
7557 IWineD3DDeviceImpl_SetCursorProperties,
7558 IWineD3DDeviceImpl_SetCursorPosition,
7559 IWineD3DDeviceImpl_ShowCursor,
7560 IWineD3DDeviceImpl_TestCooperativeLevel,
7561 /*** Getters and setters **/
7562 IWineD3DDeviceImpl_SetClipPlane,
7563 IWineD3DDeviceImpl_GetClipPlane,
7564 IWineD3DDeviceImpl_SetClipStatus,
7565 IWineD3DDeviceImpl_GetClipStatus,
7566 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7567 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7568 IWineD3DDeviceImpl_SetDepthStencilSurface,
7569 IWineD3DDeviceImpl_GetDepthStencilSurface,
7570 IWineD3DDeviceImpl_SetGammaRamp,
7571 IWineD3DDeviceImpl_GetGammaRamp,
7572 IWineD3DDeviceImpl_SetIndices,
7573 IWineD3DDeviceImpl_GetIndices,
7574 IWineD3DDeviceImpl_SetBaseVertexIndex,
7575 IWineD3DDeviceImpl_GetBaseVertexIndex,
7576 IWineD3DDeviceImpl_SetLight,
7577 IWineD3DDeviceImpl_GetLight,
7578 IWineD3DDeviceImpl_SetLightEnable,
7579 IWineD3DDeviceImpl_GetLightEnable,
7580 IWineD3DDeviceImpl_SetMaterial,
7581 IWineD3DDeviceImpl_GetMaterial,
7582 IWineD3DDeviceImpl_SetNPatchMode,
7583 IWineD3DDeviceImpl_GetNPatchMode,
7584 IWineD3DDeviceImpl_SetPaletteEntries,
7585 IWineD3DDeviceImpl_GetPaletteEntries,
7586 IWineD3DDeviceImpl_SetPixelShader,
7587 IWineD3DDeviceImpl_GetPixelShader,
7588 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7589 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7590 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7591 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7592 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7593 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7594 IWineD3DDeviceImpl_SetRenderState,
7595 IWineD3DDeviceImpl_GetRenderState,
7596 IWineD3DDeviceImpl_SetRenderTarget,
7597 IWineD3DDeviceImpl_GetRenderTarget,
7598 IWineD3DDeviceImpl_SetFrontBackBuffers,
7599 IWineD3DDeviceImpl_SetSamplerState,
7600 IWineD3DDeviceImpl_GetSamplerState,
7601 IWineD3DDeviceImpl_SetScissorRect,
7602 IWineD3DDeviceImpl_GetScissorRect,
7603 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7604 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7605 IWineD3DDeviceImpl_SetStreamSource,
7606 IWineD3DDeviceImpl_GetStreamSource,
7607 IWineD3DDeviceImpl_SetStreamSourceFreq,
7608 IWineD3DDeviceImpl_GetStreamSourceFreq,
7609 IWineD3DDeviceImpl_SetTexture,
7610 IWineD3DDeviceImpl_GetTexture,
7611 IWineD3DDeviceImpl_SetTextureStageState,
7612 IWineD3DDeviceImpl_GetTextureStageState,
7613 IWineD3DDeviceImpl_SetTransform,
7614 IWineD3DDeviceImpl_GetTransform,
7615 IWineD3DDeviceImpl_SetVertexDeclaration,
7616 IWineD3DDeviceImpl_GetVertexDeclaration,
7617 IWineD3DDeviceImpl_SetVertexShader,
7618 IWineD3DDeviceImpl_GetVertexShader,
7619 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7620 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7621 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7622 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7623 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7624 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7625 IWineD3DDeviceImpl_SetViewport,
7626 IWineD3DDeviceImpl_GetViewport,
7627 IWineD3DDeviceImpl_MultiplyTransform,
7628 IWineD3DDeviceImpl_ValidateDevice,
7629 IWineD3DDeviceImpl_ProcessVertices,
7630 /*** State block ***/
7631 IWineD3DDeviceImpl_BeginStateBlock,
7632 IWineD3DDeviceImpl_EndStateBlock,
7633 /*** Scene management ***/
7634 IWineD3DDeviceImpl_BeginScene,
7635 IWineD3DDeviceImpl_EndScene,
7636 IWineD3DDeviceImpl_Present,
7637 IWineD3DDeviceImpl_Clear,
7638 /*** Drawing ***/
7639 IWineD3DDeviceImpl_DrawPrimitive,
7640 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7641 IWineD3DDeviceImpl_DrawPrimitiveUP,
7642 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7643 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7644 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7645 IWineD3DDeviceImpl_DrawRectPatch,
7646 IWineD3DDeviceImpl_DrawTriPatch,
7647 IWineD3DDeviceImpl_DeletePatch,
7648 IWineD3DDeviceImpl_ColorFill,
7649 IWineD3DDeviceImpl_UpdateTexture,
7650 IWineD3DDeviceImpl_UpdateSurface,
7651 IWineD3DDeviceImpl_GetFrontBufferData,
7652 /*** object tracking ***/
7653 IWineD3DDeviceImpl_ResourceReleased,
7654 IWineD3DDeviceImpl_EnumResources
7655 };
7656
7657 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7658 WINED3DRS_ALPHABLENDENABLE ,
7659 WINED3DRS_ALPHAFUNC ,
7660 WINED3DRS_ALPHAREF ,
7661 WINED3DRS_ALPHATESTENABLE ,
7662 WINED3DRS_BLENDOP ,
7663 WINED3DRS_COLORWRITEENABLE ,
7664 WINED3DRS_DESTBLEND ,
7665 WINED3DRS_DITHERENABLE ,
7666 WINED3DRS_FILLMODE ,
7667 WINED3DRS_FOGDENSITY ,
7668 WINED3DRS_FOGEND ,
7669 WINED3DRS_FOGSTART ,
7670 WINED3DRS_LASTPIXEL ,
7671 WINED3DRS_SHADEMODE ,
7672 WINED3DRS_SRCBLEND ,
7673 WINED3DRS_STENCILENABLE ,
7674 WINED3DRS_STENCILFAIL ,
7675 WINED3DRS_STENCILFUNC ,
7676 WINED3DRS_STENCILMASK ,
7677 WINED3DRS_STENCILPASS ,
7678 WINED3DRS_STENCILREF ,
7679 WINED3DRS_STENCILWRITEMASK ,
7680 WINED3DRS_STENCILZFAIL ,
7681 WINED3DRS_TEXTUREFACTOR ,
7682 WINED3DRS_WRAP0 ,
7683 WINED3DRS_WRAP1 ,
7684 WINED3DRS_WRAP2 ,
7685 WINED3DRS_WRAP3 ,
7686 WINED3DRS_WRAP4 ,
7687 WINED3DRS_WRAP5 ,
7688 WINED3DRS_WRAP6 ,
7689 WINED3DRS_WRAP7 ,
7690 WINED3DRS_ZENABLE ,
7691 WINED3DRS_ZFUNC ,
7692 WINED3DRS_ZWRITEENABLE
7693 };
7694
7695 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7696 WINED3DTSS_ALPHAARG0 ,
7697 WINED3DTSS_ALPHAARG1 ,
7698 WINED3DTSS_ALPHAARG2 ,
7699 WINED3DTSS_ALPHAOP ,
7700 WINED3DTSS_BUMPENVLOFFSET ,
7701 WINED3DTSS_BUMPENVLSCALE ,
7702 WINED3DTSS_BUMPENVMAT00 ,
7703 WINED3DTSS_BUMPENVMAT01 ,
7704 WINED3DTSS_BUMPENVMAT10 ,
7705 WINED3DTSS_BUMPENVMAT11 ,
7706 WINED3DTSS_COLORARG0 ,
7707 WINED3DTSS_COLORARG1 ,
7708 WINED3DTSS_COLORARG2 ,
7709 WINED3DTSS_COLOROP ,
7710 WINED3DTSS_RESULTARG ,
7711 WINED3DTSS_TEXCOORDINDEX ,
7712 WINED3DTSS_TEXTURETRANSFORMFLAGS
7713 };
7714
7715 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7716 WINED3DSAMP_ADDRESSU ,
7717 WINED3DSAMP_ADDRESSV ,
7718 WINED3DSAMP_ADDRESSW ,
7719 WINED3DSAMP_BORDERCOLOR ,
7720 WINED3DSAMP_MAGFILTER ,
7721 WINED3DSAMP_MINFILTER ,
7722 WINED3DSAMP_MIPFILTER ,
7723 WINED3DSAMP_MIPMAPLODBIAS ,
7724 WINED3DSAMP_MAXMIPLEVEL ,
7725 WINED3DSAMP_MAXANISOTROPY ,
7726 WINED3DSAMP_SRGBTEXTURE ,
7727 WINED3DSAMP_ELEMENTINDEX
7728 };
7729
7730 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7731 WINED3DRS_AMBIENT ,
7732 WINED3DRS_AMBIENTMATERIALSOURCE ,
7733 WINED3DRS_CLIPPING ,
7734 WINED3DRS_CLIPPLANEENABLE ,
7735 WINED3DRS_COLORVERTEX ,
7736 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7737 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7738 WINED3DRS_FOGDENSITY ,
7739 WINED3DRS_FOGEND ,
7740 WINED3DRS_FOGSTART ,
7741 WINED3DRS_FOGTABLEMODE ,
7742 WINED3DRS_FOGVERTEXMODE ,
7743 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7744 WINED3DRS_LIGHTING ,
7745 WINED3DRS_LOCALVIEWER ,
7746 WINED3DRS_MULTISAMPLEANTIALIAS ,
7747 WINED3DRS_MULTISAMPLEMASK ,
7748 WINED3DRS_NORMALIZENORMALS ,
7749 WINED3DRS_PATCHEDGESTYLE ,
7750 WINED3DRS_POINTSCALE_A ,
7751 WINED3DRS_POINTSCALE_B ,
7752 WINED3DRS_POINTSCALE_C ,
7753 WINED3DRS_POINTSCALEENABLE ,
7754 WINED3DRS_POINTSIZE ,
7755 WINED3DRS_POINTSIZE_MAX ,
7756 WINED3DRS_POINTSIZE_MIN ,
7757 WINED3DRS_POINTSPRITEENABLE ,
7758 WINED3DRS_RANGEFOGENABLE ,
7759 WINED3DRS_SPECULARMATERIALSOURCE ,
7760 WINED3DRS_TWEENFACTOR ,
7761 WINED3DRS_VERTEXBLEND ,
7762 WINED3DRS_CULLMODE ,
7763 WINED3DRS_FOGCOLOR
7764 };
7765
7766 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7767 WINED3DTSS_TEXCOORDINDEX ,
7768 WINED3DTSS_TEXTURETRANSFORMFLAGS
7769 };
7770
7771 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7772 WINED3DSAMP_DMAPOFFSET
7773 };
7774
7775 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7776 DWORD rep = This->StateTable[state].representative;
7777 DWORD idx;
7778 BYTE shift;
7779 UINT i;
7780 WineD3DContext *context;
7781
7782 if(!rep) return;
7783 for(i = 0; i < This->numContexts; i++) {
7784 context = This->contexts[i];
7785 if(isStateDirty(context, rep)) continue;
7786
7787 context->dirtyArray[context->numDirtyEntries++] = rep;
7788 idx = rep >> 5;
7789 shift = rep & 0x1f;
7790 context->isStateDirty[idx] |= (1 << shift);
7791 }
7792 }
7793
7794 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7795 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7796 /* The drawable size of a pbuffer render target is the current pbuffer size
7797 */
7798 *width = dev->pbufferWidth;
7799 *height = dev->pbufferHeight;
7800 }
7801
7802 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7803 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7804 */
7805 *width = This->pow2Width;
7806 *height = This->pow2Height;
7807 }
7808
7809 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7810 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7811 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7812 * current context's drawable, which is the size of the back buffer of the swapchain
7813 * the active context belongs to. The back buffer of the swapchain is stored as the
7814 * surface the context belongs to.
7815 */
7816 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7817 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;
7818 }