wined3d: Do not mark texture stages above MAX_TEXTURES dirty.
[wine.git] / dlls / wined3d / device.c
blobf22b03de15237815d83a8452cf1b6bf3e8fe9873
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006 Stefan Dösinger for CodeWeavers
10 * Copyright 2006 Henri Verbeet
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include <stdio.h>
29 #ifdef HAVE_FLOAT_H
30 # include <float.h>
31 #endif
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
35 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
36 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
60 X11DRV_GET_FONT, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 inline static Display *get_display( HDC hdc )
66 Display *display;
67 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
69 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
70 sizeof(display), (LPSTR)&display )) display = NULL;
71 return display;
74 /* allocate one pbuffer per surface */
75 BOOL pbuffer_per_surface = FALSE;
77 /* static function declarations */
78 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
80 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type);
82 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil);
84 /* helper macros */
85 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
87 #define D3DCREATEOBJECTINSTANCE(object, type) { \
88 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
89 D3DMEMCHECK(object, pp##type); \
90 object->lpVtbl = &IWineD3D##type##_Vtbl; \
91 object->wineD3DDevice = This; \
92 object->parent = parent; \
93 object->ref = 1; \
94 *pp##type = (IWineD3D##type *) object; \
97 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
98 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
99 D3DMEMCHECK(object, pp##type); \
100 object->lpVtbl = &IWineD3D##type##_Vtbl; \
101 object->parent = parent; \
102 object->ref = 1; \
103 object->baseShader.device = (IWineD3DDevice*) This; \
104 *pp##type = (IWineD3D##type *) object; \
107 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
108 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
109 D3DMEMCHECK(object, pp##type); \
110 object->lpVtbl = &IWineD3D##type##_Vtbl; \
111 object->resource.wineD3DDevice = This; \
112 object->resource.parent = parent; \
113 object->resource.resourceType = d3dtype; \
114 object->resource.ref = 1; \
115 object->resource.pool = Pool; \
116 object->resource.format = Format; \
117 object->resource.usage = Usage; \
118 object->resource.size = _size; \
119 /* Check that we have enough video ram left */ \
120 if (Pool == WINED3DPOOL_DEFAULT) { \
121 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
122 WARN("Out of 'bogus' video memory\n"); \
123 HeapFree(GetProcessHeap(), 0, object); \
124 *pp##type = NULL; \
125 return WINED3DERR_OUTOFVIDEOMEMORY; \
127 globalChangeGlRam(_size); \
129 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
130 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
131 FIXME("Out of memory!\n"); \
132 HeapFree(GetProcessHeap(), 0, object); \
133 *pp##type = NULL; \
134 return WINED3DERR_OUTOFVIDEOMEMORY; \
136 *pp##type = (IWineD3D##type *) object; \
137 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
138 TRACE("(%p) : Created resource %p\n", This, object); \
141 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
142 _basetexture.levels = Levels; \
143 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
144 _basetexture.LOD = 0; \
145 _basetexture.dirty = TRUE; \
148 /**********************************************************
149 * Global variable / Constants follow
150 **********************************************************/
151 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
153 /**********************************************************
154 * Utility functions follow
155 **********************************************************/
156 /* Convert the WINED3DLIGHT properties into equivalent gl lights */
157 static void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
159 float quad_att;
160 float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
163 /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
164 glMatrixMode(GL_MODELVIEW);
165 glPushMatrix();
166 glLoadMatrixf((float *)&This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
168 /* Diffuse: */
169 colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
170 colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
171 colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
172 colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
173 glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
174 checkGLcall("glLightfv");
176 /* Specular */
177 colRGBA[0] = lightInfo->OriginalParms.Specular.r;
178 colRGBA[1] = lightInfo->OriginalParms.Specular.g;
179 colRGBA[2] = lightInfo->OriginalParms.Specular.b;
180 colRGBA[3] = lightInfo->OriginalParms.Specular.a;
181 glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
182 checkGLcall("glLightfv");
184 /* Ambient */
185 colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
186 colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
187 colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
188 colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
189 glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
190 checkGLcall("glLightfv");
192 /* Attenuation - Are these right? guessing... */
193 glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0);
194 checkGLcall("glLightf");
195 glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1);
196 checkGLcall("glLightf");
198 if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) {
199 quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range);
200 } else {
201 quad_att = 0; /* 0 or MAX? (0 seems to be ok) */
204 if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
205 glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
206 checkGLcall("glLightf");
208 switch (lightInfo->OriginalParms.Type) {
209 case WINED3DLIGHT_POINT:
210 /* Position */
211 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
212 checkGLcall("glLightfv");
213 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
214 checkGLcall("glLightf");
215 /* FIXME: Range */
216 break;
218 case WINED3DLIGHT_SPOT:
219 /* Position */
220 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
221 checkGLcall("glLightfv");
222 /* Direction */
223 glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
224 checkGLcall("glLightfv");
225 glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
226 checkGLcall("glLightf");
227 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
228 checkGLcall("glLightf");
229 /* FIXME: Range */
230 break;
232 case WINED3DLIGHT_DIRECTIONAL:
233 /* Direction */
234 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
235 checkGLcall("glLightfv");
236 glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
237 checkGLcall("glLightf");
238 glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
239 checkGLcall("glLightf");
240 break;
242 default:
243 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
246 /* Restore the modelview matrix */
247 glPopMatrix();
250 /**********************************************************
251 * GLSL helper functions follow
252 **********************************************************/
254 /** Attach a GLSL pixel or vertex shader object to the shader program */
255 static void attach_glsl_shader(IWineD3DDevice *iface, IWineD3DBaseShader* shader) {
257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
258 GLhandleARB shaderObj = ((IWineD3DBaseShaderImpl*)shader)->baseShader.prgId;
259 if (This->stateBlock->glsl_program && shaderObj != 0) {
260 TRACE_(d3d_shader)("Attaching GLSL shader object %u to program %u\n", shaderObj, This->stateBlock->glsl_program->programId);
261 GL_EXTCALL(glAttachObjectARB(This->stateBlock->glsl_program->programId, shaderObj));
262 checkGLcall("glAttachObjectARB");
266 /** Sets the GLSL program ID for the given pixel and vertex shader combination.
267 * It sets the programId on the current StateBlock (because it should be called
268 * inside of the DrawPrimitive() part of the render loop).
270 * If a program for the given combination does not exist, create one, and store
271 * the program in the list. If it creates a program, it will link the given
272 * objects, too.
274 * We keep the shader programs around on a list because linking
275 * shader objects together is an expensive operation. It's much
276 * faster to loop through a list of pre-compiled & linked programs
277 * each time that the application sets a new pixel or vertex shader
278 * than it is to re-link them together at that time.
280 * The list will be deleted in IWineD3DDevice::Release().
282 void set_glsl_shader_program(IWineD3DDevice *iface) {
284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
285 IWineD3DPixelShader *pshader = This->stateBlock->pixelShader;
286 IWineD3DVertexShader *vshader = This->stateBlock->vertexShader;
287 struct glsl_shader_prog_link *curLink = NULL;
288 struct glsl_shader_prog_link *newLink = NULL;
289 struct list *ptr = NULL;
290 GLhandleARB programId = 0;
291 int i;
292 char glsl_name[8];
294 ptr = list_head( &This->glsl_shader_progs );
295 while (ptr) {
296 /* At least one program exists - see if it matches our ps/vs combination */
297 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
298 if (vshader == curLink->vertexShader && pshader == curLink->pixelShader) {
299 /* Existing Program found, use it */
300 TRACE_(d3d_shader)("Found existing program (%u) for this vertex/pixel shader combination\n",
301 curLink->programId);
302 This->stateBlock->glsl_program = curLink;
303 return;
305 /* This isn't the entry we need - try the next one */
306 ptr = list_next( &This->glsl_shader_progs, ptr );
309 /* If we get to this point, then no matching program exists, so we create one */
310 programId = GL_EXTCALL(glCreateProgramObjectARB());
311 TRACE_(d3d_shader)("Created new GLSL shader program %u\n", programId);
313 /* Allocate a new link for the list of programs */
314 newLink = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link));
315 newLink->programId = programId;
316 This->stateBlock->glsl_program = newLink;
318 /* Attach GLSL vshader */
319 if (NULL != vshader && This->vs_selected_mode == SHADER_GLSL) {
320 int i;
321 int max_attribs = 16; /* TODO: Will this always be the case? It is at the moment... */
322 char tmp_name[10];
324 TRACE("Attaching vertex shader to GLSL program\n");
325 attach_glsl_shader(iface, (IWineD3DBaseShader*)vshader);
327 /* Bind vertex attributes to a corresponding index number to match
328 * the same index numbers as ARB_vertex_programs (makes loading
329 * vertex attributes simpler). With this method, we can use the
330 * exact same code to load the attributes later for both ARB and
331 * GLSL shaders.
333 * We have to do this here because we need to know the Program ID
334 * in order to make the bindings work, and it has to be done prior
335 * to linking the GLSL program. */
336 for (i = 0; i < max_attribs; ++i) {
337 snprintf(tmp_name, sizeof(tmp_name), "attrib%i", i);
338 GL_EXTCALL(glBindAttribLocationARB(programId, i, tmp_name));
340 checkGLcall("glBindAttribLocationARB");
341 newLink->vertexShader = vshader;
344 /* Attach GLSL pshader */
345 if (NULL != pshader && This->ps_selected_mode == SHADER_GLSL) {
346 TRACE("Attaching pixel shader to GLSL program\n");
347 attach_glsl_shader(iface, (IWineD3DBaseShader*)pshader);
348 newLink->pixelShader = pshader;
351 /* Link the program */
352 TRACE_(d3d_shader)("Linking GLSL shader program %u\n", programId);
353 GL_EXTCALL(glLinkProgramARB(programId));
354 print_glsl_info_log(&GLINFO_LOCATION, programId);
355 list_add_head( &This->glsl_shader_progs, &newLink->entry);
357 newLink->vuniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(vshader_constantsF));
358 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
359 snprintf(glsl_name, sizeof(glsl_name), "VC[%i]", i);
360 newLink->vuniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
362 newLink->puniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(pshader_constantsF));
363 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
364 snprintf(glsl_name, sizeof(glsl_name), "PC[%i]", i);
365 newLink->puniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
368 return;
371 /** Detach the GLSL pixel or vertex shader object from the shader program */
372 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
376 if (shaderObj != 0 && programId != 0) {
377 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
378 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
379 checkGLcall("glDetachObjectARB");
383 /** Delete a GLSL shader program */
384 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
388 if (obj != 0) {
389 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
390 GL_EXTCALL(glDeleteObjectARB(obj));
391 checkGLcall("glDeleteObjectARB");
395 /** Delete the list of linked programs this shader is associated with.
396 * Also at this point, check to see if there are any objects left attached
397 * to each GLSL program. If not, delete the GLSL program object.
398 * This will be run when a device is released. */
399 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
401 struct list *ptr = NULL;
402 struct glsl_shader_prog_link *curLink = NULL;
403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
405 int numAttached = 0;
406 int i;
407 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
408 (one pixel shader and one vertex shader at most) */
410 ptr = list_head( &This->glsl_shader_progs );
411 while (ptr) {
412 /* First, get the current item,
413 * save the link to the next pointer,
414 * detach and delete shader objects,
415 * then de-allocate the list item's memory */
416 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
417 ptr = list_next( &This->glsl_shader_progs, ptr );
419 /* See if this object is still attached to the program - it may have been detached already */
420 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
421 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
422 for (i = 0; i < numAttached; i++) {
423 detach_glsl_shader(iface, objList[i], curLink->programId);
426 delete_glsl_shader_program(iface, curLink->programId);
428 /* Free the uniform locations */
429 HeapFree(GetProcessHeap(), 0, curLink->vuniformF_locations);
430 HeapFree(GetProcessHeap(), 0, curLink->puniformF_locations);
432 /* Free the memory for this list item */
433 HeapFree(GetProcessHeap(), 0, curLink);
438 /* Apply the current values to the specified texture stage */
439 static void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD Sampler, DWORD texture_idx, DWORD Flags) {
440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
441 float col[4];
443 union {
444 float f;
445 DWORD d;
446 } tmpvalue;
448 /* In addition, IDirect3DDevice9::SetSamplerState will now be used for filtering, tiling,
449 clamping, MIPLOD, etc. This will work for up to 16 samplers.
452 if (Sampler >= GL_LIMITS(sampler_stages)) {
453 FIXME("Trying to set the state of more samplers %d than are supported %d by this openGL implementation\n", Sampler, GL_LIMITS(sampler_stages));
454 return;
456 VTRACE(("Activating appropriate texture state %d\n", Sampler));
457 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
458 ENTER_GL();
459 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
460 checkGLcall("glActiveTextureARB");
461 LEAVE_GL();
462 /* Could we use bindTexture and then apply the states instead of GLACTIVETEXTURE */
463 } else if (Sampler > 0) {
464 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
465 return;
468 /* TODO: change this to a lookup table
469 LOOKUP_TEXTURE_STATES lists all texture states that should be applied.
470 LOOKUP_CONTEXT_SATES list all context applicable states that can be applied
471 etc.... it's a lot cleaner, quicker and possibly easier to maintain than running a switch and setting a skip flag...
472 especially when there are a number of groups of states. */
474 TRACE("-----------------------> Updating the texture at Sampler %d to have new texture state information\n", Sampler);
476 /* The list of states not to apply is a big as the list of states to apply, so it makes sense to produce an inclusive list */
477 #define APPLY_STATE(_state) IWineD3DDeviceImpl_ApplyTextureUnitState(iface, Sampler, _state)
478 /* these are the only two supported states that need to be applied */
479 APPLY_STATE(WINED3DTSS_TEXCOORDINDEX);
480 APPLY_STATE(WINED3DTSS_TEXTURETRANSFORMFLAGS);
481 #if 0 /* not supported at the moment */
482 APPLY_STATE(WINED3DTSS_BUMPENVMAT00);
483 APPLY_STATE(WINED3DTSS_BUMPENVMAT01);
484 APPLY_STATE(WINED3DTSS_BUMPENVMAT10);
485 APPLY_STATE(WINED3DTSS_BUMPENVMAT11);
486 APPLY_STATE(WINED3DTSS_BUMPENVLSCALE);
487 APPLY_STATE(WINED3DTSS_BUMPENVLOFFSET);
488 APPLY_STATE(WINED3DTSS_RESULTARG);
489 APPLY_STATE(WINED3DTSS_CONSTANT);
490 #endif
491 /* a quick sanity check in case someone forgot to update this function */
492 if (WINED3D_HIGHEST_TEXTURE_STATE > WINED3DTSS_CONSTANT) {
493 FIXME("(%p) : There are more texture states than expected, update device.c to match\n", This);
495 #undef APPLY_STATE
497 /* apply any sampler states that always need applying */
498 if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) {
499 tmpvalue.d = This->stateBlock->samplerState[Sampler][WINED3DSAMP_MIPMAPLODBIAS];
500 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
501 GL_TEXTURE_LOD_BIAS_EXT,
502 tmpvalue.f);
503 checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ...");
506 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
507 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
508 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
510 /* TODO: NV_POINT_SPRITE */
511 if (GL_SUPPORT(ARB_POINT_SPRITE)) {
512 if (This->stateBlock->renderState[WINED3DRS_POINTSPRITEENABLE]) {
513 /* Doesn't work with GL_POINT_SMOOTH on on my ATI 9600, but then ATI drivers are buggered! */
514 glDisable(GL_POINT_SMOOTH);
516 /* Centre the texture on the vertex */
517 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
518 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
520 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
521 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
522 checkGLcall("glTexEnvf(...)");
523 VTRACE(("glEnable( GL_POINT_SPRITE_ARB )\n"));
524 glEnable( GL_POINT_SPRITE_ARB );
525 checkGLcall("glEnable(...)");
526 } else {
527 VTRACE(("glDisable( GL_POINT_SPRITE_ARB )\n"));
528 glDisable( GL_POINT_SPRITE_ARB );
529 checkGLcall("glEnable(...)");
533 TRACE("-----------------------> Updated the texture at Sampler %d to have new texture state information\n", Sampler);
536 /**********************************************************
537 * IUnknown parts follows
538 **********************************************************/
540 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
544 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
545 if (IsEqualGUID(riid, &IID_IUnknown)
546 || IsEqualGUID(riid, &IID_IWineD3DBase)
547 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
548 IUnknown_AddRef(iface);
549 *ppobj = This;
550 return S_OK;
552 *ppobj = NULL;
553 return E_NOINTERFACE;
556 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
558 ULONG refCount = InterlockedIncrement(&This->ref);
560 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
561 return refCount;
564 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
566 ULONG refCount = InterlockedDecrement(&This->ref);
568 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
570 if (!refCount) {
571 if (This->fbo) {
572 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
575 HeapFree(GetProcessHeap(), 0, This->render_targets);
577 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
579 /* TODO: Clean up all the surfaces and textures! */
580 /* NOTE: You must release the parent if the object was created via a callback
581 ** ***************************/
583 /* Delete any GLSL shader programs that may exist */
584 if (This->vs_selected_mode == SHADER_GLSL ||
585 This->ps_selected_mode == SHADER_GLSL)
586 delete_glsl_shader_list(iface);
588 /* Release the update stateblock */
589 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
590 if(This->updateStateBlock != This->stateBlock)
591 FIXME("(%p) Something's still holding the Update stateblock\n",This);
593 This->updateStateBlock = NULL;
594 { /* because were not doing proper internal refcounts releasing the primary state block
595 causes recursion with the extra checks in ResourceReleased, to avoid this we have
596 to set this->stateBlock = NULL; first */
597 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
598 This->stateBlock = NULL;
600 /* Release the stateblock */
601 if(IWineD3DStateBlock_Release(stateBlock) > 0){
602 FIXME("(%p) Something's still holding the Update stateblock\n",This);
606 if (This->resources != NULL ) {
607 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
608 dumpResources(This->resources);
612 IWineD3D_Release(This->wineD3D);
613 This->wineD3D = NULL;
614 HeapFree(GetProcessHeap(), 0, This);
615 TRACE("Freed device %p\n", This);
616 This = NULL;
618 return refCount;
621 /**********************************************************
622 * IWineD3DDevice implementation follows
623 **********************************************************/
624 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
626 *pParent = This->parent;
627 IUnknown_AddRef(This->parent);
628 return WINED3D_OK;
631 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
632 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
633 GLenum error, glUsage;
634 DWORD vboUsage = object->resource.usage;
635 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
636 WARN("Creating a vbo failed once, not trying again\n");
637 return;
640 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
642 ENTER_GL();
643 /* Make sure that the gl error is cleared. Do not use checkGLcall
644 * here because checkGLcall just prints a fixme and continues. However,
645 * if an error during VBO creation occurs we can fall back to non-vbo operation
646 * with full functionality(but performance loss)
648 while(glGetError() != GL_NO_ERROR);
650 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
651 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
652 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
653 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
654 * to check if the rhw and color values are in the correct format.
657 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
658 error = glGetError();
659 if(object->vbo == 0 || error != GL_NO_ERROR) {
660 WARN("Failed to create a VBO with error %d\n", error);
661 goto error;
664 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
665 error = glGetError();
666 if(error != GL_NO_ERROR) {
667 WARN("Failed to bind the VBO, error %d\n", error);
668 goto error;
671 /* Transformed vertices are horribly inflexible. If the app specifies an
672 * vertex buffer with transformed vertices in default pool without DYNAMIC
673 * usage assume DYNAMIC usage and print a warning. The app will have to update
674 * the vertices regularily for them to be useful
676 if(((object->fvf & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) &&
677 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
678 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
679 vboUsage |= WINED3DUSAGE_DYNAMIC;
682 /* Don't use static, because dx apps tend to update the buffer
683 * quite often even if they specify 0 usage
685 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
686 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
687 TRACE("Gl usage = GL_STREAM_DRAW\n");
688 glUsage = GL_STREAM_DRAW_ARB;
689 break;
690 case D3DUSAGE_WRITEONLY:
691 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
692 glUsage = GL_DYNAMIC_DRAW_ARB;
693 break;
694 case D3DUSAGE_DYNAMIC:
695 TRACE("Gl usage = GL_STREAM_COPY\n");
696 glUsage = GL_STREAM_COPY_ARB;
697 break;
698 default:
699 TRACE("Gl usage = GL_DYNAMIC_COPY\n");
700 glUsage = GL_DYNAMIC_COPY_ARB;
701 break;
704 /* Reserve memory for the buffer. The amount of data won't change
705 * so we are safe with calling glBufferData once with a NULL ptr and
706 * calling glBufferSubData on updates
708 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
709 error = glGetError();
710 if(error != GL_NO_ERROR) {
711 WARN("glBufferDataARB failed with error %d\n", error);
712 goto error;
715 LEAVE_GL();
717 return;
718 error:
719 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
720 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
721 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
722 object->vbo = 0;
723 object->Flags |= VBFLAG_VBOCREATEFAIL;
724 LEAVE_GL();
725 return;
728 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
729 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
730 IUnknown *parent) {
731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
732 IWineD3DVertexBufferImpl *object;
733 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
734 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
735 BOOL conv;
736 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
738 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
739 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
741 if(Size == 0) return WINED3DERR_INVALIDCALL;
743 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
744 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
746 object->fvf = FVF;
748 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
749 * drawStridedFast (half-life 2).
751 * Basically converting the vertices in the buffer is quite expensive, and observations
752 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
753 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
755 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
756 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
757 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
758 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
759 * dx7 apps.
760 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
761 * more. In this call we can convert dx7 buffers too.
763 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
764 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
765 (dxVersion > 7 || !conv) ) {
766 CreateVBO(object);
768 /* DX7 buffers can be locked directly into the VBO (no conversion, see above */
769 if(dxVersion == 7 && object->vbo) {
770 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
771 object->resource.allocatedMemory = NULL;
775 return WINED3D_OK;
778 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
779 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
780 HANDLE *sharedHandle, IUnknown *parent) {
781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
782 IWineD3DIndexBufferImpl *object;
783 TRACE("(%p) Creating index buffer\n", This);
785 /* Allocate the storage for the device */
786 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
788 /*TODO: use VBO's */
789 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
790 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
793 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
794 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
795 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
797 return WINED3D_OK;
800 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
803 IWineD3DStateBlockImpl *object;
804 int i, j;
805 HRESULT temp_result;
807 D3DCREATEOBJECTINSTANCE(object, StateBlock)
808 object->blockType = Type;
810 /* Special case - Used during initialization to produce a placeholder stateblock
811 so other functions called can update a state block */
812 if (Type == WINED3DSBT_INIT) {
813 /* Don't bother increasing the reference count otherwise a device will never
814 be freed due to circular dependencies */
815 return WINED3D_OK;
818 temp_result = allocate_shader_constants(object);
819 if (WINED3D_OK != temp_result)
820 return temp_result;
822 /* Otherwise, might as well set the whole state block to the appropriate values */
823 if (This->stateBlock != NULL)
824 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
825 else
826 memset(object->streamFreq, 1, sizeof(object->streamFreq));
828 /* Reset the ref and type after kludging it */
829 object->wineD3DDevice = This;
830 object->ref = 1;
831 object->blockType = Type;
833 TRACE("Updating changed flags appropriate for type %d\n", Type);
835 if (Type == WINED3DSBT_ALL) {
837 TRACE("ALL => Pretend everything has changed\n");
838 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
840 } else if (Type == WINED3DSBT_PIXELSTATE) {
842 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
843 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
845 object->changed.pixelShader = TRUE;
847 /* Pixel Shader Constants */
848 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
849 object->changed.pixelShaderConstantsF[i] = TRUE;
850 for (i = 0; i < MAX_CONST_B; ++i)
851 object->changed.pixelShaderConstantsB[i] = TRUE;
852 for (i = 0; i < MAX_CONST_I; ++i)
853 object->changed.pixelShaderConstantsI[i] = TRUE;
855 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
856 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
858 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
859 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
860 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
863 for (j = 0 ; j < 16; j++) {
864 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
866 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
870 } else if (Type == WINED3DSBT_VERTEXSTATE) {
872 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
873 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
875 object->changed.vertexShader = TRUE;
877 /* Vertex Shader Constants */
878 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
879 object->changed.vertexShaderConstantsF[i] = TRUE;
880 for (i = 0; i < MAX_CONST_B; ++i)
881 object->changed.vertexShaderConstantsB[i] = TRUE;
882 for (i = 0; i < MAX_CONST_I; ++i)
883 object->changed.vertexShaderConstantsI[i] = TRUE;
885 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
886 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
888 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
889 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
890 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
893 for (j = 0 ; j < 16; j++){
894 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
895 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
899 /* Duplicate light chain */
901 PLIGHTINFOEL *src = NULL;
902 PLIGHTINFOEL *dst = NULL;
903 PLIGHTINFOEL *newEl = NULL;
904 src = This->stateBlock->lights;
905 object->lights = NULL;
908 while (src) {
909 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
910 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
911 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
912 newEl->prev = dst;
913 newEl->changed = TRUE;
914 newEl->enabledChanged = TRUE;
915 if (dst == NULL) {
916 object->lights = newEl;
917 } else {
918 dst->next = newEl;
920 dst = newEl;
921 src = src->next;
926 } else {
927 FIXME("Unrecognized state block type %d\n", Type);
930 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
931 return WINED3D_OK;
935 /* ************************************
936 MSDN:
937 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
939 Discard
940 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
942 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
944 ******************************** */
946 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) {
947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
948 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
949 unsigned int pow2Width, pow2Height;
950 unsigned int Size = 1;
951 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
952 TRACE("(%p) Create surface\n",This);
954 /** FIXME: Check ranges on the inputs are valid
955 * MSDN
956 * MultisampleQuality
957 * [in] Quality level. The valid range is between zero and one less than the level
958 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
959 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
960 * values of paired render targets, depth stencil surfaces, and the MultiSample type
961 * must all match.
962 *******************************/
966 * TODO: Discard MSDN
967 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
969 * If this flag is set, the contents of the depth stencil buffer will be
970 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
971 * with a different depth surface.
973 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
974 ***************************/
976 if(MultisampleQuality < 0) {
977 FIXME("Invalid multisample level %d\n", MultisampleQuality);
978 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
981 if(MultisampleQuality > 0) {
982 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
983 MultisampleQuality=0;
986 /** FIXME: Check that the format is supported
987 * by the device.
988 *******************************/
990 /* Non-power2 support */
991 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
992 pow2Width = Width;
993 pow2Height = Height;
994 } else {
995 /* Find the nearest pow2 match */
996 pow2Width = pow2Height = 1;
997 while (pow2Width < Width) pow2Width <<= 1;
998 while (pow2Height < Height) pow2Height <<= 1;
1001 if (pow2Width > Width || pow2Height > Height) {
1002 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
1003 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
1004 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
1005 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
1006 This, Width, Height);
1007 return WINED3DERR_NOTAVAILABLE;
1011 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
1012 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
1013 * space!
1014 *********************************/
1015 if (WINED3DFMT_UNKNOWN == Format) {
1016 Size = 0;
1017 } else if (Format == WINED3DFMT_DXT1) {
1018 /* DXT1 is half byte per pixel */
1019 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
1021 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
1022 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
1023 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
1024 } else {
1025 /* The pitch is a multiple of 4 bytes */
1026 Size = ((pow2Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1027 Size *= pow2Height;
1030 /** Create and initialise the surface resource **/
1031 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
1032 /* "Standalone" surface */
1033 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1035 object->currentDesc.Width = Width;
1036 object->currentDesc.Height = Height;
1037 object->currentDesc.MultiSampleType = MultiSample;
1038 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1040 /* Setup some glformat defaults */
1041 object->glDescription.glFormat = tableEntry->glFormat;
1042 object->glDescription.glFormatInternal = tableEntry->glInternal;
1043 object->glDescription.glType = tableEntry->glType;
1045 object->glDescription.textureName = 0;
1046 object->glDescription.level = Level;
1047 object->glDescription.target = GL_TEXTURE_2D;
1049 /* Internal data */
1050 object->pow2Width = pow2Width;
1051 object->pow2Height = pow2Height;
1053 /* Flags */
1054 object->Flags = 0; /* We start without flags set */
1055 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
1056 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1057 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1058 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1061 if (WINED3DFMT_UNKNOWN != Format) {
1062 object->bytesPerPixel = tableEntry->bpp;
1063 object->pow2Size = ((pow2Width * object->bytesPerPixel) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1064 object->pow2Size *= pow2Height;
1065 } else {
1066 object->bytesPerPixel = 0;
1067 object->pow2Size = 0;
1070 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
1072 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1074 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
1075 * this function is too deep to need to care about things like this.
1076 * Levels need to be checked too, and possibly Type since they all affect what can be done.
1077 * ****************************************/
1078 switch(Pool) {
1079 case WINED3DPOOL_SCRATCH:
1080 if(!Lockable)
1081 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE \
1082 which are mutually exclusive, setting lockable to true\n");
1083 Lockable = TRUE;
1084 break;
1085 case WINED3DPOOL_SYSTEMMEM:
1086 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1087 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1088 case WINED3DPOOL_MANAGED:
1089 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
1090 Usage of DYNAMIC which are mutually exclusive, not doing \
1091 anything just telling you.\n");
1092 break;
1093 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1094 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1095 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1096 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1097 break;
1098 default:
1099 FIXME("(%p) Unknown pool %d\n", This, Pool);
1100 break;
1103 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1104 FIXME("Trying to create a render target that isn't in the default pool\n");
1107 /* mark the texture as dirty so that it gets loaded first time around*/
1108 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1109 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1110 This, Width, Height, Format, debug_d3dformat(Format),
1111 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1113 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
1114 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
1115 This->ddraw_primary = (IWineD3DSurface *) object;
1117 /* Look at the implementation and set the correct Vtable */
1118 switch(Impl) {
1119 case SURFACE_OPENGL:
1120 /* Nothing to do, it's set already */
1121 break;
1123 case SURFACE_GDI:
1124 object->lpVtbl = &IWineGDISurface_Vtbl;
1125 break;
1127 default:
1128 /* To be sure to catch this */
1129 ERR("Unknown requested surface implementation %d!\n", Impl);
1130 IWineD3DSurface_Release((IWineD3DSurface *) object);
1131 return WINED3DERR_INVALIDCALL;
1134 /* Call the private setup routine */
1135 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1139 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1140 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1141 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1142 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1145 IWineD3DTextureImpl *object;
1146 unsigned int i;
1147 UINT tmpW;
1148 UINT tmpH;
1149 HRESULT hr;
1150 unsigned int pow2Width;
1151 unsigned int pow2Height;
1154 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1155 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
1156 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
1158 /* TODO: It should only be possible to create textures for formats
1159 that are reported as supported */
1160 if (WINED3DFMT_UNKNOWN >= Format) {
1161 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1162 return WINED3DERR_INVALIDCALL;
1165 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1166 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1167 object->width = Width;
1168 object->height = Height;
1170 /** Non-power2 support **/
1171 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
1172 pow2Width = Width;
1173 pow2Height = Height;
1174 } else {
1175 /* Find the nearest pow2 match */
1176 pow2Width = pow2Height = 1;
1177 while (pow2Width < Width) pow2Width <<= 1;
1178 while (pow2Height < Height) pow2Height <<= 1;
1181 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1182 /* Precalculated scaling for 'faked' non power of two texture coords */
1183 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1184 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1185 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1187 /* Calculate levels for mip mapping */
1188 if (Levels == 0) {
1189 TRACE("calculating levels %d\n", object->baseTexture.levels);
1190 object->baseTexture.levels++;
1191 tmpW = Width;
1192 tmpH = Height;
1193 while (tmpW > 1 || tmpH > 1) {
1194 tmpW = max(1, tmpW >> 1);
1195 tmpH = max(1, tmpH >> 1);
1196 object->baseTexture.levels++;
1198 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1201 /* Generate all the surfaces */
1202 tmpW = Width;
1203 tmpH = Height;
1204 for (i = 0; i < object->baseTexture.levels; i++)
1206 /* use the callback to create the texture surface */
1207 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1208 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1209 FIXME("Failed to create surface %p\n", object);
1210 /* clean up */
1211 object->surfaces[i] = NULL;
1212 IWineD3DTexture_Release((IWineD3DTexture *)object);
1214 *ppTexture = NULL;
1215 return hr;
1218 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1219 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1220 /* calculate the next mipmap level */
1221 tmpW = max(1, tmpW >> 1);
1222 tmpH = max(1, tmpH >> 1);
1225 TRACE("(%p) : Created texture %p\n", This, object);
1226 return WINED3D_OK;
1229 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1230 UINT Width, UINT Height, UINT Depth,
1231 UINT Levels, DWORD Usage,
1232 WINED3DFORMAT Format, WINED3DPOOL Pool,
1233 IWineD3DVolumeTexture **ppVolumeTexture,
1234 HANDLE *pSharedHandle, IUnknown *parent,
1235 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1238 IWineD3DVolumeTextureImpl *object;
1239 unsigned int i;
1240 UINT tmpW;
1241 UINT tmpH;
1242 UINT tmpD;
1244 /* TODO: It should only be possible to create textures for formats
1245 that are reported as supported */
1246 if (WINED3DFMT_UNKNOWN >= Format) {
1247 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1248 return WINED3DERR_INVALIDCALL;
1251 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1252 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1254 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1255 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1257 object->width = Width;
1258 object->height = Height;
1259 object->depth = Depth;
1261 /* Calculate levels for mip mapping */
1262 if (Levels == 0) {
1263 object->baseTexture.levels++;
1264 tmpW = Width;
1265 tmpH = Height;
1266 tmpD = Depth;
1267 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1268 tmpW = max(1, tmpW >> 1);
1269 tmpH = max(1, tmpH >> 1);
1270 tmpD = max(1, tmpD >> 1);
1271 object->baseTexture.levels++;
1273 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1276 /* Generate all the surfaces */
1277 tmpW = Width;
1278 tmpH = Height;
1279 tmpD = Depth;
1281 for (i = 0; i < object->baseTexture.levels; i++)
1283 /* Create the volume */
1284 D3DCB_CreateVolume(This->parent, parent, Width, Height, Depth, Format, Pool, Usage,
1285 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1287 /* Set its container to this object */
1288 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1290 /* calcualte the next mipmap level */
1291 tmpW = max(1, tmpW >> 1);
1292 tmpH = max(1, tmpH >> 1);
1293 tmpD = max(1, tmpD >> 1);
1296 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1297 TRACE("(%p) : Created volume texture %p\n", This, object);
1298 return WINED3D_OK;
1301 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1302 UINT Width, UINT Height, UINT Depth,
1303 DWORD Usage,
1304 WINED3DFORMAT Format, WINED3DPOOL Pool,
1305 IWineD3DVolume** ppVolume,
1306 HANDLE* pSharedHandle, IUnknown *parent) {
1308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1309 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1310 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1312 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1314 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1315 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1317 object->currentDesc.Width = Width;
1318 object->currentDesc.Height = Height;
1319 object->currentDesc.Depth = Depth;
1320 object->bytesPerPixel = formatDesc->bpp;
1322 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1323 object->lockable = TRUE;
1324 object->locked = FALSE;
1325 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1326 object->dirty = TRUE;
1328 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1331 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1332 UINT Levels, DWORD Usage,
1333 WINED3DFORMAT Format, WINED3DPOOL Pool,
1334 IWineD3DCubeTexture **ppCubeTexture,
1335 HANDLE *pSharedHandle, IUnknown *parent,
1336 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1339 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1340 unsigned int i, j;
1341 UINT tmpW;
1342 HRESULT hr;
1343 unsigned int pow2EdgeLength = EdgeLength;
1345 /* TODO: It should only be possible to create textures for formats
1346 that are reported as supported */
1347 if (WINED3DFMT_UNKNOWN >= Format) {
1348 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1349 return WINED3DERR_INVALIDCALL;
1352 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1353 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1355 TRACE("(%p) Create Cube Texture\n", This);
1357 /** Non-power2 support **/
1359 /* Find the nearest pow2 match */
1360 pow2EdgeLength = 1;
1361 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1363 object->edgeLength = EdgeLength;
1364 /* TODO: support for native non-power 2 */
1365 /* Precalculated scaling for 'faked' non power of two texture coords */
1366 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1368 /* Calculate levels for mip mapping */
1369 if (Levels == 0) {
1370 object->baseTexture.levels++;
1371 tmpW = EdgeLength;
1372 while (tmpW > 1) {
1373 tmpW = max(1, tmpW >> 1);
1374 object->baseTexture.levels++;
1376 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1379 /* Generate all the surfaces */
1380 tmpW = EdgeLength;
1381 for (i = 0; i < object->baseTexture.levels; i++) {
1383 /* Create the 6 faces */
1384 for (j = 0; j < 6; j++) {
1386 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1387 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1389 if(hr!= WINED3D_OK) {
1390 /* clean up */
1391 int k;
1392 int l;
1393 for (l = 0; l < j; l++) {
1394 IWineD3DSurface_Release(object->surfaces[j][i]);
1396 for (k = 0; k < i; k++) {
1397 for (l = 0; l < 6; l++) {
1398 IWineD3DSurface_Release(object->surfaces[l][j]);
1402 FIXME("(%p) Failed to create surface\n",object);
1403 HeapFree(GetProcessHeap(),0,object);
1404 *ppCubeTexture = NULL;
1405 return hr;
1407 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1408 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1410 tmpW = max(1, tmpW >> 1);
1413 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1414 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1415 return WINED3D_OK;
1418 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1420 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1422 if (NULL == ppQuery) {
1423 /* Just a check to see if we support this type of query */
1424 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1425 switch(Type) {
1426 case WINED3DQUERYTYPE_OCCLUSION:
1427 TRACE("(%p) occlusion query\n", This);
1428 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1429 hr = WINED3D_OK;
1430 else
1431 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1432 break;
1433 case WINED3DQUERYTYPE_VCACHE:
1434 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1435 case WINED3DQUERYTYPE_VERTEXSTATS:
1436 case WINED3DQUERYTYPE_EVENT:
1437 case WINED3DQUERYTYPE_TIMESTAMP:
1438 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1439 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1440 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1441 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1442 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1443 case WINED3DQUERYTYPE_PIXELTIMINGS:
1444 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1445 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1446 default:
1447 FIXME("(%p) Unhandled query type %d\n", This, Type);
1449 return hr;
1452 D3DCREATEOBJECTINSTANCE(object, Query)
1453 object->type = Type;
1454 /* allocated the 'extended' data based on the type of query requested */
1455 switch(Type){
1456 case WINED3DQUERYTYPE_OCCLUSION:
1457 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1458 TRACE("(%p) Allocating data for an occlusion query\n", This);
1459 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1460 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1461 break;
1463 case WINED3DQUERYTYPE_VCACHE:
1464 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1465 case WINED3DQUERYTYPE_VERTEXSTATS:
1466 case WINED3DQUERYTYPE_EVENT:
1467 case WINED3DQUERYTYPE_TIMESTAMP:
1468 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1469 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1470 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1471 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1472 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1473 case WINED3DQUERYTYPE_PIXELTIMINGS:
1474 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1475 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1476 default:
1477 object->extendedData = 0;
1478 FIXME("(%p) Unhandled query type %d\n",This , Type);
1480 TRACE("(%p) : Created Query %p\n", This, object);
1481 return WINED3D_OK;
1484 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1485 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1486 IUnknown* parent,
1487 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1488 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1491 HDC hDc;
1492 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1493 int num;
1494 XVisualInfo template;
1495 GLXContext oldContext;
1496 Drawable oldDrawable;
1497 HRESULT hr = WINED3D_OK;
1499 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1501 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1502 * does a device hold a reference to a swap chain giving them a lifetime of the device
1503 * or does the swap chain notify the device of its destruction.
1504 *******************************/
1506 /* Check the params */
1507 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1508 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1509 return WINED3DERR_INVALIDCALL;
1510 } else if (*pPresentationParameters->BackBufferCount > 1) {
1511 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");
1514 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1516 /*********************
1517 * Lookup the window Handle and the relating X window handle
1518 ********************/
1520 /* Setup hwnd we are using, plus which display this equates to */
1521 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1522 if (!object->win_handle) {
1523 object->win_handle = This->createParms.hFocusWindow;
1526 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1527 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1528 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1529 return WINED3DERR_NOTAVAILABLE;
1531 hDc = GetDC(object->win_handle);
1532 object->display = get_display(hDc);
1533 ReleaseDC(object->win_handle, hDc);
1534 TRACE("Using a display of %p %p\n", object->display, hDc);
1536 if (NULL == object->display || NULL == hDc) {
1537 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1538 return WINED3DERR_NOTAVAILABLE;
1541 if (object->win == 0) {
1542 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1543 return WINED3DERR_NOTAVAILABLE;
1546 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1547 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1550 * Create an opengl context for the display visual
1551 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1552 * use different properties after that point in time. FIXME: How to handle when requested format
1553 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1554 * it chooses is identical to the one already being used!
1555 **********************************/
1557 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1558 ENTER_GL();
1560 /* Create a new context for this swapchain */
1561 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1562 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1563 (or the best possible if none is requested) */
1564 TRACE("Found x visual ID : %ld\n", template.visualid);
1566 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1567 if (NULL == object->visInfo) {
1568 ERR("cannot really get XVisual\n");
1569 LEAVE_GL();
1570 return WINED3DERR_NOTAVAILABLE;
1571 } else {
1572 int n, value;
1573 /* Write out some debug info about the visual/s */
1574 TRACE("Using x visual ID : %ld\n", template.visualid);
1575 TRACE(" visual info: %p\n", object->visInfo);
1576 TRACE(" num items : %d\n", num);
1577 for (n = 0;n < num; n++) {
1578 TRACE("=====item=====: %d\n", n + 1);
1579 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1580 TRACE(" screen : %d\n", object->visInfo[n].screen);
1581 TRACE(" depth : %u\n", object->visInfo[n].depth);
1582 TRACE(" class : %d\n", object->visInfo[n].class);
1583 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1584 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1585 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1586 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1587 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1588 /* log some extra glx info */
1589 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1590 TRACE(" gl_aux_buffers : %d\n", value);
1591 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1592 TRACE(" gl_buffer_size : %d\n", value);
1593 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1594 TRACE(" gl_red_size : %d\n", value);
1595 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1596 TRACE(" gl_green_size : %d\n", value);
1597 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1598 TRACE(" gl_blue_size : %d\n", value);
1599 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1600 TRACE(" gl_alpha_size : %d\n", value);
1601 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1602 TRACE(" gl_depth_size : %d\n", value);
1603 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1604 TRACE(" gl_stencil_size : %d\n", value);
1606 /* Now choose a similar visual ID*/
1608 #ifdef USE_CONTEXT_MANAGER
1610 /** TODO: use a context mamager **/
1611 #endif
1614 IWineD3DSwapChain *implSwapChain;
1615 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1616 /* The first time around we create the context that is shared with all other swapchains and render targets */
1617 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1618 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1619 } else {
1621 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1622 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1623 /* and create a new context with the implicit swapchains context as the shared context */
1624 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1625 IWineD3DSwapChain_Release(implSwapChain);
1629 /* Cleanup */
1630 XFree(object->visInfo);
1631 object->visInfo = NULL;
1633 LEAVE_GL();
1635 if (!object->glCtx) {
1636 ERR("Failed to create GLX context\n");
1637 return WINED3DERR_NOTAVAILABLE;
1638 } else {
1639 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1640 object->win_handle, object->glCtx, object->win, object->visInfo);
1643 /*********************
1644 * Windowed / Fullscreen
1645 *******************/
1648 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1649 * so we should really check to see if there is a fullscreen swapchain already
1650 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1651 **************************************/
1653 if (!*(pPresentationParameters->Windowed)) {
1655 DEVMODEW devmode;
1656 HDC hdc;
1657 int bpp = 0;
1659 /* Get info on the current display setup */
1660 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1661 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1662 DeleteDC(hdc);
1664 /* Change the display settings */
1665 memset(&devmode, 0, sizeof(DEVMODEW));
1666 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1667 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1668 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1669 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1670 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1671 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1673 /* Make popup window */
1674 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1675 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1676 *(pPresentationParameters->BackBufferWidth),
1677 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1679 /* For GetDisplayMode */
1680 This->ddraw_width = devmode.dmPelsWidth;
1681 This->ddraw_height = devmode.dmPelsHeight;
1682 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1686 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1687 * then the corresponding dimension of the client area of the hDeviceWindow
1688 * (or the focus window, if hDeviceWindow is NULL) is taken.
1689 **********************/
1691 if (*(pPresentationParameters->Windowed) &&
1692 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1693 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1695 RECT Rect;
1696 GetClientRect(object->win_handle, &Rect);
1698 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1699 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1700 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1702 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1703 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1704 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1708 /*********************
1709 * finish off parameter initialization
1710 *******************/
1712 /* Put the correct figures in the presentation parameters */
1713 TRACE("Copying across presentation parameters\n");
1714 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1715 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1716 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1717 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1718 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1719 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1720 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1721 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1722 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1723 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1724 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1725 object->presentParms.Flags = *(pPresentationParameters->Flags);
1726 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1727 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1730 /*********************
1731 * Create the back, front and stencil buffers
1732 *******************/
1734 TRACE("calling rendertarget CB\n");
1735 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1736 parent,
1737 object->presentParms.BackBufferWidth,
1738 object->presentParms.BackBufferHeight,
1739 object->presentParms.BackBufferFormat,
1740 object->presentParms.MultiSampleType,
1741 object->presentParms.MultiSampleQuality,
1742 TRUE /* Lockable */,
1743 &object->frontBuffer,
1744 NULL /* pShared (always null)*/);
1745 if (object->frontBuffer != NULL)
1746 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1748 if(object->presentParms.BackBufferCount > 0) {
1749 int i;
1751 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1752 if(!object->backBuffer) {
1753 ERR("Out of memory\n");
1755 if (object->frontBuffer) {
1756 IUnknown *bufferParent;
1757 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1758 IUnknown_Release(bufferParent); /* once for the get parent */
1759 if (IUnknown_Release(bufferParent) > 0) {
1760 FIXME("(%p) Something's still holding the front buffer\n",This);
1763 HeapFree(GetProcessHeap(), 0, object);
1764 return E_OUTOFMEMORY;
1767 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1768 TRACE("calling rendertarget CB\n");
1769 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1770 parent,
1771 object->presentParms.BackBufferWidth,
1772 object->presentParms.BackBufferHeight,
1773 object->presentParms.BackBufferFormat,
1774 object->presentParms.MultiSampleType,
1775 object->presentParms.MultiSampleQuality,
1776 TRUE /* Lockable */,
1777 &object->backBuffer[i],
1778 NULL /* pShared (always null)*/);
1779 if(hr == WINED3D_OK && object->backBuffer[i]) {
1780 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1781 } else {
1782 break;
1785 } else {
1786 object->backBuffer = NULL;
1789 if (object->backBuffer != NULL) {
1790 ENTER_GL();
1791 glDrawBuffer(GL_BACK);
1792 checkGLcall("glDrawBuffer(GL_BACK)");
1793 LEAVE_GL();
1794 } else {
1795 /* Single buffering - draw to front buffer */
1796 ENTER_GL();
1797 glDrawBuffer(GL_FRONT);
1798 checkGLcall("glDrawBuffer(GL_FRONT)");
1799 LEAVE_GL();
1802 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1803 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1804 TRACE("Creating depth stencil buffer\n");
1805 if (This->depthStencilBuffer == NULL ) {
1806 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1807 parent,
1808 object->presentParms.BackBufferWidth,
1809 object->presentParms.BackBufferHeight,
1810 object->presentParms.AutoDepthStencilFormat,
1811 object->presentParms.MultiSampleType,
1812 object->presentParms.MultiSampleQuality,
1813 FALSE /* FIXME: Discard */,
1814 &This->depthStencilBuffer,
1815 NULL /* pShared (always null)*/ );
1816 if (This->depthStencilBuffer != NULL)
1817 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1820 /** TODO: A check on width, height and multisample types
1821 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1822 ****************************/
1823 object->wantsDepthStencilBuffer = TRUE;
1824 } else {
1825 object->wantsDepthStencilBuffer = FALSE;
1828 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1831 /*********************
1832 * init the default renderTarget management
1833 *******************/
1834 object->drawable = object->win;
1835 object->render_ctx = object->glCtx;
1837 if (hr == WINED3D_OK) {
1838 /*********************
1839 * Setup some defaults and clear down the buffers
1840 *******************/
1841 ENTER_GL();
1842 /** save current context and drawable **/
1843 oldContext = glXGetCurrentContext();
1844 oldDrawable = glXGetCurrentDrawable();
1846 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1847 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1848 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1850 checkGLcall("glXMakeCurrent");
1852 TRACE("Setting up the screen\n");
1853 /* Clear the screen */
1854 glClearColor(1.0, 0.0, 0.0, 0.0);
1855 checkGLcall("glClearColor");
1856 glClearIndex(0);
1857 glClearDepth(1);
1858 glClearStencil(0xffff);
1860 checkGLcall("glClear");
1862 glColor3f(1.0, 1.0, 1.0);
1863 checkGLcall("glColor3f");
1865 glEnable(GL_LIGHTING);
1866 checkGLcall("glEnable");
1868 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1869 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1871 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1872 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1874 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1875 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1877 /* switch back to the original context (if there was one)*/
1878 if (This->swapchains) {
1879 /** TODO: restore the context and drawable **/
1880 glXMakeCurrent(object->display, oldDrawable, oldContext);
1883 /* Set the surface alignment. This never changes, so we are safe to set it once per context*/
1884 glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);
1885 checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1886 glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);
1887 checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1889 LEAVE_GL();
1891 TRACE("Set swapchain to %p\n", object);
1892 } else { /* something went wrong so clean up */
1893 IUnknown* bufferParent;
1894 if (object->frontBuffer) {
1896 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1897 IUnknown_Release(bufferParent); /* once for the get parent */
1898 if (IUnknown_Release(bufferParent) > 0) {
1899 FIXME("(%p) Something's still holding the front buffer\n",This);
1902 if (object->backBuffer) {
1903 int i;
1904 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1905 if(object->backBuffer[i]) {
1906 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1907 IUnknown_Release(bufferParent); /* once for the get parent */
1908 if (IUnknown_Release(bufferParent) > 0) {
1909 FIXME("(%p) Something's still holding the back buffer\n",This);
1913 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1914 object->backBuffer = NULL;
1916 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1917 /* Clean up the context */
1918 /* check that we are the current context first (we shouldn't be though!) */
1919 if (object->glCtx != 0) {
1920 if(glXGetCurrentContext() == object->glCtx) {
1921 glXMakeCurrent(object->display, None, NULL);
1923 glXDestroyContext(object->display, object->glCtx);
1925 HeapFree(GetProcessHeap(), 0, object);
1929 return hr;
1932 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1933 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1935 TRACE("(%p)\n", This);
1937 return This->NumberOfSwapChains;
1940 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1942 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1944 if(iSwapChain < This->NumberOfSwapChains) {
1945 *pSwapChain = This->swapchains[iSwapChain];
1946 IWineD3DSwapChain_AddRef(*pSwapChain);
1947 TRACE("(%p) returning %p\n", This, *pSwapChain);
1948 return WINED3D_OK;
1949 } else {
1950 TRACE("Swapchain out of range\n");
1951 *pSwapChain = NULL;
1952 return WINED3DERR_INVALIDCALL;
1956 /*****
1957 * Vertex Declaration
1958 *****/
1959 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1961 IWineD3DVertexDeclarationImpl *object = NULL;
1962 HRESULT hr = WINED3D_OK;
1963 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1964 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1965 object->allFVF = 0;
1967 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1969 return hr;
1972 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1973 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1975 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1976 HRESULT hr = WINED3D_OK;
1977 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1978 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1980 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1982 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1983 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1984 if (pDeclaration != NULL) {
1985 IWineD3DVertexDeclaration *vertexDeclaration;
1986 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1987 if (WINED3D_OK == hr) {
1988 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1989 object->vertexDeclaration = vertexDeclaration;
1990 } else {
1991 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1992 IWineD3DVertexShader_Release(*ppVertexShader);
1993 return WINED3DERR_INVALIDCALL;
1997 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1999 if (WINED3D_OK != hr) {
2000 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
2001 IWineD3DVertexShader_Release(*ppVertexShader);
2002 return WINED3DERR_INVALIDCALL;
2005 #if 0 /* TODO: In D3D* SVP is atatched to the shader, in D3D9 it's attached to the device and isn't stored in the stateblock. */
2006 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
2007 /* Foo */
2008 } else {
2009 /* Bar */
2012 #endif
2014 return WINED3D_OK;
2017 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
2018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2019 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2020 HRESULT hr = WINED3D_OK;
2022 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
2023 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
2024 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
2025 if (WINED3D_OK == hr) {
2026 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
2027 } else {
2028 WARN("(%p) : Failed to create pixel shader\n", This);
2031 return hr;
2034 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
2035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2036 IWineD3DPaletteImpl *object;
2037 HRESULT hr;
2038 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2040 /* Create the new object */
2041 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2042 if(!object) {
2043 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2044 return E_OUTOFMEMORY;
2047 object->lpVtbl = &IWineD3DPalette_Vtbl;
2048 object->ref = 1;
2049 object->Flags = Flags;
2050 object->parent = Parent;
2051 object->wineD3DDevice = This;
2052 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2054 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2056 if(!object->hpal) {
2057 HeapFree( GetProcessHeap(), 0, object);
2058 return E_OUTOFMEMORY;
2061 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2062 if(FAILED(hr)) {
2063 IWineD3DPalette_Release((IWineD3DPalette *) object);
2064 return hr;
2067 *Palette = (IWineD3DPalette *) object;
2069 return WINED3D_OK;
2072 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2073 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2074 IWineD3DSwapChainImpl *swapchain;
2075 DWORD state;
2077 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2078 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2080 /* TODO: Test if OpenGL is compiled in and loaded */
2082 /* Initialize the texture unit mapping to a 1:1 mapping */
2083 for(state = 0; state < MAX_SAMPLERS; state++) {
2084 This->texUnitMap[state] = state;
2086 This->oneToOneTexUnitMap = TRUE;
2088 /* Setup the implicit swapchain */
2089 TRACE("Creating implicit swapchain\n");
2090 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2091 WARN("Failed to create implicit swapchain\n");
2092 return WINED3DERR_INVALIDCALL;
2095 This->NumberOfSwapChains = 1;
2096 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2097 if(!This->swapchains) {
2098 ERR("Out of memory!\n");
2099 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2100 return E_OUTOFMEMORY;
2102 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2104 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2105 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2106 This->render_targets[0] = swapchain->backBuffer[0];
2108 else {
2109 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2110 This->render_targets[0] = swapchain->frontBuffer;
2112 IWineD3DSurface_AddRef(This->render_targets[0]);
2113 /* Depth Stencil support */
2114 This->stencilBufferTarget = This->depthStencilBuffer;
2115 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
2116 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
2118 if (NULL != This->stencilBufferTarget) {
2119 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2122 /* Set up some starting GL setup */
2123 ENTER_GL();
2125 * Initialize openGL extension related variables
2126 * with Default values
2129 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2130 /* Setup all the devices defaults */
2131 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2132 #if 0
2133 IWineD3DImpl_CheckGraphicsMemory();
2134 #endif
2135 LEAVE_GL();
2137 /* Initialize our list of GLSL programs */
2138 list_init(&This->glsl_shader_progs);
2140 { /* Set a default viewport */
2141 WINED3DVIEWPORT vp;
2142 vp.X = 0;
2143 vp.Y = 0;
2144 vp.Width = *(pPresentationParameters->BackBufferWidth);
2145 vp.Height = *(pPresentationParameters->BackBufferHeight);
2146 vp.MinZ = 0.0f;
2147 vp.MaxZ = 1.0f;
2148 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2151 /* Initialize the current view state */
2152 This->modelview_valid = 1;
2153 This->proj_valid = 0;
2154 This->view_ident = 1;
2155 This->last_was_rhw = 0;
2156 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2157 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2159 /* Clear the screen */
2160 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
2162 /* Mark all states dirty. The Setters will not mark a state dirty when the new value is equal to the old value
2163 * This might create a problem in 2 situations:
2164 * ->The D3D default value is 0, but the opengl default value is something else
2165 * ->D3D7 unintialized D3D and reinitializes it. This way the context is destroyed, be the stateblock unchanged
2167 for(state = 0; state <= STATE_HIGHEST; state++) {
2168 IWineD3DDeviceImpl_MarkStateDirty(This, state);
2171 This->d3d_initialized = TRUE;
2172 return WINED3D_OK;
2175 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2177 int sampler;
2178 uint i;
2179 TRACE("(%p)\n", This);
2181 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2183 /* Delete the mouse cursor texture */
2184 if(This->cursorTexture) {
2185 ENTER_GL();
2186 glDeleteTextures(1, &This->cursorTexture);
2187 LEAVE_GL();
2188 This->cursorTexture = 0;
2191 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2192 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2195 /* Release the buffers (with sanity checks)*/
2196 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2197 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2198 if(This->depthStencilBuffer != This->stencilBufferTarget)
2199 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2201 This->stencilBufferTarget = NULL;
2203 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2204 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2205 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2207 TRACE("Setting rendertarget to NULL\n");
2208 This->render_targets[0] = NULL;
2210 if (This->depthStencilBuffer) {
2211 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2212 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2214 This->depthStencilBuffer = NULL;
2217 for(i=0; i < This->NumberOfSwapChains; i++) {
2218 TRACE("Releasing the implicit swapchain %d\n", i);
2219 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2220 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2224 HeapFree(GetProcessHeap(), 0, This->swapchains);
2225 This->swapchains = NULL;
2226 This->NumberOfSwapChains = 0;
2228 This->d3d_initialized = FALSE;
2229 return WINED3D_OK;
2232 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2234 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2236 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2237 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2238 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2239 * separately.
2241 This->ddraw_fullscreen = fullscreen;
2244 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2247 DEVMODEW DevModeW;
2248 int i;
2249 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2251 TRACE("(%p)->(%x,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2253 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2254 /* Ignore some modes if a description was passed */
2255 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2256 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2257 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2259 TRACE("Enumerating %dx%d@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2261 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2262 return D3D_OK;
2265 return D3D_OK;
2268 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2269 DEVMODEW devmode;
2270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2271 LONG ret;
2272 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2273 RECT clip_rc;
2275 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2277 /* Resize the screen even without a window:
2278 * The app could have unset it with SetCooperativeLevel, but not called
2279 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2280 * but we don't have any hwnd
2283 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2284 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2285 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2286 devmode.dmPelsWidth = pMode->Width;
2287 devmode.dmPelsHeight = pMode->Height;
2289 devmode.dmDisplayFrequency = pMode->RefreshRate;
2290 if (pMode->RefreshRate != 0) {
2291 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2294 /* Only change the mode if necessary */
2295 if( (This->ddraw_width == pMode->Width) &&
2296 (This->ddraw_height == pMode->Height) &&
2297 (This->ddraw_format == pMode->Format) &&
2298 (pMode->RefreshRate == 0) ) {
2299 return D3D_OK;
2302 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2303 if (ret != DISP_CHANGE_SUCCESSFUL) {
2304 if(devmode.dmDisplayFrequency != 0) {
2305 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2306 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2307 devmode.dmDisplayFrequency = 0;
2308 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2310 if(ret != DISP_CHANGE_SUCCESSFUL) {
2311 return DDERR_INVALIDMODE;
2315 /* Store the new values */
2316 This->ddraw_width = pMode->Width;
2317 This->ddraw_height = pMode->Height;
2318 This->ddraw_format = pMode->Format;
2320 /* Only do this with a window of course */
2321 if(This->ddraw_window)
2322 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2324 /* And finally clip mouse to our screen */
2325 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2326 ClipCursor(&clip_rc);
2328 return WINED3D_OK;
2331 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2333 *ppD3D= This->wineD3D;
2334 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2335 IWineD3D_AddRef(*ppD3D);
2336 return WINED3D_OK;
2339 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2340 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2341 * into the video ram as possible and seeing how many fit
2342 * you can also get the correct initial value from nvidia and ATI's driver via X
2343 * texture memory is video memory + AGP memory
2344 *******************/
2345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2346 static BOOL showfixmes = TRUE;
2347 if (showfixmes) {
2348 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2349 (wined3d_settings.emulated_textureram/(1024*1024)),
2350 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2351 showfixmes = FALSE;
2353 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2354 (wined3d_settings.emulated_textureram/(1024*1024)),
2355 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2356 /* return simulated texture memory left */
2357 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2362 /*****
2363 * Get / Set FVF
2364 *****/
2365 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2367 HRESULT hr = WINED3D_OK;
2369 /* Update the current state block */
2370 This->updateStateBlock->fvf = fvf;
2371 This->updateStateBlock->changed.fvf = TRUE;
2372 This->updateStateBlock->set.fvf = TRUE;
2374 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2375 return hr;
2379 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2381 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2382 *pfvf = This->stateBlock->fvf;
2383 return WINED3D_OK;
2386 /*****
2387 * Get / Set Stream Source
2388 *****/
2389 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2391 IWineD3DVertexBuffer *oldSrc;
2393 /**TODO: instance and index data, see
2394 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2396 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2397 **************/
2399 /* D3d9 only, but shouldn't hurt d3d8 */
2400 UINT streamFlags;
2402 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2403 if (streamFlags) {
2404 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2405 FIXME("stream index data not supported\n");
2407 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2408 FIXME("stream instance data not supported\n");
2412 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2414 if (StreamNumber >= MAX_STREAMS) {
2415 WARN("Stream out of range %d\n", StreamNumber);
2416 return WINED3DERR_INVALIDCALL;
2419 oldSrc = This->stateBlock->streamSource[StreamNumber];
2420 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2422 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2423 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2424 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2425 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2426 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2427 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2429 /* Handle recording of state blocks */
2430 if (This->isRecordingState) {
2431 TRACE("Recording... not performing anything\n");
2432 return WINED3D_OK;
2435 /* Same stream object: no action */
2436 if (oldSrc == pStreamData)
2437 return WINED3D_OK;
2439 /* Need to do a getParent and pass the reffs up */
2440 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2441 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2442 so for now, just count internally */
2443 if (pStreamData != NULL) {
2444 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2445 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2446 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2448 vbImpl->stream = StreamNumber;
2449 vbImpl->Flags |= VBFLAG_STREAM;
2450 IWineD3DVertexBuffer_AddRef(pStreamData);
2452 if (oldSrc != NULL) {
2453 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2454 IWineD3DVertexBuffer_Release(oldSrc);
2457 return WINED3D_OK;
2460 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2462 UINT streamFlags;
2464 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2465 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2468 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2469 if (streamFlags) {
2470 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2471 FIXME("stream index data not supported\n");
2473 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2474 FIXME("stream instance data not supported\n");
2478 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2480 if (StreamNumber >= MAX_STREAMS) {
2481 WARN("Stream out of range %d\n", StreamNumber);
2482 return WINED3DERR_INVALIDCALL;
2484 *pStream = This->stateBlock->streamSource[StreamNumber];
2485 *pStride = This->stateBlock->streamStride[StreamNumber];
2486 if (pOffset) {
2487 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2490 if (*pStream == NULL) {
2491 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2492 return WINED3DERR_INVALIDCALL;
2495 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2496 return WINED3D_OK;
2499 /*Should be quite easy, just an extension of vertexdata
2500 ref...
2501 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2503 The divider is a bit odd though
2505 VertexOffset = StartVertex / Divider * StreamStride +
2506 VertexIndex / Divider * StreamStride + StreamOffset
2509 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2512 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2513 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2515 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2516 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2517 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2519 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2520 FIXME("Stream indexing not fully supported\n");
2523 return WINED3D_OK;
2526 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2529 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2530 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2532 TRACE("(%p) : returning %d\n", This, *Divider);
2534 return WINED3D_OK;
2537 /*****
2538 * Get / Set & Multiply Transform
2539 *****/
2540 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2543 /* Most of this routine, comments included copied from ddraw tree initially: */
2544 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2546 /* Handle recording of state blocks */
2547 if (This->isRecordingState) {
2548 TRACE("Recording... not performing anything\n");
2549 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2550 This->updateStateBlock->set.transform[d3dts] = TRUE;
2551 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2552 return WINED3D_OK;
2556 * If the new matrix is the same as the current one,
2557 * we cut off any further processing. this seems to be a reasonable
2558 * optimization because as was noticed, some apps (warcraft3 for example)
2559 * tend towards setting the same matrix repeatedly for some reason.
2561 * From here on we assume that the new matrix is different, wherever it matters.
2563 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2564 TRACE("The app is setting the same matrix over again\n");
2565 return WINED3D_OK;
2566 } else {
2567 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2571 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2572 where ViewMat = Camera space, WorldMat = world space.
2574 In OpenGL, camera and world space is combined into GL_MODELVIEW
2575 matrix. The Projection matrix stay projection matrix.
2578 /* Capture the times we can just ignore the change for now */
2579 if (d3dts == WINED3DTS_WORLDMATRIX(0)) {
2580 This->modelview_valid = FALSE;
2581 return WINED3D_OK;
2583 } else if (d3dts == WINED3DTS_PROJECTION) {
2584 This->proj_valid = FALSE;
2585 return WINED3D_OK;
2587 } else if (d3dts >= WINED3DTS_WORLDMATRIX(1) && d3dts <= WINED3DTS_WORLDMATRIX(255)) {
2588 /* Indexed Vertex Blending Matrices 256 -> 511 */
2589 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2590 FIXME("WINED3DTS_WORLDMATRIX(1..255) not handled\n");
2591 return WINED3D_OK;
2594 /* Now we really are going to have to change a matrix */
2595 ENTER_GL();
2597 if (d3dts >= WINED3DTS_TEXTURE0 && d3dts <= WINED3DTS_TEXTURE7) { /* handle texture matrices */
2598 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2599 } else if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2600 unsigned int k;
2602 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2603 * NOTE: We have to reset the positions even if the light/plane is not currently
2604 * enabled, since the call to enable it will not reset the position.
2605 * NOTE2: Apparently texture transforms do NOT need reapplying
2608 PLIGHTINFOEL *lightChain = NULL;
2609 This->modelview_valid = FALSE;
2610 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2612 glMatrixMode(GL_MODELVIEW);
2613 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2614 glPushMatrix();
2615 glLoadMatrixf((const float *)lpmatrix);
2616 checkGLcall("glLoadMatrixf(...)");
2618 /* Reset lights */
2619 lightChain = This->stateBlock->lights;
2620 while (lightChain && lightChain->glIndex != -1) {
2621 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2622 checkGLcall("glLightfv posn");
2623 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2624 checkGLcall("glLightfv dirn");
2625 lightChain = lightChain->next;
2628 /* Reset Clipping Planes if clipping is enabled */
2629 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2630 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2631 checkGLcall("glClipPlane");
2633 glPopMatrix();
2635 } else { /* What was requested!?? */
2636 WARN("invalid matrix specified: %i\n", d3dts);
2639 /* Release lock, all done */
2640 LEAVE_GL();
2641 return WINED3D_OK;
2644 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2646 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2647 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2648 return WINED3D_OK;
2651 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2652 WINED3DMATRIX *mat = NULL;
2653 WINED3DMATRIX temp;
2655 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2656 * below means it will be recorded in a state block change, but it
2657 * works regardless where it is recorded.
2658 * If this is found to be wrong, change to StateBlock.
2660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2661 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2663 if (State < HIGHEST_TRANSFORMSTATE)
2665 mat = &This->updateStateBlock->transforms[State];
2666 } else {
2667 FIXME("Unhandled transform state!!\n");
2670 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2672 /* Apply change via set transform - will reapply to eg. lights this way */
2673 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2676 /*****
2677 * Get / Set Light
2678 *****/
2679 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2680 you can reference any indexes you want as long as that number max are enabled at any
2681 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2682 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2683 but when recording, just build a chain pretty much of commands to be replayed. */
2685 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2686 float rho;
2687 PLIGHTINFOEL *object, *temp;
2689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2690 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2692 /* If recording state block, just add to end of lights chain */
2693 if (This->isRecordingState) {
2694 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2695 if (NULL == object) {
2696 return WINED3DERR_OUTOFVIDEOMEMORY;
2698 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2699 object->OriginalIndex = Index;
2700 object->glIndex = -1;
2701 object->changed = TRUE;
2703 /* Add to the END of the chain of lights changes to be replayed */
2704 if (This->updateStateBlock->lights == NULL) {
2705 This->updateStateBlock->lights = object;
2706 } else {
2707 temp = This->updateStateBlock->lights;
2708 while (temp->next != NULL) temp=temp->next;
2709 temp->next = object;
2711 TRACE("Recording... not performing anything more\n");
2712 return WINED3D_OK;
2715 /* Ok, not recording any longer so do real work */
2716 object = This->stateBlock->lights;
2717 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2719 /* If we didn't find it in the list of lights, time to add it */
2720 if (object == NULL) {
2721 PLIGHTINFOEL *insertAt,*prevPos;
2723 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2724 if (NULL == object) {
2725 return WINED3DERR_OUTOFVIDEOMEMORY;
2727 object->OriginalIndex = Index;
2728 object->glIndex = -1;
2730 /* Add it to the front of list with the idea that lights will be changed as needed
2731 BUT after any lights currently assigned GL indexes */
2732 insertAt = This->stateBlock->lights;
2733 prevPos = NULL;
2734 while (insertAt != NULL && insertAt->glIndex != -1) {
2735 prevPos = insertAt;
2736 insertAt = insertAt->next;
2739 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2740 This->stateBlock->lights = object;
2741 } else if (insertAt == NULL) { /* End of list */
2742 prevPos->next = object;
2743 object->prev = prevPos;
2744 } else { /* Middle of chain */
2745 if (prevPos == NULL) {
2746 This->stateBlock->lights = object;
2747 } else {
2748 prevPos->next = object;
2750 object->prev = prevPos;
2751 object->next = insertAt;
2752 insertAt->prev = object;
2756 /* Initialize the object */
2757 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,
2758 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2759 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2760 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2761 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2762 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2763 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2765 /* Save away the information */
2766 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2768 switch (pLight->Type) {
2769 case WINED3DLIGHT_POINT:
2770 /* Position */
2771 object->lightPosn[0] = pLight->Position.x;
2772 object->lightPosn[1] = pLight->Position.y;
2773 object->lightPosn[2] = pLight->Position.z;
2774 object->lightPosn[3] = 1.0f;
2775 object->cutoff = 180.0f;
2776 /* FIXME: Range */
2777 break;
2779 case WINED3DLIGHT_DIRECTIONAL:
2780 /* Direction */
2781 object->lightPosn[0] = -pLight->Direction.x;
2782 object->lightPosn[1] = -pLight->Direction.y;
2783 object->lightPosn[2] = -pLight->Direction.z;
2784 object->lightPosn[3] = 0.0;
2785 object->exponent = 0.0f;
2786 object->cutoff = 180.0f;
2787 break;
2789 case WINED3DLIGHT_SPOT:
2790 /* Position */
2791 object->lightPosn[0] = pLight->Position.x;
2792 object->lightPosn[1] = pLight->Position.y;
2793 object->lightPosn[2] = pLight->Position.z;
2794 object->lightPosn[3] = 1.0;
2796 /* Direction */
2797 object->lightDirn[0] = pLight->Direction.x;
2798 object->lightDirn[1] = pLight->Direction.y;
2799 object->lightDirn[2] = pLight->Direction.z;
2800 object->lightDirn[3] = 1.0;
2803 * opengl-ish and d3d-ish spot lights use too different models for the
2804 * light "intensity" as a function of the angle towards the main light direction,
2805 * so we only can approximate very roughly.
2806 * however spot lights are rather rarely used in games (if ever used at all).
2807 * furthermore if still used, probably nobody pays attention to such details.
2809 if (pLight->Falloff == 0) {
2810 rho = 6.28f;
2811 } else {
2812 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2814 if (rho < 0.0001) rho = 0.0001f;
2815 object->exponent = -0.3/log(cos(rho/2));
2816 if (object->exponent > 128.0) {
2817 object->exponent = 128.0;
2819 object->cutoff = pLight->Phi*90/M_PI;
2821 /* FIXME: Range */
2822 break;
2824 default:
2825 FIXME("Unrecognized light type %d\n", pLight->Type);
2828 /* Update the live definitions if the light is currently assigned a glIndex */
2829 if (object->glIndex != -1) {
2830 setup_light(iface, object->glIndex, object);
2832 return WINED3D_OK;
2835 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2836 PLIGHTINFOEL *lightInfo = NULL;
2837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2838 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2840 /* Locate the light in the live lights */
2841 lightInfo = This->stateBlock->lights;
2842 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2844 if (lightInfo == NULL) {
2845 TRACE("Light information requested but light not defined\n");
2846 return WINED3DERR_INVALIDCALL;
2849 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2850 return WINED3D_OK;
2853 /*****
2854 * Get / Set Light Enable
2855 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2856 *****/
2857 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2858 PLIGHTINFOEL *lightInfo = NULL;
2859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2860 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2862 /* Tests show true = 128...not clear why */
2864 Enable = Enable? 128: 0;
2866 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2867 if (This->isRecordingState) {
2868 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2869 if (NULL == lightInfo) {
2870 return WINED3DERR_OUTOFVIDEOMEMORY;
2872 lightInfo->OriginalIndex = Index;
2873 lightInfo->glIndex = -1;
2874 lightInfo->enabledChanged = TRUE;
2875 lightInfo->lightEnabled = Enable;
2877 /* Add to the END of the chain of lights changes to be replayed */
2878 if (This->updateStateBlock->lights == NULL) {
2879 This->updateStateBlock->lights = lightInfo;
2880 } else {
2881 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2882 while (temp->next != NULL) temp=temp->next;
2883 temp->next = lightInfo;
2885 TRACE("Recording... not performing anything more\n");
2886 return WINED3D_OK;
2889 /* Not recording... So, locate the light in the live lights */
2890 lightInfo = This->stateBlock->lights;
2891 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2893 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2894 if (lightInfo == NULL) {
2896 TRACE("Light enabled requested but light not defined, so defining one!\n");
2897 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2899 /* Search for it again! Should be fairly quick as near head of list */
2900 lightInfo = This->stateBlock->lights;
2901 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2902 if (lightInfo == NULL) {
2903 FIXME("Adding default lights has failed dismally\n");
2904 return WINED3DERR_INVALIDCALL;
2908 /* OK, we now have a light... */
2909 if (!Enable) {
2911 /* If we are disabling it, check it was enabled, and
2912 still only do something if it has assigned a glIndex (which it should have!) */
2913 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2914 TRACE("Disabling light set up at gl idx %d\n", lightInfo->glIndex);
2915 ENTER_GL();
2916 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2917 checkGLcall("glDisable GL_LIGHT0+Index");
2918 LEAVE_GL();
2919 } else {
2920 TRACE("Nothing to do as light was not enabled\n");
2922 lightInfo->lightEnabled = Enable;
2923 } else {
2925 /* We are enabling it. If it is enabled, it's really simple */
2926 if (lightInfo->lightEnabled) {
2927 /* nop */
2928 TRACE("Nothing to do as light was enabled\n");
2930 /* If it already has a glIndex, it's still simple */
2931 } else if (lightInfo->glIndex != -1) {
2932 TRACE("Reusing light as already set up at gl idx %d\n", lightInfo->glIndex);
2933 lightInfo->lightEnabled = Enable;
2934 ENTER_GL();
2935 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2936 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2937 LEAVE_GL();
2939 /* Otherwise got to find space - lights are ordered gl indexes first */
2940 } else {
2941 PLIGHTINFOEL *bsf = NULL;
2942 PLIGHTINFOEL *pos = This->stateBlock->lights;
2943 PLIGHTINFOEL *prev = NULL;
2944 int Index= 0;
2945 int glIndex = -1;
2947 /* Try to minimize changes as much as possible */
2948 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2950 /* Try to remember which index can be replaced if necessary */
2951 if (bsf==NULL && !pos->lightEnabled) {
2952 /* Found a light we can replace, save as best replacement */
2953 bsf = pos;
2956 /* Step to next space */
2957 prev = pos;
2958 pos = pos->next;
2959 Index ++;
2962 /* If we have too many active lights, fail the call */
2963 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2964 FIXME("Program requests too many concurrent lights\n");
2965 return WINED3DERR_INVALIDCALL;
2967 /* If we have allocated all lights, but not all are enabled,
2968 reuse one which is not enabled */
2969 } else if (Index == This->maxConcurrentLights) {
2970 /* use bsf - Simply swap the new light and the BSF one */
2971 PLIGHTINFOEL *bsfNext = bsf->next;
2972 PLIGHTINFOEL *bsfPrev = bsf->prev;
2974 /* Sort out ends */
2975 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2976 if (bsf->prev != NULL) {
2977 bsf->prev->next = lightInfo;
2978 } else {
2979 This->stateBlock->lights = lightInfo;
2982 /* If not side by side, lots of chains to update */
2983 if (bsf->next != lightInfo) {
2984 lightInfo->prev->next = bsf;
2985 bsf->next->prev = lightInfo;
2986 bsf->next = lightInfo->next;
2987 bsf->prev = lightInfo->prev;
2988 lightInfo->next = bsfNext;
2989 lightInfo->prev = bsfPrev;
2991 } else {
2992 /* Simple swaps */
2993 bsf->prev = lightInfo;
2994 bsf->next = lightInfo->next;
2995 lightInfo->next = bsf;
2996 lightInfo->prev = bsfPrev;
3000 /* Update states */
3001 glIndex = bsf->glIndex;
3002 bsf->glIndex = -1;
3003 lightInfo->glIndex = glIndex;
3004 lightInfo->lightEnabled = Enable;
3006 /* Finally set up the light in gl itself */
3007 TRACE("Replacing light which was set up at gl idx %d\n", lightInfo->glIndex);
3008 ENTER_GL();
3009 setup_light(iface, glIndex, lightInfo);
3010 glEnable(GL_LIGHT0 + glIndex);
3011 checkGLcall("glEnable GL_LIGHT0 new setup");
3012 LEAVE_GL();
3014 /* If we reached the end of the allocated lights, with space in the
3015 gl lights, setup a new light */
3016 } else if (pos->glIndex == -1) {
3018 /* We reached the end of the allocated gl lights, so already
3019 know the index of the next one! */
3020 glIndex = Index;
3021 lightInfo->glIndex = glIndex;
3022 lightInfo->lightEnabled = Enable;
3024 /* In an ideal world, it's already in the right place */
3025 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
3026 /* No need to move it */
3027 } else {
3028 /* Remove this light from the list */
3029 lightInfo->prev->next = lightInfo->next;
3030 if (lightInfo->next != NULL) {
3031 lightInfo->next->prev = lightInfo->prev;
3034 /* Add in at appropriate place (inbetween prev and pos) */
3035 lightInfo->prev = prev;
3036 lightInfo->next = pos;
3037 if (prev == NULL) {
3038 This->stateBlock->lights = lightInfo;
3039 } else {
3040 prev->next = lightInfo;
3042 if (pos != NULL) {
3043 pos->prev = lightInfo;
3047 /* Finally set up the light in gl itself */
3048 TRACE("Defining new light at gl idx %d\n", lightInfo->glIndex);
3049 ENTER_GL();
3050 setup_light(iface, glIndex, lightInfo);
3051 glEnable(GL_LIGHT0 + glIndex);
3052 checkGLcall("glEnable GL_LIGHT0 new setup");
3053 LEAVE_GL();
3058 return WINED3D_OK;
3061 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3063 PLIGHTINFOEL *lightInfo = NULL;
3064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3065 TRACE("(%p) : for idx(%d)\n", This, Index);
3067 /* Locate the light in the live lights */
3068 lightInfo = This->stateBlock->lights;
3069 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
3071 if (lightInfo == NULL) {
3072 TRACE("Light enabled state requested but light not defined\n");
3073 return WINED3DERR_INVALIDCALL;
3075 *pEnable = lightInfo->lightEnabled;
3076 return WINED3D_OK;
3079 /*****
3080 * Get / Set Clip Planes
3081 *****/
3082 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3084 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3086 /* Validate Index */
3087 if (Index >= GL_LIMITS(clipplanes)) {
3088 TRACE("Application has requested clipplane this device doesn't support\n");
3089 return WINED3DERR_INVALIDCALL;
3092 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3093 This->updateStateBlock->set.clipplane[Index] = TRUE;
3094 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3095 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3096 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3097 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3099 /* Handle recording of state blocks */
3100 if (This->isRecordingState) {
3101 TRACE("Recording... not performing anything\n");
3102 return WINED3D_OK;
3105 /* Apply it */
3107 ENTER_GL();
3109 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
3110 glMatrixMode(GL_MODELVIEW);
3111 glPushMatrix();
3112 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
3114 TRACE("Clipplane [%f,%f,%f,%f]\n",
3115 This->updateStateBlock->clipplane[Index][0],
3116 This->updateStateBlock->clipplane[Index][1],
3117 This->updateStateBlock->clipplane[Index][2],
3118 This->updateStateBlock->clipplane[Index][3]);
3119 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3120 checkGLcall("glClipPlane");
3122 glPopMatrix();
3123 LEAVE_GL();
3125 return WINED3D_OK;
3128 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3130 TRACE("(%p) : for idx %d\n", This, Index);
3132 /* Validate Index */
3133 if (Index >= GL_LIMITS(clipplanes)) {
3134 TRACE("Application has requested clipplane this device doesn't support\n");
3135 return WINED3DERR_INVALIDCALL;
3138 pPlane[0] = This->stateBlock->clipplane[Index][0];
3139 pPlane[1] = This->stateBlock->clipplane[Index][1];
3140 pPlane[2] = This->stateBlock->clipplane[Index][2];
3141 pPlane[3] = This->stateBlock->clipplane[Index][3];
3142 return WINED3D_OK;
3145 /*****
3146 * Get / Set Clip Plane Status
3147 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3148 *****/
3149 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3151 FIXME("(%p) : stub\n", This);
3152 if (NULL == pClipStatus) {
3153 return WINED3DERR_INVALIDCALL;
3155 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3156 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3157 return WINED3D_OK;
3160 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3162 FIXME("(%p) : stub\n", This);
3163 if (NULL == pClipStatus) {
3164 return WINED3DERR_INVALIDCALL;
3166 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3167 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3168 return WINED3D_OK;
3171 /*****
3172 * Get / Set Material
3173 *****/
3174 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3177 This->updateStateBlock->changed.material = TRUE;
3178 This->updateStateBlock->set.material = TRUE;
3179 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3181 /* Handle recording of state blocks */
3182 if (This->isRecordingState) {
3183 TRACE("Recording... not performing anything\n");
3184 return WINED3D_OK;
3187 ENTER_GL();
3188 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3189 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3190 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3191 pMaterial->Ambient.b, pMaterial->Ambient.a);
3192 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3193 pMaterial->Specular.b, pMaterial->Specular.a);
3194 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3195 pMaterial->Emissive.b, pMaterial->Emissive.a);
3196 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3198 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3199 checkGLcall("glMaterialfv(GL_AMBIENT)");
3200 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3201 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3203 /* Only change material color if specular is enabled, otherwise it is set to black */
3204 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3205 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3206 checkGLcall("glMaterialfv(GL_SPECULAR");
3207 } else {
3208 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3209 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3210 checkGLcall("glMaterialfv(GL_SPECULAR");
3212 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3213 checkGLcall("glMaterialfv(GL_EMISSION)");
3214 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3215 checkGLcall("glMaterialf(GL_SHININESS");
3217 LEAVE_GL();
3218 return WINED3D_OK;
3221 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3223 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3224 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3225 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3226 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3227 pMaterial->Ambient.b, pMaterial->Ambient.a);
3228 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3229 pMaterial->Specular.b, pMaterial->Specular.a);
3230 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3231 pMaterial->Emissive.b, pMaterial->Emissive.a);
3232 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3234 return WINED3D_OK;
3237 /*****
3238 * Get / Set Indices
3239 *****/
3240 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3241 UINT BaseVertexIndex) {
3242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3243 IWineD3DIndexBuffer *oldIdxs;
3245 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3246 oldIdxs = This->updateStateBlock->pIndexData;
3248 This->updateStateBlock->changed.indices = TRUE;
3249 This->updateStateBlock->set.indices = TRUE;
3250 This->updateStateBlock->pIndexData = pIndexData;
3251 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3253 /* Handle recording of state blocks */
3254 if (This->isRecordingState) {
3255 TRACE("Recording... not performing anything\n");
3256 return WINED3D_OK;
3259 if (NULL != pIndexData) {
3260 IWineD3DIndexBuffer_AddRef(pIndexData);
3262 if (NULL != oldIdxs) {
3263 IWineD3DIndexBuffer_Release(oldIdxs);
3265 return WINED3D_OK;
3268 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3271 *ppIndexData = This->stateBlock->pIndexData;
3273 /* up ref count on ppindexdata */
3274 if (*ppIndexData) {
3275 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3276 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3277 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3278 }else{
3279 TRACE("(%p) No index data set\n", This);
3281 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3283 return WINED3D_OK;
3286 /*****
3287 * Get / Set Viewports
3288 *****/
3289 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3292 TRACE("(%p)\n", This);
3293 This->updateStateBlock->changed.viewport = TRUE;
3294 This->updateStateBlock->set.viewport = TRUE;
3295 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3297 /* Handle recording of state blocks */
3298 if (This->isRecordingState) {
3299 TRACE("Recording... not performing anything\n");
3300 return WINED3D_OK;
3302 This->viewport_changed = TRUE;
3304 ENTER_GL();
3306 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3307 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3309 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3310 checkGLcall("glDepthRange");
3311 /* Note: GL requires lower left, DirectX supplies upper left */
3312 /* TODO: replace usage of renderTarget with context management */
3313 glViewport(pViewport->X,
3314 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3315 pViewport->Width, pViewport->Height);
3317 checkGLcall("glViewport");
3319 LEAVE_GL();
3321 return WINED3D_OK;
3325 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3327 TRACE("(%p)\n", This);
3328 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3329 return WINED3D_OK;
3332 /*****
3333 * Get / Set Render States
3334 * TODO: Verify against dx9 definitions
3335 *****/
3336 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3339 DWORD oldValue = This->stateBlock->renderState[State];
3341 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3343 This->updateStateBlock->changed.renderState[State] = TRUE;
3344 This->updateStateBlock->set.renderState[State] = TRUE;
3345 This->updateStateBlock->renderState[State] = Value;
3347 /* Handle recording of state blocks */
3348 if (This->isRecordingState) {
3349 TRACE("Recording... not performing anything\n");
3350 return WINED3D_OK;
3353 /* Compared here and not before the assignment to allow proper stateblock recording */
3354 if(Value == oldValue) {
3355 TRACE("Application is setting the old value over, nothing to do\n");
3356 } else {
3357 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3360 return WINED3D_OK;
3363 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3365 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3366 *pValue = This->stateBlock->renderState[State];
3367 return WINED3D_OK;
3370 /*****
3371 * Get / Set Sampler States
3372 * TODO: Verify against dx9 definitions
3373 *****/
3375 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3377 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
3380 * SetSampler is designed to allow for more than the standard up to 8 textures
3381 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3382 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3384 * http://developer.nvidia.com/object/General_FAQ.html#t6
3386 * There are two new settings for GForce
3387 * the sampler one:
3388 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3389 * and the texture one:
3390 * GL_MAX_TEXTURE_COORDS_ARB.
3391 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3392 ******************/
3393 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
3394 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
3395 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
3396 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
3397 return WINED3DERR_INVALIDCALL;
3400 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
3401 debug_d3dsamplerstate(Type), Type, Value);
3402 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3403 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
3404 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3406 /* Handle recording of state blocks */
3407 if (This->isRecordingState) {
3408 TRACE("Recording... not performing anything\n");
3409 return WINED3D_OK;
3412 if(oldValue == Value) {
3413 TRACE("Application is setting the old value over, nothing to do\n");
3414 return WINED3D_OK;
3417 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3419 return WINED3D_OK;
3422 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3424 /** TODO: check that sampler is in range **/
3425 *Value = This->stateBlock->samplerState[Sampler][Type];
3426 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
3428 return WINED3D_OK;
3431 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3433 RECT windowRect;
3434 UINT winHeight;
3436 GetClientRect(((IWineD3DSwapChainImpl *)This->swapchains[0])->win_handle, &windowRect);
3437 /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
3438 * Warning2: Even in windowed mode the coords are relative to the window, not the screen
3440 winHeight = windowRect.bottom - windowRect.top;
3441 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This, pRect->left, pRect->bottom - winHeight,
3442 pRect->right - pRect->left, pRect->bottom - pRect->top);
3443 ENTER_GL();
3444 glScissor(pRect->left, winHeight - pRect->bottom, pRect->right - pRect->left, pRect->bottom - pRect->top);
3445 checkGLcall("glScissor");
3446 LEAVE_GL();
3448 return WINED3D_OK;
3451 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3453 GLint scissorBox[4];
3455 ENTER_GL();
3456 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
3457 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
3458 pRect->left = scissorBox[0];
3459 pRect->top = scissorBox[1];
3460 pRect->right = scissorBox[0] + scissorBox[2];
3461 pRect->bottom = scissorBox[1] + scissorBox[3];
3462 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3463 LEAVE_GL();
3464 return WINED3D_OK;
3467 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3469 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3471 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3473 This->updateStateBlock->vertexDecl = pDecl;
3474 This->updateStateBlock->changed.vertexDecl = TRUE;
3475 This->updateStateBlock->set.vertexDecl = TRUE;
3477 if (This->isRecordingState) {
3478 TRACE("Recording... not performing anything\n");
3481 if (NULL != pDecl) {
3482 IWineD3DVertexDeclaration_AddRef(pDecl);
3484 if (NULL != oldDecl) {
3485 IWineD3DVertexDeclaration_Release(oldDecl);
3487 return WINED3D_OK;
3490 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3493 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3495 *ppDecl = This->stateBlock->vertexDecl;
3496 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3497 return WINED3D_OK;
3500 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3502 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3504 This->updateStateBlock->vertexShader = pShader;
3505 This->updateStateBlock->changed.vertexShader = TRUE;
3506 This->updateStateBlock->set.vertexShader = TRUE;
3508 if (This->isRecordingState) {
3509 TRACE("Recording... not performing anything\n");
3512 if (NULL != pShader) {
3513 IWineD3DVertexShader_AddRef(pShader);
3515 if (NULL != oldShader) {
3516 IWineD3DVertexShader_Release(oldShader);
3519 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3521 * TODO: merge HAL shaders context switching from prototype
3523 return WINED3D_OK;
3526 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3529 if (NULL == ppShader) {
3530 return WINED3DERR_INVALIDCALL;
3532 *ppShader = This->stateBlock->vertexShader;
3533 if( NULL != *ppShader)
3534 IWineD3DVertexShader_AddRef(*ppShader);
3536 TRACE("(%p) : returning %p\n", This, *ppShader);
3537 return WINED3D_OK;
3540 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3541 IWineD3DDevice *iface,
3542 UINT start,
3543 CONST BOOL *srcData,
3544 UINT count) {
3546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3547 int i, cnt = min(count, MAX_CONST_B - start);
3549 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3550 iface, srcData, start, count);
3552 if (srcData == NULL || cnt < 0)
3553 return WINED3DERR_INVALIDCALL;
3555 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3556 for (i = 0; i < cnt; i++)
3557 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3559 for (i = start; i < cnt + start; ++i) {
3560 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3561 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3564 return WINED3D_OK;
3567 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3568 IWineD3DDevice *iface,
3569 UINT start,
3570 BOOL *dstData,
3571 UINT count) {
3573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3574 int cnt = min(count, MAX_CONST_B - start);
3576 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3577 iface, dstData, start, count);
3579 if (dstData == NULL || cnt < 0)
3580 return WINED3DERR_INVALIDCALL;
3582 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3583 return WINED3D_OK;
3586 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3587 IWineD3DDevice *iface,
3588 UINT start,
3589 CONST int *srcData,
3590 UINT count) {
3592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3593 int i, cnt = min(count, MAX_CONST_I - start);
3595 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3596 iface, srcData, start, count);
3598 if (srcData == NULL || cnt < 0)
3599 return WINED3DERR_INVALIDCALL;
3601 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3602 for (i = 0; i < cnt; i++)
3603 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3604 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3606 for (i = start; i < cnt + start; ++i) {
3607 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3608 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3611 return WINED3D_OK;
3614 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3615 IWineD3DDevice *iface,
3616 UINT start,
3617 int *dstData,
3618 UINT count) {
3620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3621 int cnt = min(count, MAX_CONST_I - start);
3623 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3624 iface, dstData, start, count);
3626 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3627 return WINED3DERR_INVALIDCALL;
3629 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3630 return WINED3D_OK;
3633 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3634 IWineD3DDevice *iface,
3635 UINT start,
3636 CONST float *srcData,
3637 UINT count) {
3639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3640 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3642 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3643 iface, srcData, start, count);
3645 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
3646 return WINED3DERR_INVALIDCALL;
3648 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3649 for (i = 0; i < cnt; i++)
3650 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3651 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3653 for (i = start; i < cnt + start; ++i) {
3654 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3655 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3656 ptr->idx = i;
3657 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3658 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3660 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3663 return WINED3D_OK;
3666 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3667 IWineD3DDevice *iface,
3668 UINT start,
3669 float *dstData,
3670 UINT count) {
3672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3673 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3675 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3676 iface, dstData, start, count);
3678 if (dstData == NULL || cnt < 0)
3679 return WINED3DERR_INVALIDCALL;
3681 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3682 return WINED3D_OK;
3685 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3686 DWORD i;
3687 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3688 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3692 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3693 DWORD i, tex;
3694 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3695 * it is never called.
3697 * Rules are:
3698 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3699 * that would be really messy and require shader recompilation
3700 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3701 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3702 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3703 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3705 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3706 if(This->oneToOneTexUnitMap) {
3707 TRACE("Not touching 1:1 map\n");
3708 return;
3710 TRACE("Restoring 1:1 texture unit mapping\n");
3711 /* Restore a 1:1 mapping */
3712 for(i = 0; i < MAX_SAMPLERS; i++) {
3713 if(This->texUnitMap[i] != i) {
3714 This->texUnitMap[i] = i;
3715 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3716 markTextureStagesDirty(This, i);
3719 This->oneToOneTexUnitMap = TRUE;
3720 return;
3721 } else {
3722 /* No pixel shader, and we do not have enought texture units available. Try to skip NULL textures
3723 * First, see if we can succeed at all
3725 tex = 0;
3726 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3727 if(This->stateBlock->textures[i] == NULL) tex++;
3730 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3731 FIXME("Too many bound textures to support the combiner settings\n");
3732 return;
3735 /* Now work out the mapping */
3736 tex = 0;
3737 This->oneToOneTexUnitMap = FALSE;
3738 FIXME("Non 1:1 mapping UNTESTED!\n");
3739 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3740 if(This->stateBlock->textures[i] == NULL) tex++;
3741 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3742 if(This->texUnitMap[i] != tex) {
3743 This->texUnitMap[i] = tex;
3744 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3745 markTextureStagesDirty(This, i);
3751 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3753 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3754 This->updateStateBlock->pixelShader = pShader;
3755 This->updateStateBlock->changed.pixelShader = TRUE;
3756 This->updateStateBlock->set.pixelShader = TRUE;
3758 /* Handle recording of state blocks */
3759 if (This->isRecordingState) {
3760 TRACE("Recording... not performing anything\n");
3763 if (NULL != pShader) {
3764 IWineD3DPixelShader_AddRef(pShader);
3766 if (NULL != oldShader) {
3767 IWineD3DPixelShader_Release(oldShader);
3770 if (This->isRecordingState) {
3771 TRACE("Recording... not performing anything\n");
3772 return WINED3D_OK;
3775 if(pShader == oldShader) {
3776 TRACE("App is setting the old pixel shader over, nothing to do\n");
3777 return WINED3D_OK;
3780 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3781 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3783 /* Rebuild the texture unit mapping if nvrc's are supported */
3784 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3785 IWineD3DDeviceImpl_FindTexUnitMap(This);
3788 return WINED3D_OK;
3791 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3794 if (NULL == ppShader) {
3795 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3796 return WINED3DERR_INVALIDCALL;
3799 *ppShader = This->stateBlock->pixelShader;
3800 if (NULL != *ppShader) {
3801 IWineD3DPixelShader_AddRef(*ppShader);
3803 TRACE("(%p) : returning %p\n", This, *ppShader);
3804 return WINED3D_OK;
3807 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3808 IWineD3DDevice *iface,
3809 UINT start,
3810 CONST BOOL *srcData,
3811 UINT count) {
3813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3814 int i, cnt = min(count, MAX_CONST_B - start);
3816 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3817 iface, srcData, start, count);
3819 if (srcData == NULL || cnt < 0)
3820 return WINED3DERR_INVALIDCALL;
3822 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3823 for (i = 0; i < cnt; i++)
3824 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3826 for (i = start; i < cnt + start; ++i) {
3827 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3828 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3831 return WINED3D_OK;
3834 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3835 IWineD3DDevice *iface,
3836 UINT start,
3837 BOOL *dstData,
3838 UINT count) {
3840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3841 int cnt = min(count, MAX_CONST_B - start);
3843 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3844 iface, dstData, start, count);
3846 if (dstData == NULL || cnt < 0)
3847 return WINED3DERR_INVALIDCALL;
3849 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3850 return WINED3D_OK;
3853 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3854 IWineD3DDevice *iface,
3855 UINT start,
3856 CONST int *srcData,
3857 UINT count) {
3859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3860 int i, cnt = min(count, MAX_CONST_I - start);
3862 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3863 iface, srcData, start, count);
3865 if (srcData == NULL || cnt < 0)
3866 return WINED3DERR_INVALIDCALL;
3868 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3869 for (i = 0; i < cnt; i++)
3870 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3871 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3873 for (i = start; i < cnt + start; ++i) {
3874 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3875 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3878 return WINED3D_OK;
3881 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3882 IWineD3DDevice *iface,
3883 UINT start,
3884 int *dstData,
3885 UINT count) {
3887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3888 int cnt = min(count, MAX_CONST_I - start);
3890 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3891 iface, dstData, start, count);
3893 if (dstData == NULL || cnt < 0)
3894 return WINED3DERR_INVALIDCALL;
3896 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3897 return WINED3D_OK;
3900 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3901 IWineD3DDevice *iface,
3902 UINT start,
3903 CONST float *srcData,
3904 UINT count) {
3906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3907 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3909 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3910 iface, srcData, start, count);
3912 if (srcData == NULL || cnt < 0)
3913 return WINED3DERR_INVALIDCALL;
3915 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3916 for (i = 0; i < cnt; i++)
3917 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3918 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3920 for (i = start; i < cnt + start; ++i) {
3921 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3922 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3923 ptr->idx = i;
3924 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3925 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3927 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3930 return WINED3D_OK;
3933 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3934 IWineD3DDevice *iface,
3935 UINT start,
3936 float *dstData,
3937 UINT count) {
3939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3940 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3942 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3943 iface, dstData, start, count);
3945 if (dstData == NULL || cnt < 0)
3946 return WINED3DERR_INVALIDCALL;
3948 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3949 return WINED3D_OK;
3952 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3953 static HRESULT
3954 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3955 char *dest_ptr, *dest_conv = NULL;
3956 unsigned int i;
3957 DWORD DestFVF = dest->fvf;
3958 WINED3DVIEWPORT vp;
3959 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3960 BOOL doClip;
3961 int numTextures;
3963 if (SrcFVF & WINED3DFVF_NORMAL) {
3964 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3967 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3968 ERR("Source has no position mask\n");
3969 return WINED3DERR_INVALIDCALL;
3972 /* We might access VBOs from this code, so hold the lock */
3973 ENTER_GL();
3975 if (dest->resource.allocatedMemory == NULL) {
3976 /* This may happen if we do direct locking into a vbo. Unlikely,
3977 * but theoretically possible(ddraw processvertices test)
3979 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3980 if(!dest->resource.allocatedMemory) {
3981 LEAVE_GL();
3982 ERR("Out of memory\n");
3983 return E_OUTOFMEMORY;
3985 if(dest->vbo) {
3986 void *src;
3987 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3988 checkGLcall("glBindBufferARB");
3989 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3990 if(src) {
3991 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3993 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3994 checkGLcall("glUnmapBufferARB");
3998 /* Get a pointer into the destination vbo(create one if none exists) and
3999 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4001 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4002 CreateVBO(dest);
4005 if(dest->vbo) {
4006 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4007 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
4008 if(!dest_conv) {
4009 ERR("glMapBuffer failed\n");
4010 /* Continue without storing converted vertices */
4014 /* Should I clip?
4015 * a) WINED3DRS_CLIPPING is enabled
4016 * b) WINED3DVOP_CLIP is passed
4018 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4019 static BOOL warned = FALSE;
4021 * The clipping code is not quite correct. Some things need
4022 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4023 * so disable clipping for now.
4024 * (The graphics in Half-Life are broken, and my processvertices
4025 * test crashes with IDirect3DDevice3)
4026 doClip = TRUE;
4028 doClip = FALSE;
4029 if(!warned) {
4030 warned = TRUE;
4031 FIXME("Clipping is broken and disabled for now\n");
4033 } else doClip = FALSE;
4034 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4035 if(dest_conv) {
4036 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4039 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4040 WINED3DTS_VIEW,
4041 &view_mat);
4042 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4043 WINED3DTS_PROJECTION,
4044 &proj_mat);
4045 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4046 WINED3DTS_WORLDMATRIX(0),
4047 &world_mat);
4049 TRACE("View mat:\n");
4050 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); \
4051 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); \
4052 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); \
4053 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); \
4055 TRACE("Proj mat:\n");
4056 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); \
4057 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); \
4058 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); \
4059 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); \
4061 TRACE("World mat:\n");
4062 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); \
4063 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); \
4064 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); \
4065 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); \
4067 /* Get the viewport */
4068 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4069 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4070 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4072 multiply_matrix(&mat,&view_mat,&world_mat);
4073 multiply_matrix(&mat,&proj_mat,&mat);
4075 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4077 for (i = 0; i < dwCount; i+= 1) {
4078 unsigned int tex_index;
4080 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4081 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4082 /* The position first */
4083 float *p =
4084 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4085 float x, y, z, rhw;
4086 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4088 /* Multiplication with world, view and projection matrix */
4089 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);
4090 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);
4091 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);
4092 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);
4094 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4096 /* WARNING: The following things are taken from d3d7 and were not yet checked
4097 * against d3d8 or d3d9!
4100 /* Clipping conditions: From
4101 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
4103 * A vertex is clipped if it does not match the following requirements
4104 * -rhw < x <= rhw
4105 * -rhw < y <= rhw
4106 * 0 < z <= rhw
4107 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4109 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4110 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4114 if( !doClip ||
4115 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4116 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4117 ( rhw > eps ) ) ) {
4119 /* "Normal" viewport transformation (not clipped)
4120 * 1) The values are divided by rhw
4121 * 2) The y axis is negative, so multiply it with -1
4122 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4123 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4124 * 4) Multiply x with Width/2 and add Width/2
4125 * 5) The same for the height
4126 * 6) Add the viewpoint X and Y to the 2D coordinates and
4127 * The minimum Z value to z
4128 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4130 * Well, basically it's simply a linear transformation into viewport
4131 * coordinates
4134 x /= rhw;
4135 y /= rhw;
4136 z /= rhw;
4138 y *= -1;
4140 x *= vp.Width / 2;
4141 y *= vp.Height / 2;
4142 z *= vp.MaxZ - vp.MinZ;
4144 x += vp.Width / 2 + vp.X;
4145 y += vp.Height / 2 + vp.Y;
4146 z += vp.MinZ;
4148 rhw = 1 / rhw;
4149 } else {
4150 /* That vertex got clipped
4151 * Contrary to OpenGL it is not dropped completely, it just
4152 * undergoes a different calculation.
4154 TRACE("Vertex got clipped\n");
4155 x += rhw;
4156 y += rhw;
4158 x /= 2;
4159 y /= 2;
4161 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4162 * outside of the main vertex buffer memory. That needs some more
4163 * investigation...
4167 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4170 ( (float *) dest_ptr)[0] = x;
4171 ( (float *) dest_ptr)[1] = y;
4172 ( (float *) dest_ptr)[2] = z;
4173 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4175 dest_ptr += 3 * sizeof(float);
4177 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4178 dest_ptr += sizeof(float);
4181 if(dest_conv) {
4182 float w = 1 / rhw;
4183 ( (float *) dest_conv)[0] = x * w;
4184 ( (float *) dest_conv)[1] = y * w;
4185 ( (float *) dest_conv)[2] = z * w;
4186 ( (float *) dest_conv)[3] = w;
4188 dest_conv += 3 * sizeof(float);
4190 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4191 dest_conv += sizeof(float);
4195 if (DestFVF & WINED3DFVF_PSIZE) {
4196 dest_ptr += sizeof(DWORD);
4197 if(dest_conv) dest_conv += sizeof(DWORD);
4199 if (DestFVF & WINED3DFVF_NORMAL) {
4200 float *normal =
4201 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4202 /* AFAIK this should go into the lighting information */
4203 FIXME("Didn't expect the destination to have a normal\n");
4204 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4205 if(dest_conv) {
4206 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4210 if (DestFVF & WINED3DFVF_DIFFUSE) {
4211 DWORD *color_d =
4212 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4213 if(!color_d) {
4214 static BOOL warned = FALSE;
4216 if(!warned) {
4217 ERR("No diffuse color in source, but destination has one\n");
4218 warned = TRUE;
4221 *( (DWORD *) dest_ptr) = 0xffffffff;
4222 dest_ptr += sizeof(DWORD);
4224 if(dest_conv) {
4225 *( (DWORD *) dest_conv) = 0xffffffff;
4226 dest_conv += sizeof(DWORD);
4229 else {
4230 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4231 if(dest_conv) {
4232 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4233 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4234 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4235 dest_conv += sizeof(DWORD);
4240 if (DestFVF & WINED3DFVF_SPECULAR) {
4241 /* What's the color value in the feedback buffer? */
4242 DWORD *color_s =
4243 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4244 if(!color_s) {
4245 static BOOL warned = FALSE;
4247 if(!warned) {
4248 ERR("No specular color in source, but destination has one\n");
4249 warned = TRUE;
4252 *( (DWORD *) dest_ptr) = 0xFF000000;
4253 dest_ptr += sizeof(DWORD);
4255 if(dest_conv) {
4256 *( (DWORD *) dest_conv) = 0xFF000000;
4257 dest_conv += sizeof(DWORD);
4260 else {
4261 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4262 if(dest_conv) {
4263 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4264 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4265 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4266 dest_conv += sizeof(DWORD);
4271 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4272 float *tex_coord =
4273 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4274 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4275 if(!tex_coord) {
4276 ERR("No source texture, but destination requests one\n");
4277 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4278 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4280 else {
4281 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4282 if(dest_conv) {
4283 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4289 if(dest_conv) {
4290 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4291 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
4294 LEAVE_GL();
4296 return WINED3D_OK;
4298 #undef copy_and_next
4300 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
4301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4302 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
4303 WineDirect3DVertexStridedData strided;
4304 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4306 if (!SrcImpl) {
4307 WARN("NULL source vertex buffer\n");
4308 return WINED3DERR_INVALIDCALL;
4310 /* We don't need the source vbo because this buffer is only used as
4311 * a source for ProcessVertices. Avoid wasting resources by converting the
4312 * buffer and loading the VBO
4314 if(SrcImpl->vbo) {
4315 TRACE("Releasing the source vbo, it won't be needed\n");
4317 if(!SrcImpl->resource.allocatedMemory) {
4318 /* Rescue the data from the buffer */
4319 void *src;
4320 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
4321 if(!SrcImpl->resource.allocatedMemory) {
4322 ERR("Out of memory\n");
4323 return E_OUTOFMEMORY;
4326 ENTER_GL();
4327 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
4328 checkGLcall("glBindBufferARB");
4330 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4331 if(src) {
4332 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
4335 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4336 checkGLcall("glUnmapBufferARB");
4337 } else {
4338 ENTER_GL();
4341 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
4342 checkGLcall("glBindBufferARB");
4343 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
4344 checkGLcall("glDeleteBuffersARB");
4345 LEAVE_GL();
4347 SrcImpl->vbo = 0;
4350 memset(&strided, 0, sizeof(strided));
4351 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
4353 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4356 /*****
4357 * Apply / Get / Set Texture Stage States
4358 * TODO: Verify against dx9 definitions
4359 *****/
4361 /* NOTE: It's expected that this function is going to be called lots of times with the same stage active, so make it the callers responsibility to GLACTIVETEXTURE(Stage) for better state management. Set the correct Texture unit active before calling ApplyTextureStageState */
4362 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
4363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4364 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
4365 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4367 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4369 /* Check that the stage is within limits */
4370 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
4371 TRACE("Attempt to access invalid texture rejected\n");
4372 return;
4375 ENTER_GL();
4377 switch (Type) {
4378 case WINED3DTSS_ALPHAOP :
4379 case WINED3DTSS_COLOROP :
4380 /* nothing to do as moved to drawprim for now */
4381 break;
4382 case WINED3DTSS_ADDRESSW :
4383 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
4384 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
4385 FIXME("Unrecognized or unsupported WINED3DTADDRESS_* value %d, state %d\n", Value, Type);
4387 } else {
4388 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
4389 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
4390 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
4391 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
4393 #endif
4394 case WINED3DTSS_TEXCOORDINDEX :
4396 /* Handled from the state table */
4398 break;
4400 /* Unhandled */
4401 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
4402 set_texture_matrix((float *)&This->stateBlock->transforms[WINED3DTS_TEXTURE0 + Stage].u.m[0][0], Value, (This->stateBlock->textureState[Stage][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) != WINED3DTSS_TCI_PASSTHRU);
4403 break;
4405 case WINED3DTSS_BUMPENVMAT00 :
4406 case WINED3DTSS_BUMPENVMAT01 :
4407 TRACE("BUMPENVMAT0%u Stage=%d, Type=%d, Value =%d\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
4408 break;
4409 case WINED3DTSS_BUMPENVMAT10 :
4410 case WINED3DTSS_BUMPENVMAT11 :
4411 TRACE("BUMPENVMAT1%u Stage=%d, Type=%d, Value =%d\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
4412 break;
4414 case WINED3DTSS_BUMPENVLSCALE :
4415 TRACE("BUMPENVLSCALE Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
4416 break;
4418 case WINED3DTSS_BUMPENVLOFFSET :
4419 TRACE("BUMPENVLOFFSET Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
4420 break;
4422 case WINED3DTSS_RESULTARG :
4423 TRACE("RESULTARG Still a stub, Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
4424 break;
4426 default:
4427 /* Put back later: FIXME("(%p) : stub, Stage=%d, Type=%d, Value =%d\n", This, Stage, Type, Value); */
4428 TRACE("Still a stub, Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
4431 LEAVE_GL();
4433 return;
4436 /*****
4437 * Get / Set Texture Stage States
4438 * TODO: Verify against dx9 definitions
4439 *****/
4440 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4442 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4444 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4446 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4448 /* Reject invalid texture units */
4449 if (Stage >= GL_LIMITS(texture_stages)) {
4450 TRACE("Attempt to access invalid texture rejected\n");
4451 return WINED3DERR_INVALIDCALL;
4454 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4455 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
4456 This->updateStateBlock->textureState[Stage][Type] = Value;
4458 if (This->isRecordingState) {
4459 TRACE("Recording... not performing anything\n");
4460 return WINED3D_OK;
4463 /* Checked after the assignments to allow proper stateblock recording */
4464 if(oldValue == Value) {
4465 TRACE("App is setting the old value over, nothing to do\n");
4466 return WINED3D_OK;
4469 if(Stage > This->stateBlock->lowest_disabled_stage &&
4470 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4471 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4472 * Changes in other states are important on disabled stages too
4474 return WINED3D_OK;
4477 if(Type == WINED3DTSS_COLOROP) {
4478 int i;
4480 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4481 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4482 * they have to be disabled
4484 * The current stage is dirtified below.
4486 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4487 TRACE("Additionally dirtifying stage %d\n", i);
4488 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4490 This->stateBlock->lowest_disabled_stage = Stage;
4491 TRACE("New lowest disabled: %d\n", Stage);
4492 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4493 /* Previously disabled stage enabled. Stages above it may need enabling
4494 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4495 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4497 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4500 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4501 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4502 break;
4504 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4505 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4507 This->stateBlock->lowest_disabled_stage = i;
4508 TRACE("New lowest disabled: %d\n", i);
4510 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4511 /* TODO: Built a stage -> texture unit mapping for register combiners */
4515 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4517 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
4518 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
4519 * will call FindTexUnitMap too.
4521 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4522 IWineD3DDeviceImpl_FindTexUnitMap(This);
4524 return WINED3D_OK;
4527 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4529 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4530 *pValue = This->updateStateBlock->textureState[Stage][Type];
4531 return WINED3D_OK;
4534 /*****
4535 * Get / Set Texture
4536 *****/
4537 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4540 IWineD3DBaseTexture *oldTexture;
4542 oldTexture = This->updateStateBlock->textures[Stage];
4543 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4545 #if 0 /* TODO: check so vertex textures */
4546 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4547 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4548 return WINED3D_OK;
4550 #endif
4552 /* Reject invalid texture units */
4553 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
4554 WARN("Attempt to access invalid texture rejected\n");
4555 return WINED3DERR_INVALIDCALL;
4558 if(pTexture != NULL) {
4559 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4561 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4562 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4563 return WINED3DERR_INVALIDCALL;
4565 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4568 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4569 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4571 This->updateStateBlock->set.textures[Stage] = TRUE;
4572 This->updateStateBlock->changed.textures[Stage] = TRUE;
4573 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4574 This->updateStateBlock->textures[Stage] = pTexture;
4576 /* Handle recording of state blocks */
4577 if (This->isRecordingState) {
4578 TRACE("Recording... not performing anything\n");
4579 return WINED3D_OK;
4582 if(oldTexture == pTexture) {
4583 TRACE("App is setting the same texture again, nothing to do\n");
4584 return WINED3D_OK;
4587 /** NOTE: MSDN says that setTexture increases the reference count,
4588 * and the the application nust set the texture back to null (or have a leaky application),
4589 * This means we should pass the refcount up to the parent
4590 *******************************/
4591 if (NULL != This->updateStateBlock->textures[Stage]) {
4592 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4593 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4595 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4596 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4597 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4598 * so the COLOROP and ALPHAOP have to be dirtified.
4600 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4601 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4603 if(bindCount == 1) {
4604 new->baseTexture.sampler = Stage;
4606 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4610 if (NULL != oldTexture) {
4611 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4612 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4614 IWineD3DBaseTexture_Release(oldTexture);
4615 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4616 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4617 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4620 if(bindCount && old->baseTexture.sampler == Stage) {
4621 int i;
4622 /* Have to do a search for the other sampler(s) where the texture is bound to
4623 * Shouldn't happen as long as apps bind a texture only to one stage
4625 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4626 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
4627 if(This->updateStateBlock->textures[i] == oldTexture) {
4628 old->baseTexture.sampler = i;
4629 break;
4635 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4637 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
4638 * pixel shader is used
4640 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4641 IWineD3DDeviceImpl_FindTexUnitMap(This);
4644 return WINED3D_OK;
4647 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4649 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4651 /* Reject invalid texture units */
4652 if (Stage >= GL_LIMITS(sampler_stages)) {
4653 TRACE("Attempt to access invalid texture rejected\n");
4654 return WINED3DERR_INVALIDCALL;
4656 *ppTexture=This->stateBlock->textures[Stage];
4657 if (*ppTexture)
4658 IWineD3DBaseTexture_AddRef(*ppTexture);
4660 return WINED3D_OK;
4663 /*****
4664 * Get Back Buffer
4665 *****/
4666 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4667 IWineD3DSurface **ppBackBuffer) {
4668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4669 IWineD3DSwapChain *swapChain;
4670 HRESULT hr;
4672 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4674 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4675 if (hr == WINED3D_OK) {
4676 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4677 IWineD3DSwapChain_Release(swapChain);
4678 } else {
4679 *ppBackBuffer = NULL;
4681 return hr;
4684 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4686 WARN("(%p) : stub, calling idirect3d for now\n", This);
4687 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4690 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4692 IWineD3DSwapChain *swapChain;
4693 HRESULT hr;
4695 if(iSwapChain > 0) {
4696 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4697 if (hr == WINED3D_OK) {
4698 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4699 IWineD3DSwapChain_Release(swapChain);
4700 } else {
4701 FIXME("(%p) Error getting display mode\n", This);
4703 } else {
4704 /* Don't read the real display mode,
4705 but return the stored mode instead. X11 can't change the color
4706 depth, and some apps are pretty angry if they SetDisplayMode from
4707 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4709 Also don't relay to the swapchain because with ddraw it's possible
4710 that there isn't a swapchain at all */
4711 pMode->Width = This->ddraw_width;
4712 pMode->Height = This->ddraw_height;
4713 pMode->Format = This->ddraw_format;
4714 pMode->RefreshRate = 0;
4715 hr = WINED3D_OK;
4718 return hr;
4721 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4723 TRACE("(%p)->(%p)\n", This, hWnd);
4725 This->ddraw_window = hWnd;
4726 return WINED3D_OK;
4729 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4731 TRACE("(%p)->(%p)\n", This, hWnd);
4733 *hWnd = This->ddraw_window;
4734 return WINED3D_OK;
4737 /*****
4738 * Stateblock related functions
4739 *****/
4741 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4743 IWineD3DStateBlockImpl *object;
4744 HRESULT temp_result;
4746 TRACE("(%p)\n", This);
4748 if (This->isRecordingState) {
4749 return WINED3DERR_INVALIDCALL;
4752 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4753 if (NULL == object ) {
4754 FIXME("(%p)Error allocating memory for stateblock\n", This);
4755 return E_OUTOFMEMORY;
4757 TRACE("(%p) created object %p\n", This, object);
4758 object->wineD3DDevice= This;
4759 /** FIXME: object->parent = parent; **/
4760 object->parent = NULL;
4761 object->blockType = WINED3DSBT_ALL;
4762 object->ref = 1;
4763 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4765 temp_result = allocate_shader_constants(object);
4766 if (WINED3D_OK != temp_result)
4767 return temp_result;
4769 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4770 This->updateStateBlock = object;
4771 This->isRecordingState = TRUE;
4773 TRACE("(%p) recording stateblock %p\n",This , object);
4774 return WINED3D_OK;
4777 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4780 if (!This->isRecordingState) {
4781 FIXME("(%p) not recording! returning error\n", This);
4782 *ppStateBlock = NULL;
4783 return WINED3DERR_INVALIDCALL;
4786 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4787 This->isRecordingState = FALSE;
4788 This->updateStateBlock = This->stateBlock;
4789 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4790 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4791 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4792 return WINED3D_OK;
4795 /*****
4796 * Scene related functions
4797 *****/
4798 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4799 /* At the moment we have no need for any functionality at the beginning
4800 of a scene */
4801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4802 TRACE("(%p) : stub\n", This);
4803 return WINED3D_OK;
4806 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4808 TRACE("(%p)\n", This);
4809 ENTER_GL();
4810 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4811 glFlush();
4812 checkGLcall("glFlush");
4814 TRACE("End Scene\n");
4815 /* If we're using FBOs this isn't needed */
4816 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && This->render_targets[0] != NULL) {
4818 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
4819 IUnknown *targetContainer = NULL;
4820 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DBaseTexture, (void **)&targetContainer)
4821 || WINED3D_OK == IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DDevice, (void **)&targetContainer)) {
4822 TRACE("(%p) : Texture rendertarget %p\n", This ,This->render_targets[0]);
4823 /** always dirtify for now. we must find a better way to see that surface have been modified
4824 (Modifications should will only occur via draw-primitive, but we do need better locking
4825 switching to render-to-texture should remove the overhead though.
4827 IWineD3DSurface_SetPBufferState(This->render_targets[0], TRUE /* inPBuffer */, FALSE /* inTexture */);
4828 IWineD3DSurface_AddDirtyRect(This->render_targets[0], NULL);
4829 IWineD3DSurface_PreLoad(This->render_targets[0]);
4830 IWineD3DSurface_SetPBufferState(This->render_targets[0], FALSE /* inPBuffer */, FALSE /* inTexture */);
4831 IUnknown_Release(targetContainer);
4834 This->sceneEnded = TRUE;
4835 LEAVE_GL();
4836 return WINED3D_OK;
4839 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4840 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4841 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4843 IWineD3DSwapChain *swapChain = NULL;
4844 int i;
4845 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4847 TRACE("(%p) Presenting the frame\n", This);
4849 for(i = 0 ; i < swapchains ; i ++) {
4851 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4852 TRACE("presentinng chain %d, %p\n", i, swapChain);
4853 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4854 IWineD3DSwapChain_Release(swapChain);
4857 return WINED3D_OK;
4860 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4861 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4864 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4865 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4866 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4867 GLbitfield glMask = 0;
4868 GLboolean old_ztest;
4869 GLfloat old_z_clear_value;
4870 GLint old_stencil_clear_value;
4871 GLfloat old_color_clear_value[4];
4872 unsigned int i;
4873 CONST WINED3DRECT* curRect;
4875 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4876 Count, pRects, Flags, Z, Stencil);
4878 ENTER_GL();
4880 glEnable(GL_SCISSOR_TEST);
4881 checkGLcall("glEnable GL_SCISSOR_TEST");
4883 if (Count > 0 && pRects) {
4884 curRect = pRects;
4885 } else {
4886 curRect = NULL;
4889 /* Only set the values up once, as they are not changing */
4890 if (Flags & WINED3DCLEAR_STENCIL) {
4891 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
4892 glClearStencil(Stencil);
4893 checkGLcall("glClearStencil");
4894 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4895 glStencilMask(0xFFFFFFFF);
4898 if (Flags & WINED3DCLEAR_ZBUFFER) {
4899 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
4900 glDepthMask(GL_TRUE);
4901 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
4902 glClearDepth(Z);
4903 checkGLcall("glClearDepth");
4904 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4907 if (Flags & WINED3DCLEAR_TARGET) {
4908 TRACE("Clearing screen with glClear to color %x\n", Color);
4909 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
4910 glClearColor(D3DCOLOR_R(Color),
4911 D3DCOLOR_G(Color),
4912 D3DCOLOR_B(Color),
4913 D3DCOLOR_A(Color));
4914 checkGLcall("glClearColor");
4916 /* Clear ALL colors! */
4917 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4918 glMask = glMask | GL_COLOR_BUFFER_BIT;
4921 /* Now process each rect in turn */
4922 for (i = 0; i < Count || i == 0; i++) {
4924 if (curRect) {
4925 /* Note gl uses lower left, width/height */
4926 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4927 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
4928 curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4929 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4930 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4931 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4932 checkGLcall("glScissor");
4933 } else {
4934 glScissor(This->stateBlock->viewport.X,
4935 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4936 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4937 This->stateBlock->viewport.Width,
4938 This->stateBlock->viewport.Height);
4939 checkGLcall("glScissor");
4942 /* Clear the selected rectangle (or full screen) */
4943 glClear(glMask);
4944 checkGLcall("glClear");
4946 /* Step to the next rectangle */
4947 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
4950 /* Restore the old values (why..?) */
4951 if (Flags & WINED3DCLEAR_STENCIL) {
4952 glClearStencil(old_stencil_clear_value);
4953 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4955 if (Flags & WINED3DCLEAR_ZBUFFER) {
4956 glDepthMask(old_ztest);
4957 glClearDepth(old_z_clear_value);
4959 if (Flags & WINED3DCLEAR_TARGET) {
4960 glClearColor(old_color_clear_value[0],
4961 old_color_clear_value[1],
4962 old_color_clear_value[2],
4963 old_color_clear_value[3]);
4964 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4965 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4966 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4967 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4970 glDisable(GL_SCISSOR_TEST);
4971 checkGLcall("glDisable");
4972 LEAVE_GL();
4974 return WINED3D_OK;
4977 /*****
4978 * Drawing functions
4979 *****/
4980 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4981 UINT PrimitiveCount) {
4983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4984 This->stateBlock->streamIsUP = FALSE;
4986 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4987 debug_d3dprimitivetype(PrimitiveType),
4988 StartVertex, PrimitiveCount);
4989 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4990 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
4993 return WINED3D_OK;
4996 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4997 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4998 WINED3DPRIMITIVETYPE PrimitiveType,
4999 INT baseVIndex, UINT minIndex,
5000 UINT NumVertices, UINT startIndex, UINT primCount) {
5002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5003 UINT idxStride = 2;
5004 IWineD3DIndexBuffer *pIB;
5005 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5007 pIB = This->stateBlock->pIndexData;
5008 This->stateBlock->streamIsUP = FALSE;
5010 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
5011 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5012 minIndex, NumVertices, startIndex, baseVIndex, primCount);
5014 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5015 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5016 idxStride = 2;
5017 } else {
5018 idxStride = 4;
5021 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
5022 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
5024 return WINED3D_OK;
5027 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5028 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5029 UINT VertexStreamZeroStride) {
5030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5032 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5033 debug_d3dprimitivetype(PrimitiveType),
5034 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5036 /* release the stream source */
5037 if (This->stateBlock->streamSource[0] != NULL) {
5038 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
5041 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5042 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5043 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5044 This->stateBlock->streamIsUP = TRUE;
5046 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5047 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
5049 /* MSDN specifies stream zero settings must be set to NULL */
5050 This->stateBlock->streamStride[0] = 0;
5051 This->stateBlock->streamSource[0] = NULL;
5053 /*stream zero settings set to null at end, as per the msdn */
5054 return WINED3D_OK;
5057 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5058 UINT MinVertexIndex, UINT NumVertices,
5059 UINT PrimitiveCount, CONST void* pIndexData,
5060 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5061 UINT VertexStreamZeroStride) {
5062 int idxStride;
5063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5065 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5066 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5067 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5068 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5070 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5071 idxStride = 2;
5072 } else {
5073 idxStride = 4;
5076 /* release the stream and index data */
5077 if (This->stateBlock->streamSource[0] != NULL) {
5078 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
5080 if (This->stateBlock->pIndexData) {
5081 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
5084 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5085 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5086 This->stateBlock->streamIsUP = TRUE;
5087 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5089 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
5091 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5092 This->stateBlock->streamSource[0] = NULL;
5093 This->stateBlock->streamStride[0] = 0;
5094 This->stateBlock->pIndexData = NULL;
5096 return WINED3D_OK;
5099 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5101 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
5102 return WINED3D_OK;
5104 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5105 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5107 HRESULT hr = WINED3D_OK;
5108 WINED3DRESOURCETYPE sourceType;
5109 WINED3DRESOURCETYPE destinationType;
5110 int i ,levels;
5112 /* TODO: think about moving the code into IWineD3DBaseTexture */
5114 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5116 /* verify that the source and destination textures aren't NULL */
5117 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5118 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5119 This, pSourceTexture, pDestinationTexture);
5120 hr = WINED3DERR_INVALIDCALL;
5123 if (pSourceTexture == pDestinationTexture) {
5124 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5125 This, pSourceTexture, pDestinationTexture);
5126 hr = WINED3DERR_INVALIDCALL;
5128 /* Verify that the source and destination textures are the same type */
5129 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5130 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5132 if (sourceType != destinationType) {
5133 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5134 This);
5135 hr = WINED3DERR_INVALIDCALL;
5138 /* check that both textures have the identical numbers of levels */
5139 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5140 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5141 hr = WINED3DERR_INVALIDCALL;
5144 if (WINED3D_OK == hr) {
5146 /* Make sure that the destination texture is loaded */
5147 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5149 /* Update every surface level of the texture */
5150 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5152 switch (sourceType) {
5153 case WINED3DRTYPE_TEXTURE:
5155 IWineD3DSurface *srcSurface;
5156 IWineD3DSurface *destSurface;
5158 for (i = 0 ; i < levels ; ++i) {
5159 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5160 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5161 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5162 IWineD3DSurface_Release(srcSurface);
5163 IWineD3DSurface_Release(destSurface);
5164 if (WINED3D_OK != hr) {
5165 WARN("(%p) : Call to update surface failed\n", This);
5166 return hr;
5170 break;
5171 case WINED3DRTYPE_CUBETEXTURE:
5173 IWineD3DSurface *srcSurface;
5174 IWineD3DSurface *destSurface;
5175 WINED3DCUBEMAP_FACES faceType;
5177 for (i = 0 ; i < levels ; ++i) {
5178 /* Update each cube face */
5179 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5180 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5181 if (WINED3D_OK != hr) {
5182 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5183 } else {
5184 TRACE("Got srcSurface %p\n", srcSurface);
5186 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5187 if (WINED3D_OK != hr) {
5188 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5189 } else {
5190 TRACE("Got desrSurface %p\n", destSurface);
5192 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5193 IWineD3DSurface_Release(srcSurface);
5194 IWineD3DSurface_Release(destSurface);
5195 if (WINED3D_OK != hr) {
5196 WARN("(%p) : Call to update surface failed\n", This);
5197 return hr;
5202 break;
5203 #if 0 /* TODO: Add support for volume textures */
5204 case WINED3DRTYPE_VOLUMETEXTURE:
5206 IWineD3DVolume srcVolume = NULL;
5207 IWineD3DSurface destVolume = NULL;
5209 for (i = 0 ; i < levels ; ++i) {
5210 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5211 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5212 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
5213 IWineD3DVolume_Release(srcSurface);
5214 IWineD3DVolume_Release(destSurface);
5215 if (WINED3D_OK != hr) {
5216 WARN("(%p) : Call to update volume failed\n", This);
5217 return hr;
5221 break;
5222 #endif
5223 default:
5224 FIXME("(%p) : Unsupported source and destination type\n", This);
5225 hr = WINED3DERR_INVALIDCALL;
5229 return hr;
5232 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
5233 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
5234 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
5235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5237 TRACE("(%p) : stub\n", This);
5238 return WINED3D_OK;
5240 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
5241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5242 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
5243 * NOTE It may be best to move the code into surface to occomplish this
5244 ****************************************/
5246 WINED3DSURFACE_DESC surfaceDesc;
5247 unsigned int surfaceWidth, surfaceHeight;
5248 glDescriptor *targetGlDescription = NULL;
5249 glDescriptor *surfaceGlDescription = NULL;
5250 IWineD3DSwapChainImpl *container = NULL;
5252 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
5253 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
5254 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
5256 surfaceDesc.Width = &surfaceWidth;
5257 surfaceDesc.Height = &surfaceHeight;
5258 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
5259 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
5261 /* Ok, I may need to setup some kind of active swapchain reference on the device */
5262 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
5263 ENTER_GL();
5264 /* TODO: opengl Context switching for swapchains etc... */
5265 if (NULL != container || pRenderTarget == This->render_targets[0] || pRenderTarget == This->depthStencilBuffer) {
5266 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
5267 glReadBuffer(GL_BACK);
5268 vcheckGLcall("glReadBuffer(GL_BACK)");
5269 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->render_targets[0])) {
5270 glReadBuffer(GL_FRONT);
5271 vcheckGLcall("glReadBuffer(GL_FRONT)");
5272 } else if (pRenderTarget == This->depthStencilBuffer) {
5273 FIXME("Reading of depthstencil not yet supported\n");
5276 glReadPixels(0,
5278 surfaceWidth,
5279 surfaceHeight,
5280 surfaceGlDescription->glFormat,
5281 surfaceGlDescription->glType,
5282 (void *)IWineD3DSurface_GetData(pSurface));
5283 vcheckGLcall("glReadPixels(...)");
5284 if(NULL != container ){
5285 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
5287 } else {
5288 IWineD3DBaseTexture *container;
5289 GLenum textureDimensions = GL_TEXTURE_2D;
5291 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
5292 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
5293 IWineD3DBaseTexture_Release(container);
5295 /* TODO: 2D -> Cube surface coppies etc.. */
5296 if (surfaceGlDescription->target != textureDimensions) {
5297 FIXME("(%p) : Texture dimension mismatch\n", This);
5299 glEnable(textureDimensions);
5300 vcheckGLcall("glEnable(GL_TEXTURE_...)");
5301 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
5302 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
5303 vcheckGLcall("glBindTexture");
5304 glGetTexImage(surfaceGlDescription->target,
5305 surfaceGlDescription->level,
5306 surfaceGlDescription->glFormat,
5307 surfaceGlDescription->glType,
5308 (void *)IWineD3DSurface_GetData(pSurface));
5309 glDisable(textureDimensions);
5310 vcheckGLcall("glDisable(GL_TEXTURE_...)");
5313 LEAVE_GL();
5314 return WINED3D_OK;
5317 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5318 IWineD3DSwapChain *swapChain;
5319 HRESULT hr;
5320 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5321 if(hr == WINED3D_OK) {
5322 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5323 IWineD3DSwapChain_Release(swapChain);
5325 return hr;
5328 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5330 /* return a sensible default */
5331 *pNumPasses = 1;
5332 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5333 FIXME("(%p) : stub\n", This);
5334 return WINED3D_OK;
5337 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5339 int j;
5340 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5341 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5342 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5343 return WINED3DERR_INVALIDCALL;
5345 for (j = 0; j < 256; ++j) {
5346 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5347 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5348 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5349 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5351 TRACE("(%p) : returning\n", This);
5352 return WINED3D_OK;
5355 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5357 int j;
5358 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5359 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5360 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5361 return WINED3DERR_INVALIDCALL;
5363 for (j = 0; j < 256; ++j) {
5364 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5365 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5366 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5367 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5369 TRACE("(%p) : returning\n", This);
5370 return WINED3D_OK;
5373 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5375 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5376 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5377 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5378 return WINED3DERR_INVALIDCALL;
5380 /*TODO: stateblocks */
5381 This->currentPalette = PaletteNumber;
5382 TRACE("(%p) : returning\n", This);
5383 return WINED3D_OK;
5386 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5388 if (PaletteNumber == NULL) {
5389 WARN("(%p) : returning Invalid Call\n", This);
5390 return WINED3DERR_INVALIDCALL;
5392 /*TODO: stateblocks */
5393 *PaletteNumber = This->currentPalette;
5394 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5395 return WINED3D_OK;
5398 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5400 static BOOL showFixmes = TRUE;
5401 if (showFixmes) {
5402 FIXME("(%p) : stub\n", This);
5403 showFixmes = FALSE;
5406 This->softwareVertexProcessing = bSoftware;
5407 return WINED3D_OK;
5411 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5413 static BOOL showFixmes = TRUE;
5414 if (showFixmes) {
5415 FIXME("(%p) : stub\n", This);
5416 showFixmes = FALSE;
5418 return This->softwareVertexProcessing;
5422 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5424 IWineD3DSwapChain *swapChain;
5425 HRESULT hr;
5427 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5429 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5430 if(hr == WINED3D_OK){
5431 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5432 IWineD3DSwapChain_Release(swapChain);
5433 }else{
5434 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5436 return hr;
5440 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5442 static BOOL showfixmes = TRUE;
5443 if(nSegments != 0.0f) {
5444 if( showfixmes) {
5445 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5446 showfixmes = FALSE;
5449 return WINED3D_OK;
5452 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5454 static BOOL showfixmes = TRUE;
5455 if( showfixmes) {
5456 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5457 showfixmes = FALSE;
5459 return 0.0f;
5462 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5464 /** TODO: remove casts to IWineD3DSurfaceImpl
5465 * NOTE: move code to surface to accomplish this
5466 ****************************************/
5467 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5468 int srcWidth, srcHeight;
5469 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5470 WINED3DFORMAT destFormat, srcFormat;
5471 UINT destSize;
5472 int destLeft, destTop;
5473 WINED3DPOOL srcPool, destPool;
5474 int offset = 0;
5475 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5476 glDescriptor *glDescription = NULL;
5477 GLenum textureDimensions = GL_TEXTURE_2D;
5478 IWineD3DBaseTexture *baseTexture;
5480 WINED3DSURFACE_DESC winedesc;
5482 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5483 memset(&winedesc, 0, sizeof(winedesc));
5484 winedesc.Width = &srcSurfaceWidth;
5485 winedesc.Height = &srcSurfaceHeight;
5486 winedesc.Pool = &srcPool;
5487 winedesc.Format = &srcFormat;
5489 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5491 winedesc.Width = &destSurfaceWidth;
5492 winedesc.Height = &destSurfaceHeight;
5493 winedesc.Pool = &destPool;
5494 winedesc.Format = &destFormat;
5495 winedesc.Size = &destSize;
5497 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5499 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5500 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5501 return WINED3DERR_INVALIDCALL;
5504 if (destFormat == WINED3DFMT_UNKNOWN) {
5505 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5506 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5508 /* Get the update surface description */
5509 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5512 /* Make sure the surface is loaded and up to date */
5513 IWineD3DSurface_PreLoad(pDestinationSurface);
5515 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5517 ENTER_GL();
5519 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5520 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5521 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
5522 destLeft = pDestPoint ? pDestPoint->x : 0;
5523 destTop = pDestPoint ? pDestPoint->y : 0;
5526 /* This function doesn't support compressed textures
5527 the pitch is just bytesPerPixel * width */
5528 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
5529 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
5530 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
5531 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5533 /* TODO DXT formats */
5535 if(pSourceRect != NULL && pSourceRect->top != 0){
5536 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
5538 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5539 ,This
5540 ,glDescription->level
5541 ,destLeft
5542 ,destTop
5543 ,srcWidth
5544 ,srcHeight
5545 ,glDescription->glFormat
5546 ,glDescription->glType
5547 ,IWineD3DSurface_GetData(pSourceSurface)
5550 /* Sanity check */
5551 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5553 /* need to lock the surface to get the data */
5554 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5557 /* TODO: Cube and volume support */
5558 if(rowoffset != 0){
5559 /* not a whole row so we have to do it a line at a time */
5560 int j;
5562 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5563 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5565 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5567 glTexSubImage2D(glDescription->target
5568 ,glDescription->level
5569 ,destLeft
5571 ,srcWidth
5573 ,glDescription->glFormat
5574 ,glDescription->glType
5575 ,data /* could be quicker using */
5577 data += rowoffset;
5580 } else { /* Full width, so just write out the whole texture */
5582 if (WINED3DFMT_DXT1 == destFormat ||
5583 WINED3DFMT_DXT2 == destFormat ||
5584 WINED3DFMT_DXT3 == destFormat ||
5585 WINED3DFMT_DXT4 == destFormat ||
5586 WINED3DFMT_DXT5 == destFormat) {
5587 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5588 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5589 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5590 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5591 } if (destFormat != srcFormat) {
5592 FIXME("Updating mixed format compressed texture is not curretly support\n");
5593 } else {
5594 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5595 glDescription->level,
5596 glDescription->glFormatInternal,
5597 srcWidth,
5598 srcHeight,
5600 destSize,
5601 IWineD3DSurface_GetData(pSourceSurface));
5603 } else {
5604 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5608 } else {
5609 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
5611 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
5612 to repack the data from pow2Width/Height to expected Width,Height, this makes the
5613 data returned by GetData non-power2 width/height with hardware non-power2
5614 pow2Width/height are set to surface width height, repacking isn't needed so it
5615 doesn't matter which function gets called. */
5616 glTexSubImage2D(glDescription->target
5617 ,glDescription->level
5618 ,destLeft
5619 ,destTop
5620 ,srcWidth
5621 ,srcHeight
5622 ,glDescription->glFormat
5623 ,glDescription->glType
5624 ,IWineD3DSurface_GetData(pSourceSurface)
5626 } else {
5628 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
5629 glTexSubImage2D(glDescription->target
5630 ,glDescription->level
5631 ,destLeft
5632 ,destTop
5633 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
5634 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
5635 ,glDescription->glFormat
5636 ,glDescription->glType
5637 ,IWineD3DSurface_GetData(pSourceSurface)
5643 checkGLcall("glTexSubImage2D");
5644 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
5646 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
5647 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
5648 * surface bigger than it needs to be hmm.. */
5649 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
5650 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
5651 IWineD3DBaseTexture_Release(baseTexture);
5654 glDisable(textureDimensions); /* This needs to be managed better.... */
5655 LEAVE_GL();
5657 return WINED3D_OK;
5660 /* Implementation details at http://developer.nvidia.com/attach/6494
5662 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5663 hmm.. no longer supported use
5664 OpenGL evaluators or tessellate surfaces within your application.
5667 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5668 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5670 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5671 FIXME("(%p) : Stub\n", This);
5672 return WINED3D_OK;
5676 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5677 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5679 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5680 FIXME("(%p) : Stub\n", This);
5681 return WINED3D_OK;
5684 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5686 TRACE("(%p) Handle(%d)\n", This, Handle);
5687 FIXME("(%p) : Stub\n", This);
5688 return WINED3D_OK;
5691 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5693 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5694 DDBLTFX BltFx;
5695 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
5697 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5698 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5699 return WINED3DERR_INVALIDCALL;
5702 /* Just forward this to the DirectDraw blitting engine */
5703 memset(&BltFx, 0, sizeof(BltFx));
5704 BltFx.dwSize = sizeof(BltFx);
5705 BltFx.u5.dwFillColor = color;
5706 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
5709 /* rendertarget and deptth stencil functions */
5710 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5713 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5714 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5715 return WINED3DERR_INVALIDCALL;
5718 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5719 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5720 /* Note inc ref on returned surface */
5721 if(*ppRenderTarget != NULL)
5722 IWineD3DSurface_AddRef(*ppRenderTarget);
5723 return WINED3D_OK;
5726 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5728 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5729 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5730 IWineD3DSwapChainImpl *Swapchain;
5731 HRESULT hr;
5733 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5735 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5736 if(hr != WINED3D_OK) {
5737 ERR("Can't get the swapchain\n");
5738 return hr;
5741 /* Make sure to release the swapchain */
5742 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5744 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5745 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5746 return WINED3DERR_INVALIDCALL;
5748 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5749 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5750 return WINED3DERR_INVALIDCALL;
5753 if(Swapchain->frontBuffer != Front) {
5754 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5756 if(Swapchain->frontBuffer)
5757 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5758 Swapchain->frontBuffer = Front;
5760 if(Swapchain->frontBuffer) {
5761 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5765 if(Back && !Swapchain->backBuffer) {
5766 /* We need memory for the back buffer array - only one back buffer this way */
5767 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5768 if(!Swapchain->backBuffer) {
5769 ERR("Out of memory\n");
5770 return E_OUTOFMEMORY;
5774 if(Swapchain->backBuffer[0] != Back) {
5775 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5776 ENTER_GL();
5777 if(!Swapchain->backBuffer[0]) {
5778 /* GL was told to draw to the front buffer at creation,
5779 * undo that
5781 glDrawBuffer(GL_BACK);
5782 checkGLcall("glDrawBuffer(GL_BACK)");
5783 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5784 Swapchain->presentParms.BackBufferCount = 1;
5785 } else if (!Back) {
5786 /* That makes problems - disable for now */
5787 /* glDrawBuffer(GL_FRONT); */
5788 checkGLcall("glDrawBuffer(GL_FRONT)");
5789 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5790 Swapchain->presentParms.BackBufferCount = 0;
5792 LEAVE_GL();
5794 if(Swapchain->backBuffer[0])
5795 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5796 Swapchain->backBuffer[0] = Back;
5798 if(Swapchain->backBuffer[0]) {
5799 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5800 } else {
5801 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5806 return WINED3D_OK;
5809 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5811 *ppZStencilSurface = This->depthStencilBuffer;
5812 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5814 if(*ppZStencilSurface != NULL) {
5815 /* Note inc ref on returned surface */
5816 IWineD3DSurface_AddRef(*ppZStencilSurface);
5818 return WINED3D_OK;
5821 static void bind_fbo(IWineD3DDevice *iface) {
5822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5824 if (!This->fbo) {
5825 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5826 checkGLcall("glGenFramebuffersEXT()");
5828 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5829 checkGLcall("glBindFramebuffer()");
5832 /* TODO: Handle stencil attachments */
5833 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5835 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5837 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5839 bind_fbo(iface);
5841 if (depth_stencil_impl) {
5842 GLenum texttarget, target;
5844 IWineD3DSurface_PreLoad(depth_stencil);
5845 texttarget = depth_stencil_impl->glDescription.target;
5846 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5848 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5849 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5850 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5851 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5852 glBindTexture(target, 0);
5854 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5855 checkGLcall("glFramebufferTexture2DEXT()");
5856 } else {
5857 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5858 checkGLcall("glFramebufferTexture2DEXT()");
5861 if (!This->render_offscreen) {
5862 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5863 checkGLcall("glBindFramebuffer()");
5867 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5869 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5871 if (idx >= GL_LIMITS(buffers)) {
5872 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5875 bind_fbo(iface);
5877 if (rtimpl) {
5878 GLenum texttarget, target;
5880 IWineD3DSurface_PreLoad(render_target);
5881 texttarget = rtimpl->glDescription.target;
5882 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5884 glBindTexture(target, rtimpl->glDescription.textureName);
5885 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5886 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5887 glBindTexture(target, 0);
5889 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5890 checkGLcall("glFramebufferTexture2DEXT()");
5892 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5893 } else {
5894 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5895 checkGLcall("glFramebufferTexture2DEXT()");
5897 This->draw_buffers[idx] = GL_NONE;
5900 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5901 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5902 checkGLcall("glDrawBuffers()");
5905 if (!This->render_offscreen) {
5906 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5907 checkGLcall("glBindFramebuffer()");
5911 /* internal static helper functions */
5912 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
5913 IWineD3DSurface *RenderSurface);
5915 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5917 HRESULT hr = WINED3D_OK;
5918 WINED3DVIEWPORT viewport;
5920 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5922 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5923 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5924 return WINED3DERR_INVALIDCALL;
5927 /* MSDN says that null disables the render target
5928 but a device must always be associated with a render target
5929 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5931 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5932 for more details
5934 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5935 FIXME("Trying to set render target 0 to NULL\n");
5936 return WINED3DERR_INVALIDCALL;
5938 /* TODO: replace Impl* usage with interface usage */
5939 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5940 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);
5941 return WINED3DERR_INVALIDCALL;
5943 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
5944 * builds, but I think wine counts as a 'debug' build for now.
5945 ******************************/
5946 /* If we are trying to set what we already have, don't bother */
5947 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5948 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5949 } else {
5950 /* Otherwise, set the render target up */
5952 if (!This->sceneEnded) {
5953 IWineD3DDevice_EndScene(iface);
5955 TRACE("clearing renderer\n");
5956 /* IWineD3DDeviceImpl_CleanRender(iface); */
5957 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5958 depending on the renter target implementation being used.
5959 A shared context implementation will share all buffers between all rendertargets (including swapchains),
5960 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5961 stencil buffer and incure an extra memory overhead */
5962 if (RenderTargetIndex == 0) {
5963 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
5964 } else {
5965 hr = WINED3D_OK;
5968 /* Replace the render target */
5969 if (This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5970 This->render_targets[RenderTargetIndex] = pRenderTarget;
5971 if (pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5973 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5974 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5978 if (SUCCEEDED(hr)) {
5979 /* Finally, reset the viewport as the MSDN states. */
5980 /* TODO: Replace impl usage */
5981 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5982 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5983 viewport.X = 0;
5984 viewport.Y = 0;
5985 viewport.MaxZ = 1.0f;
5986 viewport.MinZ = 0.0f;
5987 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5988 } else {
5989 FIXME("Unknown error setting the render target\n");
5991 This->sceneEnded = FALSE;
5992 return hr;
5995 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5997 HRESULT hr = WINED3D_OK;
5998 IWineD3DSurface *tmp;
6000 TRACE("(%p) Swapping z-buffer\n",This);
6002 if (pNewZStencil == This->stencilBufferTarget) {
6003 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6004 } else {
6005 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6006 * depending on the renter target implementation being used.
6007 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6008 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6009 * stencil buffer and incure an extra memory overhead
6010 ******************************************************/
6013 tmp = This->stencilBufferTarget;
6014 This->stencilBufferTarget = pNewZStencil;
6015 /* should we be calling the parent or the wined3d surface? */
6016 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6017 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6018 hr = WINED3D_OK;
6019 /** TODO: glEnable/glDisable on depth/stencil depending on
6020 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
6021 **********************************************************/
6022 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6023 set_depth_stencil_fbo(iface, pNewZStencil);
6027 return hr;
6031 #ifdef GL_VERSION_1_3
6032 /* Internal functions not in DirectX */
6033 /** TODO: move this off to the opengl context manager
6034 *(the swapchain doesn't need to know anything about offscreen rendering!)
6035 ****************************************************/
6037 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
6039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6041 TRACE("(%p), %p\n", This, swapchain);
6043 if (swapchain->win != swapchain->drawable) {
6044 /* Set everything back the way it ws */
6045 swapchain->render_ctx = swapchain->glCtx;
6046 swapchain->drawable = swapchain->win;
6048 return WINED3D_OK;
6051 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
6052 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
6053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6054 int i;
6055 unsigned int width;
6056 unsigned int height;
6057 WINED3DFORMAT format;
6058 WINED3DSURFACE_DESC surfaceDesc;
6059 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6060 surfaceDesc.Width = &width;
6061 surfaceDesc.Height = &height;
6062 surfaceDesc.Format = &format;
6063 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6064 *context = NULL;
6065 /* I need a get width/height function (and should do something with the format) */
6066 for (i = 0; i < CONTEXT_CACHE; ++i) {
6067 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
6068 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
6069 the pSurface can be set to 0 allowing it to be reused from cache **/
6070 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
6071 && (!pbuffer_per_surface || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
6072 *context = &This->contextCache[i];
6073 break;
6075 if (This->contextCache[i].Width == 0) {
6076 This->contextCache[i].pSurface = pSurface;
6077 This->contextCache[i].Width = width;
6078 This->contextCache[i].Height = height;
6079 *context = &This->contextCache[i];
6080 break;
6083 if (i == CONTEXT_CACHE) {
6084 int minUsage = 0x7FFFFFFF; /* MAX_INT */
6085 glContext *dropContext = 0;
6086 for (i = 0; i < CONTEXT_CACHE; i++) {
6087 if (This->contextCache[i].usedcount < minUsage) {
6088 dropContext = &This->contextCache[i];
6089 minUsage = This->contextCache[i].usedcount;
6092 /* clean up the context (this doesn't work for ATI at the moment */
6093 #if 0
6094 glXDestroyContext(swapchain->display, dropContext->context);
6095 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
6096 #endif
6097 FIXME("Leak\n");
6098 dropContext->Width = 0;
6099 dropContext->pSurface = pSurface;
6100 *context = dropContext;
6101 } else {
6102 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
6103 for (i = 0; i < CONTEXT_CACHE; i++) {
6104 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
6108 if (*context != NULL)
6109 return WINED3D_OK;
6110 else
6111 return E_OUTOFMEMORY;
6113 #endif
6115 /* Reapply the device stateblock */
6116 static void device_reapply_stateblock(IWineD3DDeviceImpl* This) {
6118 BOOL oldRecording;
6119 IWineD3DStateBlockImpl *oldUpdateStateBlock;
6120 DWORD i;
6122 /* Disable recording */
6123 oldUpdateStateBlock = This->updateStateBlock;
6124 oldRecording= This->isRecordingState;
6125 This->isRecordingState = FALSE;
6126 This->updateStateBlock = This->stateBlock;
6128 /* Reapply the state block */
6129 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
6131 /* Temporaryily mark all render states dirty to force reapplication
6132 * until the context management for is integrated with the state management
6133 * The same for the pixel shader, sampler states and texture stage states are marked
6134 * dirty my StateBlock::Apply already
6136 for(i = 1; i < WINEHIGHEST_RENDER_STATE; i++) {
6137 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(i));
6139 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
6141 /* Restore recording */
6142 This->isRecordingState = oldRecording;
6143 This->updateStateBlock = oldUpdateStateBlock;
6146 /* Set offscreen rendering. When rendering offscreen the surface will be
6147 * rendered upside down to compensate for the fact that D3D texture coordinates
6148 * are flipped compared to GL texture coordinates. The cullmode is affected by
6149 * this, so it must be updated. To update the cullmode stateblock recording has
6150 * to be temporarily disabled. The new state management code will hopefully
6151 * make this unnecessary */
6152 static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture) {
6154 BOOL oldRecording;
6155 IWineD3DStateBlockImpl *oldUpdateStateBlock;
6157 /* Nothing to update, return. */
6158 if (This->render_offscreen == isTexture) return;
6160 /* Disable recording */
6161 oldUpdateStateBlock = This->updateStateBlock;
6162 oldRecording= This->isRecordingState;
6163 This->isRecordingState = FALSE;
6164 This->updateStateBlock = This->stateBlock;
6166 This->render_offscreen = isTexture;
6167 if (This->depth_copy_state != WINED3D_DCS_NO_COPY) {
6168 This->depth_copy_state = WINED3D_DCS_COPY;
6170 This->last_was_rhw = FALSE;
6171 This->proj_valid = FALSE;
6172 IWineD3DDeviceImpl_MarkStateDirty(This, WINED3DRS_CULLMODE);
6174 /* Restore recording */
6175 This->isRecordingState = oldRecording;
6176 This->updateStateBlock = oldUpdateStateBlock;
6179 /* Returns an array of compatible FBconfig(s).
6180 * The array must be freed with XFree. Requires ENTER_GL() */
6182 static GLXFBConfig* device_find_fbconfigs(
6183 IWineD3DDeviceImpl* This,
6184 IWineD3DSwapChainImpl* implicitSwapchainImpl,
6185 IWineD3DSurface* RenderSurface) {
6187 GLXFBConfig* cfgs = NULL;
6188 int nCfgs = 0;
6189 int attribs[256];
6190 int nAttribs = 0;
6192 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
6193 WINED3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
6194 WINED3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
6196 /**TODO:
6197 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
6198 it StencilSurface != NULL && zBufferTarget == NULL switch it on
6201 #define PUSH1(att) attribs[nAttribs++] = (att);
6202 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
6204 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
6206 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
6207 PUSH2(GLX_X_RENDERABLE, TRUE);
6208 PUSH2(GLX_DOUBLEBUFFER, TRUE);
6209 TRACE("calling makeglcfg\n");
6210 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
6211 PUSH1(None);
6212 TRACE("calling chooseFGConfig\n");
6213 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
6214 DefaultScreen(implicitSwapchainImpl->display),
6215 attribs, &nCfgs);
6216 if (cfgs == NULL) {
6217 /* OK we didn't find the exact config, so use any reasonable match */
6218 /* TODO: fill in the 'requested' and 'current' depths, and make sure that's
6219 why we failed. */
6220 static BOOL show_message = TRUE;
6221 if (show_message) {
6222 ERR("Failed to find exact match, finding alternative but you may "
6223 "suffer performance issues, try changing xfree's depth to match the requested depth\n");
6224 show_message = FALSE;
6226 nAttribs = 0;
6227 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
6228 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
6229 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
6230 PUSH2(GLX_DOUBLEBUFFER, FALSE);
6231 TRACE("calling makeglcfg\n");
6232 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
6233 PUSH1(None);
6234 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
6235 DefaultScreen(implicitSwapchainImpl->display),
6236 attribs, &nCfgs);
6239 if (cfgs == NULL) {
6240 ERR("Could not get a valid FBConfig for (%u,%s)/(%u,%s)\n",
6241 BackBufferFormat, debug_d3dformat(BackBufferFormat),
6242 StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
6243 } else {
6244 #ifdef EXTRA_TRACES
6245 int i;
6246 for (i = 0; i < nCfgs; ++i) {
6247 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
6248 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
6249 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
6251 if (NULL != This->renderTarget) {
6252 glFlush();
6253 vcheckGLcall("glFlush");
6254 /** This is only useful if the old render target was a swapchain,
6255 * we need to supercede this with a function that displays
6256 * the current buffer on the screen. This is easy to do in glx1.3 but
6257 * we need to do copy-write pixels in glx 1.2.
6258 ************************************************/
6259 glXSwapBuffers(implicitSwapChainImpl->display,
6260 implicitSwapChainImpl->drawable);
6261 printf("Hit Enter to get next frame ...\n");
6262 getchar();
6264 #endif
6266 #undef PUSH1
6267 #undef PUSH2
6269 return cfgs;
6272 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
6273 * the functionality needs splitting up so that we don't do more than we should do.
6274 * this only seems to impact performance a little.
6275 ******************************/
6276 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
6277 IWineD3DSurface *RenderSurface) {
6280 * Currently only active for GLX >= 1.3
6281 * for others versions we'll have to use GLXPixmaps
6283 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
6284 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
6285 * so only check OpenGL version
6286 * ..........................
6287 * I don't believe that it is a problem with NVidia headers,
6288 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
6289 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
6290 * ATI Note:
6291 * Your application will report GLX version 1.2 on glXQueryVersion.
6292 * However, it is safe to call the GLX 1.3 functions as described below.
6294 #if defined(GL_VERSION_1_3)
6296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6297 GLXFBConfig* cfgs = NULL;
6298 IWineD3DSwapChain *currentSwapchain;
6299 IWineD3DSwapChainImpl *currentSwapchainImpl;
6300 IWineD3DSwapChain *implicitSwapchain;
6301 IWineD3DSwapChainImpl *implicitSwapchainImpl;
6302 IWineD3DSwapChain *renderSurfaceSwapchain;
6303 IWineD3DSwapChainImpl *renderSurfaceSwapchainImpl;
6305 /* Obtain a reference to the device implicit swapchain,
6306 * the swapchain of the current render target,
6307 * and the swapchain of the new render target.
6308 * Fallback to device implicit swapchain if the current render target doesn't have one */
6309 IWineD3DDevice_GetSwapChain(iface, 0, &implicitSwapchain);
6310 IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void**) &renderSurfaceSwapchain);
6311 IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DSwapChain, (void **)&currentSwapchain);
6312 if (currentSwapchain == NULL)
6313 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
6315 currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
6316 implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
6317 renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;
6319 ENTER_GL();
6322 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
6323 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
6324 **********************************************************************/
6325 if (renderSurfaceSwapchain != NULL) {
6327 /* We also need to make sure that the lights &co are also in the context of the swapchains */
6328 /* FIXME: If the render target gets sent to the frontBuffer, should we be presenting it raw? */
6329 TRACE("making swapchain active\n");
6330 if (RenderSurface != This->render_targets[0]) {
6331 BOOL backbuf = FALSE;
6332 int i;
6334 for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
6335 if(RenderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
6336 backbuf = TRUE;
6337 break;
6341 if (backbuf) {
6342 } else {
6343 /* This could be flagged so that some operations work directly with the front buffer */
6344 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
6346 if (glXMakeCurrent(renderSurfaceSwapchainImpl->display,
6347 renderSurfaceSwapchainImpl->win,
6348 renderSurfaceSwapchainImpl->glCtx) == False) {
6350 TRACE("Error in setting current context: context %p drawable %ld !\n",
6351 implicitSwapchainImpl->glCtx, implicitSwapchainImpl->win);
6353 checkGLcall("glXMakeContextCurrent");
6355 /* Clean up the old context */
6356 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
6358 /* Reapply the stateblock, and set the device not to render to texture */
6359 device_reapply_stateblock(This);
6360 device_render_to_texture(This, FALSE);
6363 /* Offscreen rendering: PBuffers (currently disabled).
6364 * Also note that this path is never reached if FBOs are supported */
6365 } else if (wined3d_settings.offscreen_rendering_mode == ORM_PBUFFER &&
6366 (cfgs = device_find_fbconfigs(This, implicitSwapchainImpl, RenderSurface)) != NULL) {
6368 /** ********************************************************************
6369 * This is a quickly hacked out implementation of offscreen textures.
6370 * It will work in most cases but there may be problems if the client
6371 * modifies the texture directly, or expects the contents of the rendertarget
6372 * to be persistent.
6374 * There are some real speed vs compatibility issues here:
6375 * we should really use a new context for every texture, but that eats ram.
6376 * we should also be restoring the texture to the pbuffer but that eats CPU
6377 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
6378 * but if this means reusing the display backbuffer then we need to make sure that
6379 * states are correctly preserved.
6380 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
6381 * and gain a good performance increase at the cost of compatibility.
6382 * I would suggest that, when this is the case, a user configurable flag be made
6383 * available, allowing the user to choose the best emulated experience for them.
6384 *********************************************************************/
6386 XVisualInfo *visinfo;
6387 glContext *newContext;
6389 /* Here were using a shared context model */
6390 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
6391 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
6394 /* If the context doesn't exist then create a new one */
6395 /* TODO: This should really be part of findGlContext */
6396 if (NULL == newContext->context) {
6398 int attribs[256];
6399 int nAttribs = 0;
6401 TRACE("making new buffer\n");
6402 attribs[nAttribs++] = GLX_PBUFFER_WIDTH;
6403 attribs[nAttribs++] = newContext->Width;
6404 attribs[nAttribs++] = GLX_PBUFFER_HEIGHT;
6405 attribs[nAttribs++] = newContext->Height;
6406 attribs[nAttribs++] = None;
6408 newContext->drawable = glXCreatePbuffer(implicitSwapchainImpl->display, cfgs[0], attribs);
6410 /** ****************************************
6411 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
6412 *they note:
6413 * In future releases, we may provide the calls glXCreateNewContext,
6414 * glXQueryDrawable and glXMakeContextCurrent.
6415 * so until then we have to use glXGetVisualFromFBConfig &co..
6416 ********************************************/
6418 visinfo = glXGetVisualFromFBConfig(implicitSwapchainImpl->display, cfgs[0]);
6419 if (!visinfo) {
6420 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
6421 } else {
6422 newContext->context = glXCreateContext(
6423 implicitSwapchainImpl->display, visinfo,
6424 implicitSwapchainImpl->glCtx, GL_TRUE);
6426 XFree(visinfo);
6429 if (NULL == newContext || NULL == newContext->context) {
6430 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
6431 } else {
6432 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
6433 if (glXMakeCurrent(implicitSwapchainImpl->display,
6434 newContext->drawable, newContext->context) == False) {
6436 TRACE("Error in setting current context: context %p drawable %ld\n",
6437 newContext->context, newContext->drawable);
6439 checkGLcall("glXMakeContextCurrent");
6441 /* Clean up the old context */
6442 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
6444 /* Reapply stateblock, and set device to render to a texture */
6445 device_reapply_stateblock(This);
6446 device_render_to_texture(This, TRUE);
6448 /* Set the current context of the swapchain to the new context */
6449 implicitSwapchainImpl->drawable = newContext->drawable;
6450 implicitSwapchainImpl->render_ctx = newContext->context;
6452 } else {
6453 /* Same context, but update render_offscreen and cull mode */
6454 device_render_to_texture(This, TRUE);
6457 if (cfgs != NULL) XFree(cfgs);
6458 if (implicitSwapchain != NULL) IWineD3DSwapChain_Release(implicitSwapchain);
6459 if (currentSwapchain != NULL) IWineD3DSwapChain_Release(currentSwapchain);
6460 if (renderSurfaceSwapchain != NULL) IWineD3DSwapChain_Release(renderSurfaceSwapchain);
6461 LEAVE_GL();
6462 #endif
6463 return WINED3D_OK;
6466 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6467 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6469 /* TODO: the use of Impl is deprecated. */
6470 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6472 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6474 /* some basic validation checks */
6475 if(This->cursorTexture) {
6476 ENTER_GL();
6477 glDeleteTextures(1, &This->cursorTexture);
6478 LEAVE_GL();
6479 This->cursorTexture = 0;
6482 if(pCursorBitmap) {
6483 /* MSDN: Cursor must be A8R8G8B8 */
6484 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6485 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6486 return WINED3DERR_INVALIDCALL;
6489 /* MSDN: Cursor must be smaller than the display mode */
6490 if(pSur->currentDesc.Width > This->ddraw_width ||
6491 pSur->currentDesc.Height > This->ddraw_height) {
6492 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);
6493 return WINED3DERR_INVALIDCALL;
6496 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6497 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
6498 * Texture and Blitting code to draw the cursor
6500 pSur->Flags |= SFLAG_FORCELOAD;
6501 IWineD3DSurface_PreLoad(pCursorBitmap);
6502 pSur->Flags &= ~SFLAG_FORCELOAD;
6503 /* Do not store the surface's pointer because the application may release
6504 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
6505 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
6507 This->cursorTexture = pSur->glDescription.textureName;
6508 This->cursorWidth = pSur->currentDesc.Width;
6509 This->cursorHeight = pSur->currentDesc.Height;
6510 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
6513 This->xHotSpot = XHotSpot;
6514 This->yHotSpot = YHotSpot;
6515 return WINED3D_OK;
6518 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6520 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6522 This->xScreenSpace = XScreenSpace;
6523 This->yScreenSpace = YScreenSpace;
6525 return;
6529 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6531 BOOL oldVisible = This->bCursorVisible;
6532 TRACE("(%p) : visible(%d)\n", This, bShow);
6534 if(This->cursorTexture)
6535 This->bCursorVisible = bShow;
6537 return oldVisible;
6540 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6542 TRACE("(%p) : state (%u)\n", This, This->state);
6543 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6544 switch (This->state) {
6545 case WINED3D_OK:
6546 return WINED3D_OK;
6547 case WINED3DERR_DEVICELOST:
6549 ResourceList *resourceList = This->resources;
6550 while (NULL != resourceList) {
6551 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6552 return WINED3DERR_DEVICENOTRESET;
6553 resourceList = resourceList->next;
6555 return WINED3DERR_DEVICELOST;
6557 case WINED3DERR_DRIVERINTERNALERROR:
6558 return WINED3DERR_DRIVERINTERNALERROR;
6561 /* Unknown state */
6562 return WINED3DERR_DRIVERINTERNALERROR;
6566 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6568 /** FIXME: Resource tracking needs to be done,
6569 * The closes we can do to this is set the priorities of all managed textures low
6570 * and then reset them.
6571 ***********************************************************/
6572 FIXME("(%p) : stub\n", This);
6573 return WINED3D_OK;
6576 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6577 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6578 if(surface->Flags & SFLAG_DIBSECTION) {
6579 /* Release the DC */
6580 SelectObject(surface->hDC, surface->dib.holdbitmap);
6581 DeleteDC(surface->hDC);
6582 /* Release the DIB section */
6583 DeleteObject(surface->dib.DIBsection);
6584 surface->dib.bitmap_data = NULL;
6585 surface->resource.allocatedMemory = NULL;
6586 surface->Flags &= ~SFLAG_DIBSECTION;
6588 surface->currentDesc.Width = *pPresentationParameters->BackBufferWidth;
6589 surface->currentDesc.Height = *pPresentationParameters->BackBufferHeight;
6590 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
6591 surface->pow2Width = *pPresentationParameters->BackBufferWidth;
6592 surface->pow2Height = *pPresentationParameters->BackBufferHeight;
6593 } else {
6594 surface->pow2Width = surface->pow2Height = 1;
6595 while (surface->pow2Width < *pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6596 while (surface->pow2Height < *pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6598 if(surface->glDescription.textureName) {
6599 ENTER_GL();
6600 glDeleteTextures(1, &surface->glDescription.textureName);
6601 LEAVE_GL();
6602 surface->glDescription.textureName = 0;
6604 if(surface->pow2Width != *pPresentationParameters->BackBufferWidth ||
6605 surface->pow2Height != *pPresentationParameters->BackBufferHeight) {
6606 surface->Flags |= SFLAG_NONPOW2;
6607 } else {
6608 surface->Flags &= ~SFLAG_NONPOW2;
6610 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6611 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6614 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6616 IWineD3DSwapChainImpl *swapchain;
6617 HRESULT hr;
6618 BOOL DisplayModeChanged = FALSE;
6619 WINED3DDISPLAYMODE mode;
6620 TRACE("(%p)\n", This);
6622 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6623 if(FAILED(hr)) {
6624 ERR("Failed to get the first implicit swapchain\n");
6625 return hr;
6628 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6629 * on an existing gl context, so there's no real need for recreation.
6631 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6633 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6635 TRACE("New params:\n");
6636 TRACE("BackBufferWidth = %d\n", *pPresentationParameters->BackBufferWidth);
6637 TRACE("BackBufferHeight = %d\n", *pPresentationParameters->BackBufferHeight);
6638 TRACE("BackBufferFormat = %s\n", debug_d3dformat(*pPresentationParameters->BackBufferFormat));
6639 TRACE("BackBufferCount = %d\n", *pPresentationParameters->BackBufferCount);
6640 TRACE("MultiSampleType = %d\n", *pPresentationParameters->MultiSampleType);
6641 TRACE("MultiSampleQuality = %d\n", *pPresentationParameters->MultiSampleQuality);
6642 TRACE("SwapEffect = %d\n", *pPresentationParameters->SwapEffect);
6643 TRACE("hDeviceWindow = %p\n", *pPresentationParameters->hDeviceWindow);
6644 TRACE("Windowed = %s\n", *pPresentationParameters->Windowed ? "true" : "false");
6645 TRACE("EnableAutoDepthStencil = %s\n", *pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6646 TRACE("Flags = %08x\n", *pPresentationParameters->Flags);
6647 TRACE("FullScreen_RefreshRateInHz = %d\n", *pPresentationParameters->FullScreen_RefreshRateInHz);
6648 TRACE("PresentationInterval = %d\n", *pPresentationParameters->PresentationInterval);
6650 /* No special treatment of these parameters. Just store them */
6651 swapchain->presentParms.SwapEffect = *pPresentationParameters->SwapEffect;
6652 swapchain->presentParms.Flags = *pPresentationParameters->Flags;
6653 swapchain->presentParms.PresentationInterval = *pPresentationParameters->PresentationInterval;
6654 swapchain->presentParms.FullScreen_RefreshRateInHz = *pPresentationParameters->FullScreen_RefreshRateInHz;
6656 /* What to do about these? */
6657 if(*pPresentationParameters->BackBufferCount != 0 &&
6658 *pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6659 ERR("Cannot change the back buffer count yet\n");
6661 if(*pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6662 *pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6663 ERR("Cannot change the back buffer format yet\n");
6665 if(*pPresentationParameters->hDeviceWindow != NULL &&
6666 *pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6667 ERR("Cannot change the device window yet\n");
6669 if(*pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6670 ERR("What do do about a changed auto depth stencil parameter?\n");
6673 if(*pPresentationParameters->Windowed) {
6674 mode.Width = swapchain->orig_width;
6675 mode.Height = swapchain->orig_height;
6676 mode.RefreshRate = 0;
6677 mode.Format = swapchain->presentParms.BackBufferFormat;
6678 } else {
6679 mode.Width = *pPresentationParameters->BackBufferWidth;
6680 mode.Height = *pPresentationParameters->BackBufferHeight;
6681 mode.RefreshRate = *pPresentationParameters->FullScreen_RefreshRateInHz;
6682 mode.Format = swapchain->presentParms.BackBufferFormat;
6685 /* Should Width == 800 && Height == 0 set 800x600? */
6686 if(*pPresentationParameters->BackBufferWidth != 0 && *pPresentationParameters->BackBufferHeight != 0 &&
6687 (*pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6688 *pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6690 WINED3DVIEWPORT vp;
6691 int i;
6693 vp.X = 0;
6694 vp.Y = 0;
6695 vp.Width = *pPresentationParameters->BackBufferWidth;
6696 vp.Height = *pPresentationParameters->BackBufferHeight;
6697 vp.MinZ = 0;
6698 vp.MaxZ = 1;
6700 if(!*pPresentationParameters->Windowed) {
6701 DisplayModeChanged = TRUE;
6703 swapchain->presentParms.BackBufferWidth = *pPresentationParameters->BackBufferWidth;
6704 swapchain->presentParms.BackBufferHeight = *pPresentationParameters->BackBufferHeight;
6706 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6707 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6708 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6711 /* Now set the new viewport */
6712 IWineD3DDevice_SetViewport(iface, &vp);
6715 if((*pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6716 (swapchain->presentParms.Windowed && !*pPresentationParameters->Windowed) ||
6717 DisplayModeChanged) {
6718 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6721 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6722 return WINED3D_OK;
6725 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6727 /** FIXME: always true at the moment **/
6728 if(!bEnableDialogs) {
6729 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6731 return WINED3D_OK;
6735 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6737 TRACE("(%p) : pParameters %p\n", This, pParameters);
6739 *pParameters = This->createParms;
6740 return WINED3D_OK;
6743 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6744 IWineD3DSwapChain *swapchain;
6745 HRESULT hrc = WINED3D_OK;
6747 TRACE("Relaying to swapchain\n");
6749 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6750 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6751 IWineD3DSwapChain_Release(swapchain);
6753 return;
6756 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6757 IWineD3DSwapChain *swapchain;
6758 HRESULT hrc = WINED3D_OK;
6760 TRACE("Relaying to swapchain\n");
6762 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6763 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6764 IWineD3DSwapChain_Release(swapchain);
6766 return;
6770 /** ********************************************************
6771 * Notification functions
6772 ** ********************************************************/
6773 /** This function must be called in the release of a resource when ref == 0,
6774 * the contents of resource must still be correct,
6775 * any handels to other resource held by the caller must be closed
6776 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6777 *****************************************************/
6778 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6780 ResourceList* resourceList;
6782 TRACE("(%p) : resource %p\n", This, resource);
6783 #if 0
6784 EnterCriticalSection(&resourceStoreCriticalSection);
6785 #endif
6786 /* add a new texture to the frot of the linked list */
6787 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6788 resourceList->resource = resource;
6790 /* Get the old head */
6791 resourceList->next = This->resources;
6793 This->resources = resourceList;
6794 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6796 #if 0
6797 LeaveCriticalSection(&resourceStoreCriticalSection);
6798 #endif
6799 return;
6802 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6804 ResourceList* resourceList = NULL;
6805 ResourceList* previousResourceList = NULL;
6807 TRACE("(%p) : resource %p\n", This, resource);
6809 #if 0
6810 EnterCriticalSection(&resourceStoreCriticalSection);
6811 #endif
6812 resourceList = This->resources;
6814 while (resourceList != NULL) {
6815 if(resourceList->resource == resource) break;
6816 previousResourceList = resourceList;
6817 resourceList = resourceList->next;
6820 if (resourceList == NULL) {
6821 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6822 #if 0
6823 LeaveCriticalSection(&resourceStoreCriticalSection);
6824 #endif
6825 return;
6826 } else {
6827 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6829 /* make sure we don't leave a hole in the list */
6830 if (previousResourceList != NULL) {
6831 previousResourceList->next = resourceList->next;
6832 } else {
6833 This->resources = resourceList->next;
6836 #if 0
6837 LeaveCriticalSection(&resourceStoreCriticalSection);
6838 #endif
6839 return;
6843 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6845 int counter;
6847 TRACE("(%p) : resource %p\n", This, resource);
6848 switch(IWineD3DResource_GetType(resource)){
6849 case WINED3DRTYPE_SURFACE:
6850 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6851 break;
6852 case WINED3DRTYPE_TEXTURE:
6853 case WINED3DRTYPE_CUBETEXTURE:
6854 case WINED3DRTYPE_VOLUMETEXTURE:
6855 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
6856 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6857 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6858 This->stateBlock->textures[counter] = NULL;
6860 if (This->updateStateBlock != This->stateBlock ){
6861 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6862 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6863 This->updateStateBlock->textures[counter] = NULL;
6867 break;
6868 case WINED3DRTYPE_VOLUME:
6869 /* TODO: nothing really? */
6870 break;
6871 case WINED3DRTYPE_VERTEXBUFFER:
6872 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6874 int streamNumber;
6875 TRACE("Cleaning up stream pointers\n");
6877 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6878 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6879 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6881 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6882 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6883 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6884 This->updateStateBlock->streamSource[streamNumber] = 0;
6885 /* Set changed flag? */
6888 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) */
6889 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6890 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6891 This->stateBlock->streamSource[streamNumber] = 0;
6894 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6895 else { /* This shouldn't happen */
6896 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6898 #endif
6902 break;
6903 case WINED3DRTYPE_INDEXBUFFER:
6904 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6905 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6906 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6907 This->updateStateBlock->pIndexData = NULL;
6910 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6911 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6912 This->stateBlock->pIndexData = NULL;
6916 break;
6917 default:
6918 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6919 break;
6923 /* Remove the resoruce from the resourceStore */
6924 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6926 TRACE("Resource released\n");
6930 /**********************************************************
6931 * IWineD3DDevice VTbl follows
6932 **********************************************************/
6934 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6936 /*** IUnknown methods ***/
6937 IWineD3DDeviceImpl_QueryInterface,
6938 IWineD3DDeviceImpl_AddRef,
6939 IWineD3DDeviceImpl_Release,
6940 /*** IWineD3DDevice methods ***/
6941 IWineD3DDeviceImpl_GetParent,
6942 /*** Creation methods**/
6943 IWineD3DDeviceImpl_CreateVertexBuffer,
6944 IWineD3DDeviceImpl_CreateIndexBuffer,
6945 IWineD3DDeviceImpl_CreateStateBlock,
6946 IWineD3DDeviceImpl_CreateSurface,
6947 IWineD3DDeviceImpl_CreateTexture,
6948 IWineD3DDeviceImpl_CreateVolumeTexture,
6949 IWineD3DDeviceImpl_CreateVolume,
6950 IWineD3DDeviceImpl_CreateCubeTexture,
6951 IWineD3DDeviceImpl_CreateQuery,
6952 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6953 IWineD3DDeviceImpl_CreateVertexDeclaration,
6954 IWineD3DDeviceImpl_CreateVertexShader,
6955 IWineD3DDeviceImpl_CreatePixelShader,
6956 IWineD3DDeviceImpl_CreatePalette,
6957 /*** Odd functions **/
6958 IWineD3DDeviceImpl_Init3D,
6959 IWineD3DDeviceImpl_Uninit3D,
6960 IWineD3DDeviceImpl_SetFullscreen,
6961 IWineD3DDeviceImpl_EnumDisplayModes,
6962 IWineD3DDeviceImpl_EvictManagedResources,
6963 IWineD3DDeviceImpl_GetAvailableTextureMem,
6964 IWineD3DDeviceImpl_GetBackBuffer,
6965 IWineD3DDeviceImpl_GetCreationParameters,
6966 IWineD3DDeviceImpl_GetDeviceCaps,
6967 IWineD3DDeviceImpl_GetDirect3D,
6968 IWineD3DDeviceImpl_GetDisplayMode,
6969 IWineD3DDeviceImpl_SetDisplayMode,
6970 IWineD3DDeviceImpl_GetHWND,
6971 IWineD3DDeviceImpl_SetHWND,
6972 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6973 IWineD3DDeviceImpl_GetRasterStatus,
6974 IWineD3DDeviceImpl_GetSwapChain,
6975 IWineD3DDeviceImpl_Reset,
6976 IWineD3DDeviceImpl_SetDialogBoxMode,
6977 IWineD3DDeviceImpl_SetCursorProperties,
6978 IWineD3DDeviceImpl_SetCursorPosition,
6979 IWineD3DDeviceImpl_ShowCursor,
6980 IWineD3DDeviceImpl_TestCooperativeLevel,
6981 /*** Getters and setters **/
6982 IWineD3DDeviceImpl_SetClipPlane,
6983 IWineD3DDeviceImpl_GetClipPlane,
6984 IWineD3DDeviceImpl_SetClipStatus,
6985 IWineD3DDeviceImpl_GetClipStatus,
6986 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6987 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6988 IWineD3DDeviceImpl_SetDepthStencilSurface,
6989 IWineD3DDeviceImpl_GetDepthStencilSurface,
6990 IWineD3DDeviceImpl_SetFVF,
6991 IWineD3DDeviceImpl_GetFVF,
6992 IWineD3DDeviceImpl_SetGammaRamp,
6993 IWineD3DDeviceImpl_GetGammaRamp,
6994 IWineD3DDeviceImpl_SetIndices,
6995 IWineD3DDeviceImpl_GetIndices,
6996 IWineD3DDeviceImpl_SetLight,
6997 IWineD3DDeviceImpl_GetLight,
6998 IWineD3DDeviceImpl_SetLightEnable,
6999 IWineD3DDeviceImpl_GetLightEnable,
7000 IWineD3DDeviceImpl_SetMaterial,
7001 IWineD3DDeviceImpl_GetMaterial,
7002 IWineD3DDeviceImpl_SetNPatchMode,
7003 IWineD3DDeviceImpl_GetNPatchMode,
7004 IWineD3DDeviceImpl_SetPaletteEntries,
7005 IWineD3DDeviceImpl_GetPaletteEntries,
7006 IWineD3DDeviceImpl_SetPixelShader,
7007 IWineD3DDeviceImpl_GetPixelShader,
7008 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7009 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7010 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7011 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7012 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7013 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7014 IWineD3DDeviceImpl_SetRenderState,
7015 IWineD3DDeviceImpl_GetRenderState,
7016 IWineD3DDeviceImpl_SetRenderTarget,
7017 IWineD3DDeviceImpl_GetRenderTarget,
7018 IWineD3DDeviceImpl_SetFrontBackBuffers,
7019 IWineD3DDeviceImpl_SetSamplerState,
7020 IWineD3DDeviceImpl_GetSamplerState,
7021 IWineD3DDeviceImpl_SetScissorRect,
7022 IWineD3DDeviceImpl_GetScissorRect,
7023 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7024 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7025 IWineD3DDeviceImpl_SetStreamSource,
7026 IWineD3DDeviceImpl_GetStreamSource,
7027 IWineD3DDeviceImpl_SetStreamSourceFreq,
7028 IWineD3DDeviceImpl_GetStreamSourceFreq,
7029 IWineD3DDeviceImpl_SetTexture,
7030 IWineD3DDeviceImpl_GetTexture,
7031 IWineD3DDeviceImpl_SetTextureStageState,
7032 IWineD3DDeviceImpl_GetTextureStageState,
7033 IWineD3DDeviceImpl_SetTransform,
7034 IWineD3DDeviceImpl_GetTransform,
7035 IWineD3DDeviceImpl_SetVertexDeclaration,
7036 IWineD3DDeviceImpl_GetVertexDeclaration,
7037 IWineD3DDeviceImpl_SetVertexShader,
7038 IWineD3DDeviceImpl_GetVertexShader,
7039 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7040 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7041 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7042 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7043 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7044 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7045 IWineD3DDeviceImpl_SetViewport,
7046 IWineD3DDeviceImpl_GetViewport,
7047 IWineD3DDeviceImpl_MultiplyTransform,
7048 IWineD3DDeviceImpl_ValidateDevice,
7049 IWineD3DDeviceImpl_ProcessVertices,
7050 /*** State block ***/
7051 IWineD3DDeviceImpl_BeginStateBlock,
7052 IWineD3DDeviceImpl_EndStateBlock,
7053 /*** Scene management ***/
7054 IWineD3DDeviceImpl_BeginScene,
7055 IWineD3DDeviceImpl_EndScene,
7056 IWineD3DDeviceImpl_Present,
7057 IWineD3DDeviceImpl_Clear,
7058 /*** Drawing ***/
7059 IWineD3DDeviceImpl_DrawPrimitive,
7060 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7061 IWineD3DDeviceImpl_DrawPrimitiveUP,
7062 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7063 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7064 IWineD3DDeviceImpl_DrawRectPatch,
7065 IWineD3DDeviceImpl_DrawTriPatch,
7066 IWineD3DDeviceImpl_DeletePatch,
7067 IWineD3DDeviceImpl_ColorFill,
7068 IWineD3DDeviceImpl_UpdateTexture,
7069 IWineD3DDeviceImpl_UpdateSurface,
7070 IWineD3DDeviceImpl_StretchRect,
7071 IWineD3DDeviceImpl_GetRenderTargetData,
7072 IWineD3DDeviceImpl_GetFrontBufferData,
7073 /*** Internal use IWineD3DDevice methods ***/
7074 IWineD3DDeviceImpl_SetupTextureStates,
7075 /*** object tracking ***/
7076 IWineD3DDeviceImpl_ResourceReleased
7080 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7081 WINED3DRS_ALPHABLENDENABLE ,
7082 WINED3DRS_ALPHAFUNC ,
7083 WINED3DRS_ALPHAREF ,
7084 WINED3DRS_ALPHATESTENABLE ,
7085 WINED3DRS_BLENDOP ,
7086 WINED3DRS_COLORWRITEENABLE ,
7087 WINED3DRS_DESTBLEND ,
7088 WINED3DRS_DITHERENABLE ,
7089 WINED3DRS_FILLMODE ,
7090 WINED3DRS_FOGDENSITY ,
7091 WINED3DRS_FOGEND ,
7092 WINED3DRS_FOGSTART ,
7093 WINED3DRS_LASTPIXEL ,
7094 WINED3DRS_SHADEMODE ,
7095 WINED3DRS_SRCBLEND ,
7096 WINED3DRS_STENCILENABLE ,
7097 WINED3DRS_STENCILFAIL ,
7098 WINED3DRS_STENCILFUNC ,
7099 WINED3DRS_STENCILMASK ,
7100 WINED3DRS_STENCILPASS ,
7101 WINED3DRS_STENCILREF ,
7102 WINED3DRS_STENCILWRITEMASK ,
7103 WINED3DRS_STENCILZFAIL ,
7104 WINED3DRS_TEXTUREFACTOR ,
7105 WINED3DRS_WRAP0 ,
7106 WINED3DRS_WRAP1 ,
7107 WINED3DRS_WRAP2 ,
7108 WINED3DRS_WRAP3 ,
7109 WINED3DRS_WRAP4 ,
7110 WINED3DRS_WRAP5 ,
7111 WINED3DRS_WRAP6 ,
7112 WINED3DRS_WRAP7 ,
7113 WINED3DRS_ZENABLE ,
7114 WINED3DRS_ZFUNC ,
7115 WINED3DRS_ZWRITEENABLE
7118 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7119 WINED3DTSS_ADDRESSW ,
7120 WINED3DTSS_ALPHAARG0 ,
7121 WINED3DTSS_ALPHAARG1 ,
7122 WINED3DTSS_ALPHAARG2 ,
7123 WINED3DTSS_ALPHAOP ,
7124 WINED3DTSS_BUMPENVLOFFSET ,
7125 WINED3DTSS_BUMPENVLSCALE ,
7126 WINED3DTSS_BUMPENVMAT00 ,
7127 WINED3DTSS_BUMPENVMAT01 ,
7128 WINED3DTSS_BUMPENVMAT10 ,
7129 WINED3DTSS_BUMPENVMAT11 ,
7130 WINED3DTSS_COLORARG0 ,
7131 WINED3DTSS_COLORARG1 ,
7132 WINED3DTSS_COLORARG2 ,
7133 WINED3DTSS_COLOROP ,
7134 WINED3DTSS_RESULTARG ,
7135 WINED3DTSS_TEXCOORDINDEX ,
7136 WINED3DTSS_TEXTURETRANSFORMFLAGS
7139 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7140 WINED3DSAMP_ADDRESSU ,
7141 WINED3DSAMP_ADDRESSV ,
7142 WINED3DSAMP_ADDRESSW ,
7143 WINED3DSAMP_BORDERCOLOR ,
7144 WINED3DSAMP_MAGFILTER ,
7145 WINED3DSAMP_MINFILTER ,
7146 WINED3DSAMP_MIPFILTER ,
7147 WINED3DSAMP_MIPMAPLODBIAS ,
7148 WINED3DSAMP_MAXMIPLEVEL ,
7149 WINED3DSAMP_MAXANISOTROPY ,
7150 WINED3DSAMP_SRGBTEXTURE ,
7151 WINED3DSAMP_ELEMENTINDEX
7154 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7155 WINED3DRS_AMBIENT ,
7156 WINED3DRS_AMBIENTMATERIALSOURCE ,
7157 WINED3DRS_CLIPPING ,
7158 WINED3DRS_CLIPPLANEENABLE ,
7159 WINED3DRS_COLORVERTEX ,
7160 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7161 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7162 WINED3DRS_FOGDENSITY ,
7163 WINED3DRS_FOGEND ,
7164 WINED3DRS_FOGSTART ,
7165 WINED3DRS_FOGTABLEMODE ,
7166 WINED3DRS_FOGVERTEXMODE ,
7167 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7168 WINED3DRS_LIGHTING ,
7169 WINED3DRS_LOCALVIEWER ,
7170 WINED3DRS_MULTISAMPLEANTIALIAS ,
7171 WINED3DRS_MULTISAMPLEMASK ,
7172 WINED3DRS_NORMALIZENORMALS ,
7173 WINED3DRS_PATCHEDGESTYLE ,
7174 WINED3DRS_POINTSCALE_A ,
7175 WINED3DRS_POINTSCALE_B ,
7176 WINED3DRS_POINTSCALE_C ,
7177 WINED3DRS_POINTSCALEENABLE ,
7178 WINED3DRS_POINTSIZE ,
7179 WINED3DRS_POINTSIZE_MAX ,
7180 WINED3DRS_POINTSIZE_MIN ,
7181 WINED3DRS_POINTSPRITEENABLE ,
7182 WINED3DRS_RANGEFOGENABLE ,
7183 WINED3DRS_SPECULARMATERIALSOURCE ,
7184 WINED3DRS_TWEENFACTOR ,
7185 WINED3DRS_VERTEXBLEND
7188 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7189 WINED3DTSS_TEXCOORDINDEX ,
7190 WINED3DTSS_TEXTURETRANSFORMFLAGS
7193 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7194 WINED3DSAMP_DMAPOFFSET
7197 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7198 DWORD rep = StateTable[state].representative;
7199 DWORD idx;
7200 BYTE shift;
7202 if(!rep || isStateDirty(This, rep)) return;
7204 This->dirtyArray[This->numDirtyEntries++] = rep;
7205 idx = rep >> 5;
7206 shift = rep & 0x1f;
7207 This->isStateDirty[idx] |= (1 << shift);