wined3d: Avoid XFree on NULL in CheckDeviceType.
[wine/hacks.git] / dlls / wined3d / directx.c
blob59cf1b050bc7f5dc3c1d2d699d6387138d223ebc
1 /*
2 * IWineD3D implementation
4 * Copyright 2002-2004 Jason Edmeades
5 * Copyright 2003-2004 Raphael Junqueira
6 * Copyright 2004 Christian Costa
7 * Copyright 2005 Oliver Stieber
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 /* Compile time diagnostics: */
26 /* Uncomment this to force only a single display mode to be exposed: */
27 /*#define DEBUG_SINGLE_MODE*/
30 #include "config.h"
31 #include "wined3d_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
34 WINE_DECLARE_DEBUG_CHANNEL(d3d_caps);
35 #define GLINFO_LOCATION This->gl_info
37 /**********************************************************
38 * Utility functions follow
39 **********************************************************/
41 /* x11drv GDI escapes */
42 #define X11DRV_ESCAPE 6789
43 enum x11drv_escape_codes
45 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
46 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
47 X11DRV_GET_FONT, /* get current X font for a DC */
50 /* retrieve the X display to use on a given DC */
51 inline static Display *get_display( HDC hdc )
53 Display *display;
54 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
56 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
57 sizeof(display), (LPSTR)&display )) display = NULL;
58 return display;
61 /* lookup tables */
62 int minLookup[MAX_LOOKUPS];
63 int maxLookup[MAX_LOOKUPS];
64 DWORD *stateLookup[MAX_LOOKUPS];
66 DWORD minMipLookup[WINED3DTEXF_ANISOTROPIC + 1][WINED3DTEXF_LINEAR + 1];
69 typedef struct _WineD3D_GLContext {
70 GLXContext glCtx;
71 Display* display;
72 LONG ref;
73 } WineD3D_Context;
76 /**
77 * Note: GL seems to trap if GetDeviceCaps is called before any HWND's created
78 * ie there is no GL Context - Get a default rendering context to enable the
79 * function query some info from GL
81 static WineD3D_Context* WineD3D_CreateFakeGLContext(void) {
82 static WineD3D_Context ctx;
83 WineD3D_Context* ret = NULL;
85 if (glXGetCurrentContext() == NULL) {
86 BOOL gotContext = FALSE;
87 BOOL created = FALSE;
88 XVisualInfo template;
89 HDC device_context;
90 Visual* visual;
91 BOOL failed = FALSE;
92 int num;
93 XVisualInfo *visInfo;
94 Drawable drawable;
95 XWindowAttributes win_attr;
96 TRACE_(d3d_caps)("Creating Fake GL Context\n");
98 drawable = (Drawable) GetPropA(GetDesktopWindow(), "__wine_x11_whole_window");
100 /* Get the display */
101 device_context = GetDC(0);
102 ctx.display = get_display(device_context);
103 ReleaseDC(0, device_context);
105 /* Get the X visual */
106 ENTER_GL();
107 if (XGetWindowAttributes(ctx.display, drawable, &win_attr)) {
108 visual = win_attr.visual;
109 } else {
110 visual = DefaultVisual(ctx.display, DefaultScreen(ctx.display));
112 template.visualid = XVisualIDFromVisual(visual);
113 visInfo = XGetVisualInfo(ctx.display, VisualIDMask, &template, &num);
114 if (visInfo == NULL) {
115 LEAVE_GL();
116 WARN_(d3d_caps)("Error creating visual info for capabilities initialization\n");
117 failed = TRUE;
120 /* Create a GL context */
121 if (!failed) {
122 ctx.glCtx = glXCreateContext(ctx.display, visInfo, NULL, GL_TRUE);
123 XFree( visInfo );
125 if (ctx.glCtx == NULL) {
126 LEAVE_GL();
127 WARN_(d3d_caps)("Error creating default context for capabilities initialization\n");
128 failed = TRUE;
132 /* Make it the current GL context */
133 if (!failed && glXMakeCurrent(ctx.display, drawable, ctx.glCtx) == False) {
134 glXDestroyContext(ctx.display, ctx.glCtx);
135 LEAVE_GL();
136 WARN_(d3d_caps)("Error setting default context as current for capabilities initialization\n");
137 failed = TRUE;
140 /* It worked! Wow... */
141 if (!failed) {
142 gotContext = TRUE;
143 created = TRUE;
144 ret = &ctx;
145 } else {
146 ret = NULL;
149 } else {
150 if (ctx.ref > 0) ret = &ctx;
153 if (NULL != ret) InterlockedIncrement(&ret->ref);
154 return ret;
157 static void WineD3D_ReleaseFakeGLContext(WineD3D_Context* ctx) {
158 /* If we created a dummy context, throw it away */
159 if (NULL != ctx) {
160 if (0 == InterlockedDecrement(&ctx->ref)) {
161 glXMakeCurrent(ctx->display, None, NULL);
162 glXDestroyContext(ctx->display, ctx->glCtx);
163 ctx->display = NULL;
164 ctx->glCtx = NULL;
165 LEAVE_GL();
170 /**********************************************************
171 * IUnknown parts follows
172 **********************************************************/
174 static HRESULT WINAPI IWineD3DImpl_QueryInterface(IWineD3D *iface,REFIID riid,LPVOID *ppobj)
176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
178 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
179 if (IsEqualGUID(riid, &IID_IUnknown)
180 || IsEqualGUID(riid, &IID_IWineD3DBase)
181 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
182 IUnknown_AddRef(iface);
183 *ppobj = This;
184 return S_OK;
186 *ppobj = NULL;
187 return E_NOINTERFACE;
190 static ULONG WINAPI IWineD3DImpl_AddRef(IWineD3D *iface) {
191 IWineD3DImpl *This = (IWineD3DImpl *)iface;
192 ULONG refCount = InterlockedIncrement(&This->ref);
194 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
195 return refCount;
198 static ULONG WINAPI IWineD3DImpl_Release(IWineD3D *iface) {
199 IWineD3DImpl *This = (IWineD3DImpl *)iface;
200 ULONG ref;
201 TRACE("(%p) : Releasing from %d\n", This, This->ref);
202 ref = InterlockedDecrement(&This->ref);
203 if (ref == 0) {
204 HeapFree(GetProcessHeap(), 0, This);
207 return ref;
210 /* Set the shader type for this device, depending on the given capabilities,
211 * the device type, and the user preferences in wined3d_settings */
213 static void select_shader_mode(
214 WineD3D_GL_Info *gl_info,
215 WINED3DDEVTYPE DeviceType,
216 int* ps_selected,
217 int* vs_selected) {
219 /* Give priority to user disable/emulation request.
220 * Then respect REF device for software.
221 * Then check capabilities for hardware, and fallback to software */
223 if (wined3d_settings.vs_mode == VS_NONE) {
224 *vs_selected = SHADER_NONE;
225 } else if (DeviceType == WINED3DDEVTYPE_REF || wined3d_settings.vs_mode == VS_SW) {
226 *vs_selected = SHADER_SW;
227 } else if (gl_info->supported[ARB_VERTEX_SHADER] && wined3d_settings.glslRequested) {
228 *vs_selected = SHADER_GLSL;
229 } else if (gl_info->supported[ARB_VERTEX_PROGRAM]) {
230 *vs_selected = SHADER_ARB;
231 } else {
232 *vs_selected = SHADER_SW;
235 /* Fallback to SHADER_NONE where software pixel shaders should be used */
236 if (wined3d_settings.ps_mode == PS_NONE) {
237 *ps_selected = SHADER_NONE;
238 } else if (DeviceType == WINED3DDEVTYPE_REF) {
239 *ps_selected = SHADER_NONE;
240 } else if (gl_info->supported[ARB_FRAGMENT_SHADER] && wined3d_settings.glslRequested) {
241 *ps_selected = SHADER_GLSL;
242 } else if (gl_info->supported[ARB_FRAGMENT_PROGRAM]) {
243 *ps_selected = SHADER_ARB;
244 } else {
245 *ps_selected = SHADER_NONE;
249 /** Select the number of report maximum shader constants based on the selected shader modes */
250 void select_shader_max_constants(
251 int ps_selected_mode,
252 int vs_selected_mode,
253 WineD3D_GL_Info *gl_info) {
255 switch (vs_selected_mode) {
256 case SHADER_GLSL:
257 /* Subtract the other potential uniforms from the max available (bools, ints, and 1 row of projection matrix) */
258 gl_info->max_vshader_constantsF = gl_info->vs_glsl_constantsF - MAX_CONST_B - MAX_CONST_I - 1;
259 break;
260 case SHADER_ARB:
261 /* We have to subtract any other PARAMs that we might use in our shader programs.
262 * ATI seems to count 2 implicit PARAMs when we use fog and NVIDIA counts 1,
263 * and we reference one row of the PROJECTION matrix which counts as 1 PARAM. */
264 gl_info->max_vshader_constantsF = gl_info->vs_arb_constantsF - 3;
265 break;
266 case SHADER_SW:
267 gl_info->max_vshader_constantsF = 96; /* TODO: Fixup software shaders */
268 break;
269 default:
270 gl_info->max_vshader_constantsF = 0;
271 break;
274 switch (ps_selected_mode) {
275 case SHADER_GLSL:
276 /* Subtract the other potential uniforms from the max available (bools & ints) */
277 gl_info->max_pshader_constantsF = gl_info->ps_glsl_constantsF - MAX_CONST_B - MAX_CONST_I;
278 break;
279 case SHADER_ARB:
280 gl_info->max_pshader_constantsF = gl_info->ps_arb_constantsF;
281 break;
282 case SHADER_SW:
283 gl_info->max_pshader_constantsF = 96; /* TODO: Fixup software shaders */
284 break;
285 default:
286 gl_info->max_pshader_constantsF = 0;
287 break;
291 /**********************************************************
292 * IWineD3D parts follows
293 **********************************************************/
295 BOOL IWineD3DImpl_FillGLCaps(IWineD3D *iface, Display* display) {
296 IWineD3DImpl *This = (IWineD3DImpl *)iface;
297 WineD3D_GL_Info *gl_info = &This->gl_info;
299 const char *GL_Extensions = NULL;
300 const char *GLX_Extensions = NULL;
301 const char *gl_string = NULL;
302 const char *gl_string_cursor = NULL;
303 GLint gl_max;
304 GLfloat gl_floatv[2];
305 Bool test = 0;
306 int major, minor;
307 WineD3D_Context *fake_ctx = NULL;
308 BOOL gotContext = FALSE;
309 int i;
311 /* Make sure that we've got a context */
312 if (glXGetCurrentContext() == NULL) {
313 /* TODO: CreateFakeGLContext should really take a display as a parameter */
314 fake_ctx = WineD3D_CreateFakeGLContext();
315 if (NULL != fake_ctx) gotContext = TRUE;
316 } else {
317 gotContext = TRUE;
320 TRACE_(d3d_caps)("(%p, %p)\n", gl_info, display);
322 gl_string = (const char *) glGetString(GL_RENDERER);
323 if (NULL == gl_string)
324 gl_string = "None";
325 strcpy(gl_info->gl_renderer, gl_string);
327 /* Fill in the GL info retrievable depending on the display */
328 if (NULL != display) {
329 test = glXQueryVersion(display, &major, &minor);
330 gl_info->glx_version = ((major & 0x0000FFFF) << 16) | (minor & 0x0000FFFF);
331 } else {
332 FIXME("Display must not be NULL, use glXGetCurrentDisplay or getAdapterDisplay()\n");
334 gl_string = (const char *) glGetString(GL_VENDOR);
336 TRACE_(d3d_caps)("Filling vendor string %s\n", gl_string);
337 if (gl_string != NULL) {
338 /* Fill in the GL vendor */
339 if (strstr(gl_string, "NVIDIA")) {
340 gl_info->gl_vendor = VENDOR_NVIDIA;
341 } else if (strstr(gl_string, "ATI")) {
342 gl_info->gl_vendor = VENDOR_ATI;
343 } else if (strstr(gl_string, "Intel(R)") ||
344 strstr(gl_info->gl_renderer, "Intel(R)")) {
345 gl_info->gl_vendor = VENDOR_INTEL;
346 } else if (strstr(gl_string, "Mesa")) {
347 gl_info->gl_vendor = VENDOR_MESA;
348 } else {
349 gl_info->gl_vendor = VENDOR_WINE;
351 } else {
352 gl_info->gl_vendor = VENDOR_WINE;
356 TRACE_(d3d_caps)("found GL_VENDOR (%s)->(0x%04x)\n", debugstr_a(gl_string), gl_info->gl_vendor);
358 /* Parse the GL_VERSION field into major and minor information */
359 gl_string = (const char *) glGetString(GL_VERSION);
360 if (gl_string != NULL) {
362 switch (gl_info->gl_vendor) {
363 case VENDOR_NVIDIA:
364 gl_string_cursor = strstr(gl_string, "NVIDIA");
365 if (!gl_string_cursor) {
366 ERR_(d3d_caps)("Invalid nVidia version string: %s\n", debugstr_a(gl_string));
367 break;
370 gl_string_cursor = strstr(gl_string_cursor, " ");
371 if (!gl_string_cursor) {
372 ERR_(d3d_caps)("Invalid nVidia version string: %s\n", debugstr_a(gl_string));
373 break;
376 while (*gl_string_cursor == ' ') {
377 ++gl_string_cursor;
380 if (!*gl_string_cursor) {
381 ERR_(d3d_caps)("Invalid nVidia version string: %s\n", debugstr_a(gl_string));
382 break;
385 major = atoi(gl_string_cursor);
386 while (*gl_string_cursor <= '9' && *gl_string_cursor >= '0') {
387 ++gl_string_cursor;
390 if (*gl_string_cursor++ != '.') {
391 ERR_(d3d_caps)("Invalid nVidia version string: %s\n", debugstr_a(gl_string));
392 break;
395 minor = atoi(gl_string_cursor);
396 minor = major*100+minor;
397 major = 10;
399 break;
401 case VENDOR_ATI:
402 major = minor = 0;
403 gl_string_cursor = strchr(gl_string, '-');
404 if (gl_string_cursor) {
405 int error = 0;
406 gl_string_cursor++;
408 /* Check if version number is of the form x.y.z */
409 if (*gl_string_cursor > '9' && *gl_string_cursor < '0')
410 error = 1;
411 if (!error && *(gl_string_cursor+2) > '9' && *(gl_string_cursor+2) < '0')
412 error = 1;
413 if (!error && *(gl_string_cursor+4) > '9' && *(gl_string_cursor+4) < '0')
414 error = 1;
415 if (!error && *(gl_string_cursor+1) != '.' && *(gl_string_cursor+3) != '.')
416 error = 1;
418 /* Mark version number as malformed */
419 if (error)
420 gl_string_cursor = 0;
423 if (!gl_string_cursor)
424 WARN_(d3d_caps)("malformed GL_VERSION (%s)\n", debugstr_a(gl_string));
425 else {
426 major = *gl_string_cursor - '0';
427 minor = (*(gl_string_cursor+2) - '0') * 256 + (*(gl_string_cursor+4) - '0');
429 break;
431 case VENDOR_INTEL:
432 case VENDOR_MESA:
433 gl_string_cursor = strstr(gl_string, "Mesa");
434 gl_string_cursor = strstr(gl_string_cursor, " ");
435 while (*gl_string_cursor && ' ' == *gl_string_cursor) ++gl_string_cursor;
436 if (*gl_string_cursor) {
437 char tmp[16];
438 int cursor = 0;
440 while (*gl_string_cursor <= '9' && *gl_string_cursor >= '0') {
441 tmp[cursor++] = *gl_string_cursor;
442 ++gl_string_cursor;
444 tmp[cursor] = 0;
445 major = atoi(tmp);
447 if (*gl_string_cursor != '.') WARN_(d3d_caps)("malformed GL_VERSION (%s)\n", debugstr_a(gl_string));
448 ++gl_string_cursor;
450 cursor = 0;
451 while (*gl_string_cursor <= '9' && *gl_string_cursor >= '0') {
452 tmp[cursor++] = *gl_string_cursor;
453 ++gl_string_cursor;
455 tmp[cursor] = 0;
456 minor = atoi(tmp);
458 break;
460 default:
461 major = 0;
462 minor = 9;
464 gl_info->gl_driver_version = MAKEDWORD_VERSION(major, minor);
465 TRACE_(d3d_caps)("found GL_VERSION (%s)->%i.%i->(0x%08x)\n", debugstr_a(gl_string), major, minor, gl_info->gl_driver_version);
468 TRACE_(d3d_caps)("found GL_RENDERER (%s)->(0x%04x)\n", debugstr_a(gl_info->gl_renderer), gl_info->gl_card);
471 * Initialize openGL extension related variables
472 * with Default values
474 memset(&gl_info->supported, 0, sizeof(gl_info->supported));
475 gl_info->max_buffers = 1;
476 gl_info->max_textures = 1;
477 gl_info->max_texture_stages = 1;
478 gl_info->max_samplers = 1;
479 gl_info->max_sampler_stages = 1;
480 gl_info->ps_arb_version = PS_VERSION_NOT_SUPPORTED;
481 gl_info->ps_arb_max_temps = 0;
482 gl_info->ps_arb_max_instructions = 0;
483 gl_info->vs_arb_version = VS_VERSION_NOT_SUPPORTED;
484 gl_info->vs_arb_max_temps = 0;
485 gl_info->vs_arb_max_instructions = 0;
486 gl_info->vs_nv_version = VS_VERSION_NOT_SUPPORTED;
487 gl_info->vs_ati_version = VS_VERSION_NOT_SUPPORTED;
488 gl_info->vs_glsl_constantsF = 0;
489 gl_info->ps_glsl_constantsF = 0;
490 gl_info->vs_arb_constantsF = 0;
491 gl_info->ps_arb_constantsF = 0;
493 /* Now work out what GL support this card really has */
494 #define USE_GL_FUNC(type, pfn) gl_info->pfn = (type) glXGetProcAddressARB( (const GLubyte *) #pfn);
495 GL_EXT_FUNCS_GEN;
496 GLX_EXT_FUNCS_GEN;
497 #undef USE_GL_FUNC
499 /* Retrieve opengl defaults */
500 glGetIntegerv(GL_MAX_CLIP_PLANES, &gl_max);
501 gl_info->max_clipplanes = min(WINED3DMAXUSERCLIPPLANES, gl_max);
502 TRACE_(d3d_caps)("ClipPlanes support - num Planes=%d\n", gl_max);
504 glGetIntegerv(GL_MAX_LIGHTS, &gl_max);
505 gl_info->max_lights = gl_max;
506 TRACE_(d3d_caps)("Lights support - max lights=%d\n", gl_max);
508 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl_max);
509 gl_info->max_texture_size = gl_max;
510 TRACE_(d3d_caps)("Maximum texture size support - max texture size=%d\n", gl_max);
512 glGetFloatv(GL_POINT_SIZE_RANGE, gl_floatv);
513 gl_info->max_pointsize = gl_floatv[1];
514 TRACE_(d3d_caps)("Maximum point size support - max point size=%f\n", gl_floatv[1]);
516 /* Parse the gl supported features, in theory enabling parts of our code appropriately */
517 GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
518 TRACE_(d3d_caps)("GL_Extensions reported:\n");
520 if (NULL == GL_Extensions) {
521 ERR(" GL_Extensions returns NULL\n");
522 } else {
523 while (*GL_Extensions != 0x00) {
524 const char *Start = GL_Extensions;
525 char ThisExtn[256];
527 memset(ThisExtn, 0x00, sizeof(ThisExtn));
528 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
529 GL_Extensions++;
531 memcpy(ThisExtn, Start, (GL_Extensions - Start));
532 TRACE_(d3d_caps)("- %s\n", ThisExtn);
535 * ARB
537 if (strcmp(ThisExtn, "GL_ARB_draw_buffers") == 0) {
538 glGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &gl_max);
539 TRACE_(d3d_caps)(" FOUND: ARB_draw_buffers support - max buffers=%u\n", gl_max);
540 gl_info->supported[ARB_DRAW_BUFFERS] = TRUE;
541 gl_info->max_buffers = gl_max;
542 } else if (strcmp(ThisExtn, "GL_ARB_fragment_program") == 0) {
543 gl_info->ps_arb_version = PS_VERSION_11;
544 TRACE_(d3d_caps)(" FOUND: ARB Pixel Shader support - version=%02x\n", gl_info->ps_arb_version);
545 gl_info->supported[ARB_FRAGMENT_PROGRAM] = TRUE;
546 glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &gl_max);
547 TRACE_(d3d_caps)(" FOUND: ARB Pixel Shader support - GL_MAX_TEXTURE_IMAGE_UNITS_ARB=%u\n", gl_max);
548 gl_info->max_samplers = min(MAX_SAMPLERS, gl_max);
549 GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, &gl_max));
550 TRACE_(d3d_caps)(" FOUND: ARB Pixel Shader support - max float constants=%u\n", gl_max);
551 gl_info->ps_arb_constantsF = gl_max;
552 GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_TEMPORARIES_ARB, &gl_max));
553 TRACE_(d3d_caps)(" FOUND: ARB Pixel Shader support - max temporaries=%u\n", gl_max);
554 gl_info->ps_arb_max_temps = gl_max;
555 GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_INSTRUCTIONS_ARB, &gl_max));
556 TRACE_(d3d_caps)(" FOUND: ARB Pixel Shader support - max instructions=%u\n", gl_max);
557 gl_info->ps_arb_max_instructions = gl_max;
558 } else if (strcmp(ThisExtn, "GL_ARB_fragment_shader") == 0) {
559 gl_info->supported[ARB_FRAGMENT_SHADER] = TRUE;
560 glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, &gl_max);
561 gl_max /= 4;
562 TRACE_(d3d_caps)(" FOUND: ARB_fragment_shader (GLSL) support - max float ps constants=%u\n", gl_max);
563 gl_info->ps_glsl_constantsF = gl_max;
564 } else if (strcmp(ThisExtn, "GL_ARB_imaging") == 0) {
565 TRACE_(d3d_caps)(" FOUND: ARB imaging support\n");
566 gl_info->supported[ARB_IMAGING] = TRUE;
567 } else if (strcmp(ThisExtn, "GL_ARB_multisample") == 0) {
568 TRACE_(d3d_caps)(" FOUND: ARB Multisample support\n");
569 gl_info->supported[ARB_MULTISAMPLE] = TRUE;
570 } else if (strcmp(ThisExtn, "GL_ARB_multitexture") == 0) {
571 glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &gl_max);
572 TRACE_(d3d_caps)(" FOUND: ARB Multitexture support - GL_MAX_TEXTURE_UNITS_ARB=%u\n", gl_max);
573 gl_info->supported[ARB_MULTITEXTURE] = TRUE;
574 gl_info->max_textures = min(MAX_TEXTURES, gl_max);
575 gl_info->max_texture_stages = min(MAX_TEXTURES, gl_max);
576 gl_info->max_samplers = max(gl_info->max_samplers, gl_max);
577 } else if (strcmp(ThisExtn, "GL_ARB_texture_cube_map") == 0) {
578 TRACE_(d3d_caps)(" FOUND: ARB Texture Cube Map support\n");
579 gl_info->supported[ARB_TEXTURE_CUBE_MAP] = TRUE;
580 TRACE_(d3d_caps)(" IMPLIED: NVIDIA (NV) Texture Gen Reflection support\n");
581 gl_info->supported[NV_TEXGEN_REFLECTION] = TRUE;
582 } else if (strcmp(ThisExtn, "GL_ARB_texture_compression") == 0) {
583 TRACE_(d3d_caps)(" FOUND: ARB Texture Compression support\n");
584 gl_info->supported[ARB_TEXTURE_COMPRESSION] = TRUE;
585 } else if (strcmp(ThisExtn, "GL_ARB_texture_env_add") == 0) {
586 TRACE_(d3d_caps)(" FOUND: ARB Texture Env Add support\n");
587 gl_info->supported[ARB_TEXTURE_ENV_ADD] = TRUE;
588 } else if (strcmp(ThisExtn, "GL_ARB_texture_env_combine") == 0) {
589 TRACE_(d3d_caps)(" FOUND: ARB Texture Env combine support\n");
590 gl_info->supported[ARB_TEXTURE_ENV_COMBINE] = TRUE;
591 } else if (strcmp(ThisExtn, "GL_ARB_texture_env_dot3") == 0) {
592 TRACE_(d3d_caps)(" FOUND: ARB Dot3 support\n");
593 gl_info->supported[ARB_TEXTURE_ENV_DOT3] = TRUE;
594 } else if (strcmp(ThisExtn, "GL_ARB_texture_float") == 0) {
595 TRACE_(d3d_caps)(" FOUND: ARB Float texture support\n");
596 gl_info->supported[ARB_TEXTURE_FLOAT] = TRUE;
597 } else if (strcmp(ThisExtn, "GL_ARB_half_float_pixel") == 0) {
598 TRACE_(d3d_caps)(" FOUND: ARB Half-float pixel support\n");
599 gl_info->supported[ARB_HALF_FLOAT_PIXEL] = TRUE;
600 } else if (strcmp(ThisExtn, "GL_ARB_texture_border_clamp") == 0) {
601 TRACE_(d3d_caps)(" FOUND: ARB Texture border clamp support\n");
602 gl_info->supported[ARB_TEXTURE_BORDER_CLAMP] = TRUE;
603 } else if (strcmp(ThisExtn, "GL_ARB_texture_mirrored_repeat") == 0) {
604 TRACE_(d3d_caps)(" FOUND: ARB Texture mirrored repeat support\n");
605 gl_info->supported[ARB_TEXTURE_MIRRORED_REPEAT] = TRUE;
606 } else if (strcmp(ThisExtn, "GL_ARB_texture_non_power_of_two") == 0) {
607 TRACE_(d3d_caps)(" FOUND: ARB NPOT texture support\n");
608 gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] = TRUE;
609 } else if (strcmp(ThisExtn, "GLX_ARB_multisample") == 0) {
610 TRACE_(d3d_caps)(" FOUND: ARB multisample support\n");
611 gl_info->supported[ARB_MULTISAMPLE] = TRUE;
612 } else if (strcmp(ThisExtn, "GL_ARB_pixel_buffer_object") == 0) {
613 TRACE_(d3d_caps)(" FOUND: ARB Pixel Buffer support\n");
614 gl_info->supported[ARB_PIXEL_BUFFER_OBJECT] = TRUE;
615 } else if (strcmp(ThisExtn, "GL_ARB_point_sprite") == 0) {
616 TRACE_(d3d_caps)(" FOUND: ARB point sprite support\n");
617 gl_info->supported[ARB_POINT_SPRITE] = TRUE;
618 } else if (strstr(ThisExtn, "GL_ARB_vertex_program")) {
619 gl_info->vs_arb_version = VS_VERSION_11;
620 TRACE_(d3d_caps)(" FOUND: ARB Vertex Shader support - version=%02x\n", gl_info->vs_arb_version);
621 gl_info->supported[ARB_VERTEX_PROGRAM] = TRUE;
622 GL_EXTCALL(glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, &gl_max));
623 TRACE_(d3d_caps)(" FOUND: ARB Vertex Shader support - max float constants=%u\n", gl_max);
624 gl_info->vs_arb_constantsF = gl_max;
625 GL_EXTCALL(glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_TEMPORARIES_ARB, &gl_max));
626 TRACE_(d3d_caps)(" FOUND: ARB Vertex Shader support - max temporaries=%u\n", gl_max);
627 gl_info->vs_arb_max_temps = gl_max;
628 GL_EXTCALL(glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_INSTRUCTIONS_ARB, &gl_max));
629 TRACE_(d3d_caps)(" FOUND: ARB Vertex Shader support - max instructions=%u\n", gl_max);
630 gl_info->vs_arb_max_instructions = gl_max;
631 } else if (strcmp(ThisExtn, "GL_ARB_vertex_shader") == 0) {
632 gl_info->supported[ARB_VERTEX_SHADER] = TRUE;
633 glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &gl_max);
634 gl_max /= 4;
635 TRACE_(d3d_caps)(" FOUND: ARB_vertex_shader (GLSL) support - max float vs constants=%u\n", gl_max);
636 gl_info->vs_glsl_constantsF = gl_max;
637 } else if (strcmp(ThisExtn, "GL_ARB_vertex_blend") == 0) {
638 glGetIntegerv(GL_MAX_VERTEX_UNITS_ARB, &gl_max);
639 TRACE_(d3d_caps)(" FOUND: ARB Vertex Blend support GL_MAX_VERTEX_UNITS_ARB %d\n", gl_max);
640 gl_info->max_blends = gl_max;
641 gl_info->supported[ARB_VERTEX_BLEND] = TRUE;
642 } else if (strcmp(ThisExtn, "GL_ARB_vertex_buffer_object") == 0) {
643 TRACE_(d3d_caps)(" FOUND: ARB Vertex Buffer support\n");
644 gl_info->supported[ARB_VERTEX_BUFFER_OBJECT] = TRUE;
645 } else if (strcmp(ThisExtn, "GL_ARB_occlusion_query") == 0) {
646 TRACE_(d3d_caps)(" FOUND: ARB Occlusion Query support\n");
647 gl_info->supported[ARB_OCCLUSION_QUERY] = TRUE;
648 } else if (strcmp(ThisExtn, "GL_ARB_point_parameters") == 0) {
649 TRACE_(d3d_caps)(" FOUND: ARB Point parameters support\n");
650 gl_info->supported[ARB_POINT_PARAMETERS] = TRUE;
652 * EXT
654 } else if (strcmp(ThisExtn, "GL_EXT_fog_coord") == 0) {
655 TRACE_(d3d_caps)(" FOUND: EXT Fog coord support\n");
656 gl_info->supported[EXT_FOG_COORD] = TRUE;
657 } else if (strcmp(ThisExtn, "GL_EXT_framebuffer_object") == 0) {
658 TRACE_(d3d_caps)(" FOUND: EXT Frame Buffer Object support\n");
659 gl_info->supported[EXT_FRAMEBUFFER_OBJECT] = TRUE;
660 } else if (strcmp(ThisExtn, "GL_EXT_blend_minmax") == 0) {
661 TRACE_(d3d_caps)(" FOUND: EXT Blend minmax support\n");
662 gl_info->supported[EXT_BLEND_MINMAX] = TRUE;
663 } else if (strcmp(ThisExtn, "GL_EXT_paletted_texture") == 0) { /* handle paletted texture extensions */
664 TRACE_(d3d_caps)(" FOUND: EXT Paletted texture support\n");
665 gl_info->supported[EXT_PALETTED_TEXTURE] = TRUE;
666 } else if (strcmp(ThisExtn, "GL_EXT_point_parameters") == 0) {
667 TRACE_(d3d_caps)(" FOUND: EXT Point parameters support\n");
668 gl_info->supported[EXT_POINT_PARAMETERS] = TRUE;
669 } else if (strcmp(ThisExtn, "GL_EXT_secondary_color") == 0) {
670 TRACE_(d3d_caps)(" FOUND: EXT Secondary coord support\n");
671 gl_info->supported[EXT_SECONDARY_COLOR] = TRUE;
672 } else if (strcmp(ThisExtn, "GL_EXT_stencil_two_side") == 0) {
673 TRACE_(d3d_caps)(" FOUND: EXT Stencil two side support\n");
674 gl_info->supported[EXT_STENCIL_TWO_SIDE] = TRUE;
675 } else if (strcmp(ThisExtn, "GL_EXT_stencil_wrap") == 0) {
676 TRACE_(d3d_caps)(" FOUND: EXT Stencil wrap support\n");
677 gl_info->supported[EXT_STENCIL_WRAP] = TRUE;
678 } else if (strcmp(ThisExtn, "GL_EXT_texture3D") == 0) {
679 TRACE_(d3d_caps)(" FOUND: EXT_texture3D support\n");
680 gl_info->supported[EXT_TEXTURE3D] = TRUE;
681 glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE_EXT, &gl_max);
682 TRACE_(d3d_caps)("Max texture3D size: %d\n", gl_max);
683 gl_info->max_texture3d_size = gl_max;
684 } else if (strcmp(ThisExtn, "GL_EXT_texture_compression_s3tc") == 0) {
685 TRACE_(d3d_caps)(" FOUND: EXT Texture S3TC compression support\n");
686 gl_info->supported[EXT_TEXTURE_COMPRESSION_S3TC] = TRUE;
687 } else if (strcmp(ThisExtn, "GL_EXT_texture_env_add") == 0) {
688 TRACE_(d3d_caps)(" FOUND: EXT Texture Env Add support\n");
689 gl_info->supported[EXT_TEXTURE_ENV_ADD] = TRUE;
690 } else if (strcmp(ThisExtn, "GL_EXT_texture_env_combine") == 0) {
691 TRACE_(d3d_caps)(" FOUND: EXT Texture Env combine support\n");
692 gl_info->supported[EXT_TEXTURE_ENV_COMBINE] = TRUE;
693 } else if (strcmp(ThisExtn, "GL_EXT_texture_env_dot3") == 0) {
694 TRACE_(d3d_caps)(" FOUND: EXT Dot3 support\n");
695 gl_info->supported[EXT_TEXTURE_ENV_DOT3] = TRUE;
696 } else if (strcmp(ThisExtn, "GL_EXT_texture_filter_anisotropic") == 0) {
697 gl_info->supported[EXT_TEXTURE_FILTER_ANISOTROPIC] = TRUE;
698 glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_max);
699 TRACE_(d3d_caps)(" FOUND: EXT Texture Anisotropic filter support. GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT %d\n", gl_max);
700 gl_info->max_anisotropy = gl_max;
701 } else if (strcmp(ThisExtn, "GL_EXT_texture_lod") == 0) {
702 TRACE_(d3d_caps)(" FOUND: EXT Texture LOD support\n");
703 gl_info->supported[EXT_TEXTURE_LOD] = TRUE;
704 } else if (strcmp(ThisExtn, "GL_EXT_texture_lod_bias") == 0) {
705 TRACE_(d3d_caps)(" FOUND: EXT Texture LOD bias support\n");
706 gl_info->supported[EXT_TEXTURE_LOD_BIAS] = TRUE;
707 } else if (strcmp(ThisExtn, "GL_EXT_vertex_weighting") == 0) {
708 TRACE_(d3d_caps)(" FOUND: EXT Vertex weighting support\n");
709 gl_info->supported[EXT_VERTEX_WEIGHTING] = TRUE;
712 * NVIDIA
714 } else if (strstr(ThisExtn, "GL_NV_fog_distance")) {
715 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Fog Distance support\n");
716 gl_info->supported[NV_FOG_DISTANCE] = TRUE;
717 } else if (strstr(ThisExtn, "GL_NV_fragment_program")) {
718 gl_info->ps_nv_version = (strcmp(ThisExtn, "GL_NV_fragment_program2") == 0) ? PS_VERSION_30 : PS_VERSION_20;
719 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Pixel Shader support - version=%02x\n", gl_info->ps_nv_version);
720 } else if (strcmp(ThisExtn, "GL_NV_register_combiners") == 0) {
721 glGetIntegerv(GL_MAX_GENERAL_COMBINERS_NV, &gl_max);
722 gl_info->max_texture_stages = min(MAX_TEXTURES, gl_max);
723 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Register combiners (1) support - GL_MAX_GENERAL_COMBINERS_NV=%d\n", gl_max);
724 gl_info->supported[NV_REGISTER_COMBINERS] = TRUE;
725 } else if (strcmp(ThisExtn, "GL_NV_register_combiners2") == 0) {
726 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Register combiners (2) support\n");
727 gl_info->supported[NV_REGISTER_COMBINERS2] = TRUE;
728 } else if (strcmp(ThisExtn, "GL_NV_texgen_reflection") == 0) {
729 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Texture Gen Reflection support\n");
730 gl_info->supported[NV_TEXGEN_REFLECTION] = TRUE;
731 } else if (strcmp(ThisExtn, "GL_NV_texture_env_combine4") == 0) {
732 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Texture Env combine (4) support\n");
733 gl_info->supported[NV_TEXTURE_ENV_COMBINE4] = TRUE;
734 } else if (strcmp(ThisExtn, "GL_NV_texture_shader") == 0) {
735 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Texture Shader (1) support\n");
736 gl_info->supported[NV_TEXTURE_SHADER] = TRUE;
737 } else if (strcmp(ThisExtn, "GL_NV_texture_shader2") == 0) {
738 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Texture Shader (2) support\n");
739 gl_info->supported[NV_TEXTURE_SHADER2] = TRUE;
740 } else if (strcmp(ThisExtn, "GL_NV_texture_shader3") == 0) {
741 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Texture Shader (3) support\n");
742 gl_info->supported[NV_TEXTURE_SHADER3] = TRUE;
743 } else if (strcmp(ThisExtn, "GL_NV_occlusion_query") == 0) {
744 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Occlusion Query (3) support\n");
745 gl_info->supported[NV_OCCLUSION_QUERY] = TRUE;
746 } else if (strstr(ThisExtn, "GL_NV_vertex_program")) {
747 if(strcmp(ThisExtn, "GL_NV_vertex_program3") == 0)
748 gl_info->vs_nv_version = VS_VERSION_30;
749 else if(strcmp(ThisExtn, "GL_NV_vertex_program2") == 0)
750 gl_info->vs_nv_version = VS_VERSION_20;
751 else if(strcmp(ThisExtn, "GL_NV_vertex_program1_1") == 0)
752 gl_info->vs_nv_version = VS_VERSION_11;
753 else
754 gl_info->vs_nv_version = VS_VERSION_10;
755 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Vertex Shader support - version=%02x\n", gl_info->vs_nv_version);
756 gl_info->supported[NV_VERTEX_PROGRAM] = TRUE;
759 * ATI
761 /** TODO */
762 } else if (strcmp(ThisExtn, "GL_ATI_separate_stencil") == 0) {
763 TRACE_(d3d_caps)(" FOUND: ATI Separate stencil support\n");
764 gl_info->supported[ATI_SEPARATE_STENCIL] = TRUE;
765 } else if (strcmp(ThisExtn, "GL_ATI_texture_env_combine3") == 0) {
766 TRACE_(d3d_caps)(" FOUND: ATI Texture Env combine (3) support\n");
767 gl_info->supported[ATI_TEXTURE_ENV_COMBINE3] = TRUE;
768 } else if (strcmp(ThisExtn, "GL_ATI_texture_mirror_once") == 0) {
769 TRACE_(d3d_caps)(" FOUND: ATI Texture Mirror Once support\n");
770 gl_info->supported[ATI_TEXTURE_MIRROR_ONCE] = TRUE;
771 } else if (strcmp(ThisExtn, "GL_EXT_vertex_shader") == 0) {
772 gl_info->vs_ati_version = VS_VERSION_11;
773 TRACE_(d3d_caps)(" FOUND: ATI (EXT) Vertex Shader support - version=%02x\n", gl_info->vs_ati_version);
774 gl_info->supported[EXT_VERTEX_SHADER] = TRUE;
778 if (*GL_Extensions == ' ') GL_Extensions++;
781 checkGLcall("extension detection\n");
783 /* In some cases the number of texture stages can be larger than the number
784 * of samplers. The GF4 for example can use only 2 samplers (no fragment
785 * shaders), but 8 texture stages (register combiners). */
786 gl_info->max_sampler_stages = max(gl_info->max_samplers, gl_info->max_texture_stages);
788 /* We can only use NP2_NATIVE when the hardware supports it. */
789 if (wined3d_settings.nonpower2_mode == NP2_NATIVE && !gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO]) {
790 WARN_(d3d_caps)("GL_ARB_texture_non_power_of_two not supported, falling back to NP2_NONE NPOT mode.\n");
791 wined3d_settings.nonpower2_mode = NP2_NONE;
794 /* We can only use ORM_FBO when the hardware supports it. */
795 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && !gl_info->supported[EXT_FRAMEBUFFER_OBJECT]) {
796 WARN_(d3d_caps)("GL_EXT_framebuffer_object not supported, falling back to PBuffer offscreen rendering mode.\n");
797 wined3d_settings.offscreen_rendering_mode = ORM_PBUFFER;
800 /* Below is a list of Nvidia and ATI GPUs. Both vendors have dozens of different GPUs with roughly the same
801 * features. In most cases GPUs from a certain family differ in clockspeeds, the amount of video memory and
802 * in case of the latest videocards in the number of pixel/vertex pipelines.
804 * A Direct3D device object contains the PCI id (vendor + device) of the videocard which is used for
805 * rendering. Various games use this information to get a rough estimation of the features of the card
806 * and some might use it for enabling 3d effects only on certain types of videocards. In some cases
807 * games might even use it to work around bugs which happen on certain videocards/driver combinations.
808 * The problem is that OpenGL only exposes a rendering string containing the name of the videocard and
809 * not the PCI id.
811 * Various games depend on the PCI id, so somehow we need to provide one. A simple option is to parse
812 * the renderer string and translate this to the right PCI id. This is a lot of work because there are more
813 * than 200 GPUs just for Nvidia. Various cards share the same renderer string, so the amount of code might
814 * be 'small' but there are quite a number of exceptions which would make this a pain to maintain.
815 * Another way would be to query the PCI id from the operating system (assuming this is the videocard which
816 * is used for rendering which is not always the case). This would work but it is not very portable. Second
817 * it would not work well in, let's say, a remote X situation in which the amount of 3d features which can be used
818 * is limited.
820 * As said most games only use the PCI id to get an indication of the capabilities of the card.
821 * It doesn't really matter if the given id is the correct one if we return the id of a card with
822 * similar 3d features.
824 * The code below checks the OpenGL capabilities of a videocard and matches that to a certain level of
825 * Direct3D functionality. Once a card passes the Direct3D9 check, we know that the card (in case of Nvidia)
826 * is at least a GeforceFX. To give a better estimate we do a basic check on the renderer string but if that
827 * won't pass we return a default card. This way is better than maintaining a full card database as even
828 * without a full database we can return a card with similar features. Second the size of the database
829 * can be made quite small because when you know what type of 3d functionality a card has, you know to which
830 * GPU family the GPU must belong. Because of this you only have to check a small part of the renderer string
831 * to distinguishes between different models from that family.
833 switch (gl_info->gl_vendor) {
834 case VENDOR_NVIDIA:
835 /* Both the GeforceFX, 6xxx and 7xxx series support D3D9. The last two types have more
836 * shader capabilities, so we use the shader capabilities to distinguish between FX and 6xxx/7xxx.
838 if(WINE_D3D9_CAPABLE(gl_info) && (gl_info->vs_nv_version == VS_VERSION_30)) {
839 if (strstr(gl_info->gl_renderer, "7800") ||
840 strstr(gl_info->gl_renderer, "7900") ||
841 strstr(gl_info->gl_renderer, "7950") ||
842 strstr(gl_info->gl_renderer, "Quadro FX 4") ||
843 strstr(gl_info->gl_renderer, "Quadro FX 5"))
844 gl_info->gl_card = CARD_NVIDIA_GEFORCE_7800GT;
845 else if(strstr(gl_info->gl_renderer, "6800") ||
846 strstr(gl_info->gl_renderer, "7600"))
847 gl_info->gl_card = CARD_NVIDIA_GEFORCE_6800;
848 else if(strstr(gl_info->gl_renderer, "6600") ||
849 strstr(gl_info->gl_renderer, "6610") ||
850 strstr(gl_info->gl_renderer, "6700"))
851 gl_info->gl_card = CARD_NVIDIA_GEFORCE_6600GT;
852 else
853 gl_info->gl_card = CARD_NVIDIA_GEFORCE_6200; /* Geforce 6100/6150/6200/7300/7400 */
854 } else if(WINE_D3D9_CAPABLE(gl_info)) {
855 if (strstr(gl_info->gl_renderer, "5800") ||
856 strstr(gl_info->gl_renderer, "5900") ||
857 strstr(gl_info->gl_renderer, "5950") ||
858 strstr(gl_info->gl_renderer, "Quadro FX"))
859 gl_info->gl_card = CARD_NVIDIA_GEFORCEFX_5800;
860 else if(strstr(gl_info->gl_renderer, "5600") ||
861 strstr(gl_info->gl_renderer, "5650") ||
862 strstr(gl_info->gl_renderer, "5700") ||
863 strstr(gl_info->gl_renderer, "5750"))
864 gl_info->gl_card = CARD_NVIDIA_GEFORCEFX_5600;
865 else
866 gl_info->gl_card = CARD_NVIDIA_GEFORCEFX_5200; /* GeforceFX 5100/5200/5250/5300/5500 */
867 } else if(WINE_D3D8_CAPABLE(gl_info)) {
868 if (strstr(gl_info->gl_renderer, "GeForce4 Ti") || strstr(gl_info->gl_renderer, "Quadro4"))
869 gl_info->gl_card = CARD_NVIDIA_GEFORCE4_TI4200; /* Geforce4 Ti4200/Ti4400/Ti4600/Ti4800, Quadro4 */
870 else
871 gl_info->gl_card = CARD_NVIDIA_GEFORCE3; /* Geforce3 standard/Ti200/Ti500, Quadro DCC */
872 } else if(WINE_D3D7_CAPABLE(gl_info)) {
873 if (strstr(gl_info->gl_renderer, "GeForce4 MX"))
874 gl_info->gl_card = CARD_NVIDIA_GEFORCE4_MX; /* MX420/MX440/MX460/MX4000 */
875 else if(strstr(gl_info->gl_renderer, "GeForce2 MX") || strstr(gl_info->gl_renderer, "Quadro2 MXR"))
876 gl_info->gl_card = CARD_NVIDIA_GEFORCE2_MX; /* Geforce2 standard/MX100/MX200/MX400, Quadro2 MXR */
877 else if(strstr(gl_info->gl_renderer, "GeForce2") || strstr(gl_info->gl_renderer, "Quadro2"))
878 gl_info->gl_card = CARD_NVIDIA_GEFORCE2; /* Geforce2 GTS/Pro/Ti/Ultra, Quadro2 */
879 else
880 gl_info->gl_card = CARD_NVIDIA_GEFORCE; /* Geforce 256/DDR, Quadro */
881 } else {
882 if (strstr(gl_info->gl_renderer, "TNT2"))
883 gl_info->gl_card = CARD_NVIDIA_RIVA_TNT2; /* Riva TNT2 standard/M64/Pro/Ultra */
884 else
885 gl_info->gl_card = CARD_NVIDIA_RIVA_TNT; /* Riva TNT, Vanta */
887 break;
888 case VENDOR_ATI:
889 if(WINE_D3D9_CAPABLE(gl_info)) {
890 /* Radeon R5xx */
891 if (strstr(gl_info->gl_renderer, "X1600") ||
892 strstr(gl_info->gl_renderer, "X1800") ||
893 strstr(gl_info->gl_renderer, "X1900") ||
894 strstr(gl_info->gl_renderer, "X1950"))
895 gl_info->gl_card = CARD_ATI_RADEON_X1600;
896 /* Radeon R4xx + X1300/X1400 (lowend R5xx) */
897 else if(strstr(gl_info->gl_renderer, "X700") ||
898 strstr(gl_info->gl_renderer, "X800") ||
899 strstr(gl_info->gl_renderer, "X850") ||
900 strstr(gl_info->gl_renderer, "X1300") ||
901 strstr(gl_info->gl_renderer, "X1400"))
902 gl_info->gl_card = CARD_ATI_RADEON_X700;
903 /* Radeon R3xx */
904 else
905 gl_info->gl_card = CARD_ATI_RADEON_9500; /* Radeon 9500/9550/9600/9700/9800/X300/X550/X600 */
906 } else if(WINE_D3D8_CAPABLE(gl_info)) {
907 gl_info->gl_card = CARD_ATI_RADEON_8500; /* Radeon 8500/9000/9100/9200/9300 */
908 } else if(WINE_D3D7_CAPABLE(gl_info)) {
909 gl_info->gl_card = CARD_ATI_RADEON_7200; /* Radeon 7000/7100/7200/7500 */
910 } else
911 gl_info->gl_card = CARD_ATI_RAGE_128PRO;
912 break;
913 case VENDOR_INTEL:
914 if (strstr(gl_info->gl_renderer, "915GM")) {
915 gl_info->gl_card = CARD_INTEL_I915GM;
916 } else if (strstr(gl_info->gl_renderer, "915G")) {
917 gl_info->gl_card = CARD_INTEL_I915G;
918 } else if (strstr(gl_info->gl_renderer, "865G")) {
919 gl_info->gl_card = CARD_INTEL_I865G;
920 } else if (strstr(gl_info->gl_renderer, "855G")) {
921 gl_info->gl_card = CARD_INTEL_I855G;
922 } else if (strstr(gl_info->gl_renderer, "830G")) {
923 gl_info->gl_card = CARD_INTEL_I830G;
924 } else {
925 gl_info->gl_card = CARD_INTEL_I915G;
927 break;
928 case VENDOR_MESA:
929 case VENDOR_WINE:
930 default:
931 /* Default to generic Nvidia hardware based on the supported OpenGL extensions. The choice
932 * for Nvidia was because the hardware and drivers they make are of good quality. This makes
933 * them a good generic choice.
935 gl_info->gl_vendor = VENDOR_NVIDIA;
936 if(WINE_D3D9_CAPABLE(gl_info))
937 gl_info->gl_card = CARD_NVIDIA_GEFORCEFX_5600;
938 else if(WINE_D3D8_CAPABLE(gl_info))
939 gl_info->gl_card = CARD_NVIDIA_GEFORCE3;
940 else if(WINE_D3D7_CAPABLE(gl_info))
941 gl_info->gl_card = CARD_NVIDIA_GEFORCE;
942 else if(WINE_D3D6_CAPABLE(gl_info))
943 gl_info->gl_card = CARD_NVIDIA_RIVA_TNT;
944 else
945 gl_info->gl_card = CARD_NVIDIA_RIVA_128;
947 TRACE("FOUND (fake) card: 0x%x (vendor id), 0x%x (device id)\n", gl_info->gl_vendor, gl_info->gl_card);
949 /* Load all the lookup tables
950 TODO: It may be a good idea to make minLookup and maxLookup const and populate them in wined3d_private.h where they are declared */
951 minLookup[WINELOOKUP_WARPPARAM] = WINED3DTADDRESS_WRAP;
952 maxLookup[WINELOOKUP_WARPPARAM] = WINED3DTADDRESS_MIRRORONCE;
954 minLookup[WINELOOKUP_MAGFILTER] = WINED3DTEXF_NONE;
955 maxLookup[WINELOOKUP_MAGFILTER] = WINED3DTEXF_ANISOTROPIC;
958 for (i = 0; i < MAX_LOOKUPS; i++) {
959 stateLookup[i] = HeapAlloc(GetProcessHeap(), 0, sizeof(*stateLookup[i]) * (1 + maxLookup[i] - minLookup[i]) );
962 stateLookup[WINELOOKUP_WARPPARAM][WINED3DTADDRESS_WRAP - minLookup[WINELOOKUP_WARPPARAM]] = GL_REPEAT;
963 stateLookup[WINELOOKUP_WARPPARAM][WINED3DTADDRESS_CLAMP - minLookup[WINELOOKUP_WARPPARAM]] = GL_CLAMP_TO_EDGE;
964 stateLookup[WINELOOKUP_WARPPARAM][WINED3DTADDRESS_BORDER - minLookup[WINELOOKUP_WARPPARAM]] =
965 gl_info->supported[ARB_TEXTURE_BORDER_CLAMP] ? GL_CLAMP_TO_BORDER_ARB : GL_REPEAT;
966 stateLookup[WINELOOKUP_WARPPARAM][WINED3DTADDRESS_BORDER - minLookup[WINELOOKUP_WARPPARAM]] =
967 gl_info->supported[ARB_TEXTURE_BORDER_CLAMP] ? GL_CLAMP_TO_BORDER_ARB : GL_REPEAT;
968 stateLookup[WINELOOKUP_WARPPARAM][WINED3DTADDRESS_MIRROR - minLookup[WINELOOKUP_WARPPARAM]] =
969 gl_info->supported[ARB_TEXTURE_MIRRORED_REPEAT] ? GL_MIRRORED_REPEAT_ARB : GL_REPEAT;
970 stateLookup[WINELOOKUP_WARPPARAM][WINED3DTADDRESS_MIRRORONCE - minLookup[WINELOOKUP_WARPPARAM]] =
971 gl_info->supported[ATI_TEXTURE_MIRROR_ONCE] ? GL_MIRROR_CLAMP_TO_EDGE_ATI : GL_REPEAT;
973 stateLookup[WINELOOKUP_MAGFILTER][WINED3DTEXF_NONE - minLookup[WINELOOKUP_MAGFILTER]] = GL_NEAREST;
974 stateLookup[WINELOOKUP_MAGFILTER][WINED3DTEXF_POINT - minLookup[WINELOOKUP_MAGFILTER]] = GL_NEAREST;
975 stateLookup[WINELOOKUP_MAGFILTER][WINED3DTEXF_LINEAR - minLookup[WINELOOKUP_MAGFILTER]] = GL_LINEAR;
976 stateLookup[WINELOOKUP_MAGFILTER][WINED3DTEXF_ANISOTROPIC - minLookup[WINELOOKUP_MAGFILTER]] =
977 gl_info->supported[EXT_TEXTURE_FILTER_ANISOTROPIC] ? GL_LINEAR : GL_NEAREST;
980 minMipLookup[WINED3DTEXF_NONE][WINED3DTEXF_NONE] = GL_LINEAR;
981 minMipLookup[WINED3DTEXF_NONE][WINED3DTEXF_POINT] = GL_LINEAR;
982 minMipLookup[WINED3DTEXF_NONE][WINED3DTEXF_LINEAR] = GL_LINEAR;
983 minMipLookup[WINED3DTEXF_POINT][WINED3DTEXF_NONE] = GL_NEAREST;
984 minMipLookup[WINED3DTEXF_POINT][WINED3DTEXF_POINT] = GL_NEAREST_MIPMAP_NEAREST;
985 minMipLookup[WINED3DTEXF_POINT][WINED3DTEXF_LINEAR] = GL_NEAREST_MIPMAP_LINEAR;
986 minMipLookup[WINED3DTEXF_LINEAR][WINED3DTEXF_NONE] = GL_LINEAR;
987 minMipLookup[WINED3DTEXF_LINEAR][WINED3DTEXF_POINT] = GL_LINEAR_MIPMAP_NEAREST;
988 minMipLookup[WINED3DTEXF_LINEAR][WINED3DTEXF_LINEAR] = GL_LINEAR_MIPMAP_LINEAR;
989 minMipLookup[WINED3DTEXF_ANISOTROPIC][WINED3DTEXF_NONE] = gl_info->supported[EXT_TEXTURE_FILTER_ANISOTROPIC] ?
990 GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR;
991 minMipLookup[WINED3DTEXF_ANISOTROPIC][WINED3DTEXF_POINT] = gl_info->supported[EXT_TEXTURE_FILTER_ANISOTROPIC] ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR;
992 minMipLookup[WINED3DTEXF_ANISOTROPIC][WINED3DTEXF_LINEAR] = gl_info->supported[EXT_TEXTURE_FILTER_ANISOTROPIC] ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR;
994 /* TODO: config lookups */
996 if (display != NULL) {
997 GLX_Extensions = glXQueryExtensionsString(display, DefaultScreen(display));
998 TRACE_(d3d_caps)("GLX_Extensions reported:\n");
1000 if (NULL == GLX_Extensions) {
1001 ERR(" GLX_Extensions returns NULL\n");
1002 } else {
1003 while (*GLX_Extensions != 0x00) {
1004 const char *Start = GLX_Extensions;
1005 char ThisExtn[256];
1007 memset(ThisExtn, 0x00, sizeof(ThisExtn));
1008 while (*GLX_Extensions != ' ' && *GLX_Extensions != 0x00) {
1009 GLX_Extensions++;
1011 memcpy(ThisExtn, Start, (GLX_Extensions - Start));
1012 TRACE_(d3d_caps)("- %s\n", ThisExtn);
1013 if (*GLX_Extensions == ' ') GLX_Extensions++;
1018 /* If we created a dummy context, throw it away */
1019 if (NULL != fake_ctx) WineD3D_ReleaseFakeGLContext(fake_ctx);
1021 /* Only save the values obtained when a display is provided */
1022 if (fake_ctx == NULL) {
1023 return TRUE;
1024 } else {
1025 return FALSE;
1029 /**********************************************************
1030 * IWineD3D implementation follows
1031 **********************************************************/
1033 static UINT WINAPI IWineD3DImpl_GetAdapterCount (IWineD3D *iface) {
1034 IWineD3DImpl *This = (IWineD3DImpl *)iface;
1036 /* FIXME: Set to one for now to imply the display */
1037 TRACE_(d3d_caps)("(%p): Mostly stub, only returns primary display\n", This);
1038 return 1;
1041 static HRESULT WINAPI IWineD3DImpl_RegisterSoftwareDevice(IWineD3D *iface, void* pInitializeFunction) {
1042 IWineD3DImpl *This = (IWineD3DImpl *)iface;
1043 FIXME("(%p)->(%p): stub\n", This, pInitializeFunction);
1044 return WINED3D_OK;
1047 static HMONITOR WINAPI IWineD3DImpl_GetAdapterMonitor(IWineD3D *iface, UINT Adapter) {
1048 IWineD3DImpl *This = (IWineD3DImpl *)iface;
1049 POINT pt = { -1, -1 };
1051 if (Adapter >= IWineD3DImpl_GetAdapterCount(iface)) {
1052 return NULL;
1055 FIXME_(d3d_caps)("(%p): returning the primary monitor for adapter %d\n", This, Adapter);
1056 return MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
1059 /* FIXME: GetAdapterModeCount and EnumAdapterModes currently only returns modes
1060 of the same bpp but different resolutions */
1062 /* Note: dx9 supplies a format. Calls from d3d8 supply WINED3DFMT_UNKNOWN */
1063 static UINT WINAPI IWineD3DImpl_GetAdapterModeCount(IWineD3D *iface, UINT Adapter, WINED3DFORMAT Format) {
1064 IWineD3DImpl *This = (IWineD3DImpl *)iface;
1065 TRACE_(d3d_caps)("(%p}->(Adapter: %d, Format: %s)\n", This, Adapter, debug_d3dformat(Format));
1067 if (Adapter >= IWineD3D_GetAdapterCount(iface)) {
1068 return 0;
1071 if (Adapter == 0) { /* Display */
1072 int i = 0;
1073 int j = 0;
1074 #if !defined( DEBUG_SINGLE_MODE )
1075 DEVMODEW DevModeW;
1077 /* Work out the current screen bpp */
1078 HDC hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1079 int bpp = GetDeviceCaps(hdc, BITSPIXEL);
1080 DeleteDC(hdc);
1082 while (EnumDisplaySettingsExW(NULL, j, &DevModeW, 0)) {
1083 j++;
1084 switch (Format)
1086 case WINED3DFMT_UNKNOWN:
1087 i++;
1088 break;
1089 case WINED3DFMT_X8R8G8B8:
1090 case WINED3DFMT_A8R8G8B8:
1091 if (min(DevModeW.dmBitsPerPel, bpp) == 32) i++;
1092 if (min(DevModeW.dmBitsPerPel, bpp) == 24) i++;
1093 break;
1094 case WINED3DFMT_X1R5G5B5:
1095 case WINED3DFMT_A1R5G5B5:
1096 case WINED3DFMT_R5G6B5:
1097 if (min(DevModeW.dmBitsPerPel, bpp) == 16) i++;
1098 break;
1099 default:
1100 /* Skip other modes as they do not match the requested format */
1101 break;
1104 #else
1105 i = 1;
1106 j = 1;
1107 #endif
1108 TRACE_(d3d_caps)("(%p}->(Adapter: %d) => %d (out of %d)\n", This, Adapter, i, j);
1109 return i;
1110 } else {
1111 FIXME_(d3d_caps)("Adapter not primary display\n");
1113 return 0;
1116 /* Note: dx9 supplies a format. Calls from d3d8 supply WINED3DFMT_UNKNOWN */
1117 static HRESULT WINAPI IWineD3DImpl_EnumAdapterModes(IWineD3D *iface, UINT Adapter, WINED3DFORMAT Format, UINT Mode, WINED3DDISPLAYMODE* pMode) {
1118 IWineD3DImpl *This = (IWineD3DImpl *)iface;
1119 TRACE_(d3d_caps)("(%p}->(Adapter:%d, mode:%d, pMode:%p, format:%s)\n", This, Adapter, Mode, pMode, debug_d3dformat(Format));
1121 /* Validate the parameters as much as possible */
1122 if (NULL == pMode ||
1123 Adapter >= IWineD3DImpl_GetAdapterCount(iface) ||
1124 Mode >= IWineD3DImpl_GetAdapterModeCount(iface, Adapter, Format)) {
1125 return WINED3DERR_INVALIDCALL;
1128 if (Adapter == 0) { /* Display */
1129 int bpp;
1130 #if !defined( DEBUG_SINGLE_MODE )
1131 DEVMODEW DevModeW;
1132 int ModeIdx = 0;
1134 /* Work out the current screen bpp */
1135 HDC hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1136 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1137 DeleteDC(hdc);
1139 /* If we are filtering to a specific format, then need to skip all unrelated
1140 modes, but if mode is irrelevant, then we can use the index directly */
1141 if (Format == WINED3DFMT_UNKNOWN)
1143 ModeIdx = Mode;
1144 } else {
1145 int i = 0;
1146 int j = 0;
1147 DEVMODEW DevModeWtmp;
1150 while (i<(Mode) && EnumDisplaySettingsExW(NULL, j, &DevModeWtmp, 0)) {
1151 j++;
1152 switch (Format)
1154 case WINED3DFMT_UNKNOWN:
1155 i++;
1156 break;
1157 case WINED3DFMT_X8R8G8B8:
1158 case WINED3DFMT_A8R8G8B8:
1159 if (min(DevModeWtmp.dmBitsPerPel, bpp) == 32) i++;
1160 if (min(DevModeWtmp.dmBitsPerPel, bpp) == 24) i++;
1161 break;
1162 case WINED3DFMT_X1R5G5B5:
1163 case WINED3DFMT_A1R5G5B5:
1164 case WINED3DFMT_R5G6B5:
1165 if (min(DevModeWtmp.dmBitsPerPel, bpp) == 16) i++;
1166 break;
1167 default:
1168 /* Skip other modes as they do not match requested format */
1169 break;
1172 ModeIdx = j;
1175 /* Now get the display mode via the calculated index */
1176 if (EnumDisplaySettingsExW(NULL, ModeIdx, &DevModeW, 0))
1178 pMode->Width = DevModeW.dmPelsWidth;
1179 pMode->Height = DevModeW.dmPelsHeight;
1180 bpp = min(DevModeW.dmBitsPerPel, bpp);
1181 pMode->RefreshRate = D3DADAPTER_DEFAULT;
1182 if (DevModeW.dmFields & DM_DISPLAYFREQUENCY)
1184 pMode->RefreshRate = DevModeW.dmDisplayFrequency;
1187 if (Format == WINED3DFMT_UNKNOWN)
1189 switch (bpp) {
1190 case 8: pMode->Format = WINED3DFMT_R3G3B2; break;
1191 case 16: pMode->Format = WINED3DFMT_R5G6B5; break;
1192 case 24: /* Robots and EVE Online need 24 and 32 bit as A8R8G8B8 to start */
1193 case 32: pMode->Format = WINED3DFMT_A8R8G8B8; break;
1194 default: pMode->Format = WINED3DFMT_UNKNOWN;
1196 } else {
1197 pMode->Format = Format;
1200 else
1202 TRACE_(d3d_caps)("Requested mode out of range %d\n", Mode);
1203 return WINED3DERR_INVALIDCALL;
1206 #else
1207 /* Return one setting of the format requested */
1208 if (Mode > 0) return WINED3DERR_INVALIDCALL;
1209 pMode->Width = 800;
1210 pMode->Height = 600;
1211 pMode->RefreshRate = D3DADAPTER_DEFAULT;
1212 pMode->Format = (Format == WINED3DFMT_UNKNOWN) ? WINED3DFMT_A8R8G8B8 : Format;
1213 bpp = 32;
1214 #endif
1215 TRACE_(d3d_caps)("W %d H %d rr %d fmt (%x - %s) bpp %u\n", pMode->Width, pMode->Height,
1216 pMode->RefreshRate, pMode->Format, debug_d3dformat(pMode->Format), bpp);
1218 } else {
1219 FIXME_(d3d_caps)("Adapter not primary display\n");
1222 return WINED3D_OK;
1225 static HRESULT WINAPI IWineD3DImpl_GetAdapterDisplayMode(IWineD3D *iface, UINT Adapter, WINED3DDISPLAYMODE* pMode) {
1226 IWineD3DImpl *This = (IWineD3DImpl *)iface;
1227 TRACE_(d3d_caps)("(%p}->(Adapter: %d, pMode: %p)\n", This, Adapter, pMode);
1229 if (NULL == pMode ||
1230 Adapter >= IWineD3D_GetAdapterCount(iface)) {
1231 return WINED3DERR_INVALIDCALL;
1234 if (Adapter == 0) { /* Display */
1235 int bpp = 0;
1236 DEVMODEW DevModeW;
1238 EnumDisplaySettingsExW(NULL, (DWORD)-1, &DevModeW, 0);
1239 pMode->Width = DevModeW.dmPelsWidth;
1240 pMode->Height = DevModeW.dmPelsHeight;
1241 bpp = DevModeW.dmBitsPerPel;
1242 pMode->RefreshRate = D3DADAPTER_DEFAULT;
1243 if (DevModeW.dmFields&DM_DISPLAYFREQUENCY)
1245 pMode->RefreshRate = DevModeW.dmDisplayFrequency;
1248 switch (bpp) {
1249 case 8: pMode->Format = WINED3DFMT_R3G3B2; break;
1250 case 16: pMode->Format = WINED3DFMT_R5G6B5; break;
1251 case 24: pMode->Format = WINED3DFMT_X8R8G8B8; break; /* Robots needs 24bit to be X8R8G8B8 */
1252 case 32: pMode->Format = WINED3DFMT_X8R8G8B8; break; /* EVE online and the Fur demo need 32bit AdapterDisplatMode to return X8R8G8B8 */
1253 default: pMode->Format = WINED3DFMT_UNKNOWN;
1256 } else {
1257 FIXME_(d3d_caps)("Adapter not primary display\n");
1260 TRACE_(d3d_caps)("returning w:%d, h:%d, ref:%d, fmt:%s\n", pMode->Width,
1261 pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1262 return WINED3D_OK;
1265 static Display * WINAPI IWineD3DImpl_GetAdapterDisplay(IWineD3D *iface, UINT Adapter) {
1266 Display *display;
1267 HDC device_context;
1268 /* only works with one adapter at the moment... */
1270 /* Get the display */
1271 device_context = GetDC(0);
1272 display = get_display(device_context);
1273 ReleaseDC(0, device_context);
1274 return display;
1277 /* NOTE: due to structure differences between dx8 and dx9 D3DADAPTER_IDENTIFIER,
1278 and fields being inserted in the middle, a new structure is used in place */
1279 static HRESULT WINAPI IWineD3DImpl_GetAdapterIdentifier(IWineD3D *iface, UINT Adapter, DWORD Flags,
1280 WINED3DADAPTER_IDENTIFIER* pIdentifier) {
1281 IWineD3DImpl *This = (IWineD3DImpl *)iface;
1283 TRACE_(d3d_caps)("(%p}->(Adapter: %d, Flags: %x, pId=%p)\n", This, Adapter, Flags, pIdentifier);
1285 if (Adapter >= IWineD3D_GetAdapterCount(iface)) {
1286 return WINED3DERR_INVALIDCALL;
1289 if (Adapter == 0) { /* Display - only device supported for now */
1291 BOOL isGLInfoValid = This->isGLInfoValid;
1293 /* FillGLCaps updates gl_info, but we only want to store and
1294 reuse the values once we have a context which is valid. Values from
1295 a temporary context may differ from the final ones */
1296 if (!isGLInfoValid) {
1297 WineD3D_Context *fake_ctx = NULL;
1298 if (glXGetCurrentContext() == NULL) fake_ctx = WineD3D_CreateFakeGLContext();
1299 /* If we don't know the device settings, go query them now */
1300 isGLInfoValid = IWineD3DImpl_FillGLCaps(iface, IWineD3DImpl_GetAdapterDisplay(iface, Adapter));
1301 if (fake_ctx != NULL) WineD3D_ReleaseFakeGLContext(fake_ctx);
1304 /* If it worked, return the information requested */
1305 if (isGLInfoValid) {
1306 TRACE_(d3d_caps)("device/Vendor Name and Version detection using FillGLCaps\n");
1307 strcpy(pIdentifier->Driver, "Display");
1308 strcpy(pIdentifier->Description, "Direct3D HAL");
1310 /* Note dx8 doesn't supply a DeviceName */
1311 if (NULL != pIdentifier->DeviceName) strcpy(pIdentifier->DeviceName, "\\\\.\\DISPLAY"); /* FIXME: May depend on desktop? */
1312 /* Current Windows drivers have versions like 6.14.... (some older have an earlier version) */
1313 pIdentifier->DriverVersion->u.HighPart = MAKEDWORD_VERSION(6, 14);
1314 pIdentifier->DriverVersion->u.LowPart = This->gl_info.gl_driver_version;
1315 *(pIdentifier->VendorId) = This->gl_info.gl_vendor;
1316 *(pIdentifier->DeviceId) = This->gl_info.gl_card;
1317 *(pIdentifier->SubSysId) = 0;
1318 *(pIdentifier->Revision) = 0;
1320 } else {
1322 /* If it failed, return dummy values from an NVidia driver */
1323 WARN_(d3d_caps)("Cannot get GLCaps for device/Vendor Name and Version detection using FillGLCaps, currently using NVIDIA identifiers\n");
1324 strcpy(pIdentifier->Driver, "Display");
1325 strcpy(pIdentifier->Description, "Direct3D HAL");
1326 if (NULL != pIdentifier->DeviceName) strcpy(pIdentifier->DeviceName, "\\\\.\\DISPLAY"); /* FIXME: May depend on desktop? */
1327 /* Current Windows Nvidia drivers have versions like e.g. 6.14.10.5672 */
1328 pIdentifier->DriverVersion->u.HighPart = MAKEDWORD_VERSION(6, 14);
1329 /* 71.74 is a current Linux Nvidia driver version */
1330 pIdentifier->DriverVersion->u.LowPart = MAKEDWORD_VERSION(10, (71*100+74));
1331 *(pIdentifier->VendorId) = VENDOR_NVIDIA;
1332 *(pIdentifier->DeviceId) = CARD_NVIDIA_GEFORCE4_TI4200;
1333 *(pIdentifier->SubSysId) = 0;
1334 *(pIdentifier->Revision) = 0;
1337 /*FIXME: memcpy(&pIdentifier->DeviceIdentifier, ??, sizeof(??GUID)); */
1338 if (Flags & D3DENUM_NO_WHQL_LEVEL) {
1339 *(pIdentifier->WHQLLevel) = 0;
1340 } else {
1341 *(pIdentifier->WHQLLevel) = 1;
1344 } else {
1345 FIXME_(d3d_caps)("Adapter not primary display\n");
1348 return WINED3D_OK;
1351 static BOOL IWineD3DImpl_IsGLXFBConfigCompatibleWithRenderFmt(Display *display, GLXFBConfig cfgs, WINED3DFORMAT Format) {
1352 #if 0 /* This code performs a strict test between the format and the current X11 buffer depth, which may give the best performance */
1353 int gl_test;
1354 int rb, gb, bb, ab, type, buf_sz;
1356 gl_test = glXGetFBConfigAttrib(display, cfgs, GLX_RED_SIZE, &rb);
1357 gl_test = glXGetFBConfigAttrib(display, cfgs, GLX_GREEN_SIZE, &gb);
1358 gl_test = glXGetFBConfigAttrib(display, cfgs, GLX_BLUE_SIZE, &bb);
1359 gl_test = glXGetFBConfigAttrib(display, cfgs, GLX_ALPHA_SIZE, &ab);
1360 gl_test = glXGetFBConfigAttrib(display, cfgs, GLX_RENDER_TYPE, &type);
1361 gl_test = glXGetFBConfigAttrib(display, cfgs, GLX_BUFFER_SIZE, &buf_sz);
1363 switch (Format) {
1364 case WINED3DFMT_X8R8G8B8:
1365 case WINED3DFMT_R8G8B8:
1366 if (8 == rb && 8 == gb && 8 == bb) return TRUE;
1367 break;
1368 case WINED3DFMT_A8R8G8B8:
1369 if (8 == rb && 8 == gb && 8 == bb && 8 == ab) return TRUE;
1370 break;
1371 case WINED3DFMT_A2R10G10B10:
1372 if (10 == rb && 10 == gb && 10 == bb && 2 == ab) return TRUE;
1373 break;
1374 case WINED3DFMT_X1R5G5B5:
1375 if (5 == rb && 5 == gb && 5 == bb) return TRUE;
1376 break;
1377 case WINED3DFMT_A1R5G5B5:
1378 if (5 == rb && 5 == gb && 5 == bb && 1 == ab) return TRUE;
1379 break;
1380 case WINED3DFMT_X4R4G4B4:
1381 if (16 == buf_sz && 4 == rb && 4 == gb && 4 == bb) return TRUE;
1382 break;
1383 case WINED3DFMT_R5G6B5:
1384 if (5 == rb && 6 == gb && 5 == bb) return TRUE;
1385 break;
1386 case WINED3DFMT_R3G3B2:
1387 if (3 == rb && 3 == gb && 2 == bb) return TRUE;
1388 break;
1389 case WINED3DFMT_A8P8:
1390 if (type & GLX_COLOR_INDEX_BIT && 8 == buf_sz && 8 == ab) return TRUE;
1391 break;
1392 case WINED3DFMT_P8:
1393 if (type & GLX_COLOR_INDEX_BIT && 8 == buf_sz) return TRUE;
1394 break;
1395 default:
1396 ERR("unsupported format %s\n", debug_d3dformat(Format));
1397 break;
1399 return FALSE;
1400 #else /* Most of the time performance is less of an issue than compatibility, this code allows for most common opengl/d3d formats */
1401 switch (Format) {
1402 case WINED3DFMT_X8R8G8B8:
1403 case WINED3DFMT_R8G8B8:
1404 case WINED3DFMT_A8R8G8B8:
1405 case WINED3DFMT_A2R10G10B10:
1406 case WINED3DFMT_X1R5G5B5:
1407 case WINED3DFMT_A1R5G5B5:
1408 case WINED3DFMT_R5G6B5:
1409 case WINED3DFMT_R3G3B2:
1410 case WINED3DFMT_A8P8:
1411 case WINED3DFMT_P8:
1412 return TRUE;
1413 default:
1414 ERR("unsupported format %s\n", debug_d3dformat(Format));
1415 break;
1417 return FALSE;
1418 #endif
1421 static BOOL IWineD3DImpl_IsGLXFBConfigCompatibleWithDepthFmt(Display *display, GLXFBConfig cfgs, WINED3DFORMAT Format) {
1422 #if 0/* This code performs a strict test between the format and the current X11 buffer depth, which may give the best performance */
1423 int gl_test;
1424 int db, sb;
1426 gl_test = glXGetFBConfigAttrib(display, cfgs, GLX_DEPTH_SIZE, &db);
1427 gl_test = glXGetFBConfigAttrib(display, cfgs, GLX_STENCIL_SIZE, &sb);
1429 switch (Format) {
1430 case WINED3DFMT_D16:
1431 case WINED3DFMT_D16_LOCKABLE:
1432 if (16 == db) return TRUE;
1433 break;
1434 case WINED3DFMT_D32:
1435 if (32 == db) return TRUE;
1436 break;
1437 case WINED3DFMT_D15S1:
1438 if (15 == db) return TRUE;
1439 break;
1440 case WINED3DFMT_D24S8:
1441 if (24 == db && 8 == sb) return TRUE;
1442 break;
1443 case WINED3DFMT_D24FS8:
1444 if (24 == db && 8 == sb) return TRUE;
1445 break;
1446 case WINED3DFMT_D24X8:
1447 if (24 == db) return TRUE;
1448 break;
1449 case WINED3DFMT_D24X4S4:
1450 if (24 == db && 4 == sb) return TRUE;
1451 break;
1452 case WINED3DFMT_D32F_LOCKABLE:
1453 if (32 == db) return TRUE;
1454 break;
1455 default:
1456 ERR("unsupported format %s\n", debug_d3dformat(Format));
1457 break;
1459 return FALSE;
1460 #else /* Most of the time performance is less of an issue than compatibility, this code allows for most common opengl/d3d formats */
1461 switch (Format) {
1462 case WINED3DFMT_D16:
1463 case WINED3DFMT_D16_LOCKABLE:
1464 case WINED3DFMT_D32:
1465 case WINED3DFMT_D15S1:
1466 case WINED3DFMT_D24S8:
1467 case WINED3DFMT_D24FS8:
1468 case WINED3DFMT_D24X8:
1469 case WINED3DFMT_D24X4S4:
1470 case WINED3DFMT_D32F_LOCKABLE:
1471 return TRUE;
1472 default:
1473 ERR("unsupported format %s\n", debug_d3dformat(Format));
1474 break;
1476 return FALSE;
1477 #endif
1480 static HRESULT WINAPI IWineD3DImpl_CheckDepthStencilMatch(IWineD3D *iface, UINT Adapter, WINED3DDEVTYPE DeviceType,
1481 WINED3DFORMAT AdapterFormat,
1482 WINED3DFORMAT RenderTargetFormat,
1483 WINED3DFORMAT DepthStencilFormat) {
1484 IWineD3DImpl *This = (IWineD3DImpl *)iface;
1485 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1486 WineD3D_Context* ctx = NULL;
1487 GLXFBConfig* cfgs = NULL;
1488 int nCfgs = 0;
1489 int it;
1491 WARN_(d3d_caps)("(%p)-> (STUB) (Adptr:%d, DevType:(%x,%s), AdptFmt:(%x,%s), RendrTgtFmt:(%x,%s), DepthStencilFmt:(%x,%s))\n",
1492 This, Adapter,
1493 DeviceType, debug_d3ddevicetype(DeviceType),
1494 AdapterFormat, debug_d3dformat(AdapterFormat),
1495 RenderTargetFormat, debug_d3dformat(RenderTargetFormat),
1496 DepthStencilFormat, debug_d3dformat(DepthStencilFormat));
1498 if (Adapter >= IWineD3D_GetAdapterCount(iface)) {
1499 TRACE("(%p) Failed: Atapter (%u) higher than supported adapters (%u) returning WINED3DERR_INVALIDCALL\n", This, Adapter, IWineD3D_GetAdapterCount(iface));
1500 return WINED3DERR_INVALIDCALL;
1502 /* TODO: use the real context if it's available */
1503 ctx = WineD3D_CreateFakeGLContext();
1504 if(NULL != ctx) {
1505 cfgs = glXGetFBConfigs(ctx->display, DefaultScreen(ctx->display), &nCfgs);
1506 } else {
1507 TRACE_(d3d_caps)("(%p) : Unable to create a fake context at this time (there may already be an active context)\n", This);
1510 if (NULL != cfgs) {
1511 for (it = 0; it < nCfgs; ++it) {
1512 if (IWineD3DImpl_IsGLXFBConfigCompatibleWithRenderFmt(ctx->display, cfgs[it], RenderTargetFormat)) {
1513 if (IWineD3DImpl_IsGLXFBConfigCompatibleWithDepthFmt(ctx->display, cfgs[it], DepthStencilFormat)) {
1514 hr = WINED3D_OK;
1515 break ;
1519 XFree(cfgs);
1520 cfgs = NULL;
1521 } else {
1522 /* If there's a current context then we cannot create a fake one so pass everything */
1523 hr = WINED3D_OK;
1526 if (ctx != NULL)
1527 WineD3D_ReleaseFakeGLContext(ctx);
1529 if (hr != WINED3D_OK)
1530 TRACE_(d3d_caps)("Failed to match stencil format to device\n");
1532 TRACE_(d3d_caps)("(%p) : Returning %x\n", This, hr);
1533 return hr;
1536 static HRESULT WINAPI IWineD3DImpl_CheckDeviceMultiSampleType(IWineD3D *iface, UINT Adapter, WINED3DDEVTYPE DeviceType,
1537 WINED3DFORMAT SurfaceFormat,
1538 BOOL Windowed, WINED3DMULTISAMPLE_TYPE MultiSampleType, DWORD* pQualityLevels) {
1540 IWineD3DImpl *This = (IWineD3DImpl *)iface;
1541 TRACE_(d3d_caps)("(%p)-> (STUB) (Adptr:%d, DevType:(%x,%s), SurfFmt:(%x,%s), Win?%d, MultiSamp:%x, pQual:%p)\n",
1542 This,
1543 Adapter,
1544 DeviceType, debug_d3ddevicetype(DeviceType),
1545 SurfaceFormat, debug_d3dformat(SurfaceFormat),
1546 Windowed,
1547 MultiSampleType,
1548 pQualityLevels);
1550 if (Adapter >= IWineD3D_GetAdapterCount(iface)) {
1551 return WINED3DERR_INVALIDCALL;
1554 if (pQualityLevels != NULL) {
1555 static int s_single_shot = 0;
1556 if (!s_single_shot) {
1557 FIXME("Quality levels unsupported at present\n");
1558 s_single_shot = 1;
1560 *pQualityLevels = 1; /* Guess at a value! */
1563 if (WINED3DMULTISAMPLE_NONE == MultiSampleType) return WINED3D_OK;
1564 return WINED3DERR_NOTAVAILABLE;
1567 static HRESULT WINAPI IWineD3DImpl_CheckDeviceType(IWineD3D *iface, UINT Adapter, WINED3DDEVTYPE CheckType,
1568 WINED3DFORMAT DisplayFormat, WINED3DFORMAT BackBufferFormat, BOOL Windowed) {
1570 IWineD3DImpl *This = (IWineD3DImpl *)iface;
1571 GLXFBConfig* cfgs = NULL;
1572 int nCfgs = 0;
1573 int it;
1574 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1575 WineD3D_Context* ctx;
1577 TRACE_(d3d_caps)("(%p)-> (STUB) (Adptr:%d, CheckType:(%x,%s), DispFmt:(%x,%s), BackBuf:(%x,%s), Win?%d): stub\n",
1578 This,
1579 Adapter,
1580 CheckType, debug_d3ddevicetype(CheckType),
1581 DisplayFormat, debug_d3dformat(DisplayFormat),
1582 BackBufferFormat, debug_d3dformat(BackBufferFormat),
1583 Windowed);
1585 if (Adapter >= IWineD3D_GetAdapterCount(iface)) {
1586 WARN_(d3d_caps)("Adapter >= IWineD3D_GetAdapterCount(iface), returning WINED3DERR_INVALIDCALL\n");
1587 return WINED3DERR_INVALIDCALL;
1590 ctx = WineD3D_CreateFakeGLContext();
1591 if (NULL != ctx) {
1592 cfgs = glXGetFBConfigs(ctx->display, DefaultScreen(ctx->display), &nCfgs);
1593 for (it = 0; it < nCfgs; ++it) {
1594 if (IWineD3DImpl_IsGLXFBConfigCompatibleWithRenderFmt(ctx->display, cfgs[it], DisplayFormat)) {
1595 hr = WINED3D_OK;
1596 TRACE_(d3d_caps)("OK\n");
1597 break ;
1600 if(cfgs) XFree(cfgs);
1601 WineD3D_ReleaseFakeGLContext(ctx);
1604 if(hr != WINED3D_OK)
1605 TRACE_(d3d_caps)("returning something different from WINED3D_OK\n");
1607 return hr;
1610 static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapter, WINED3DDEVTYPE DeviceType,
1611 WINED3DFORMAT AdapterFormat, DWORD Usage, WINED3DRESOURCETYPE RType, WINED3DFORMAT CheckFormat) {
1612 IWineD3DImpl *This = (IWineD3DImpl *)iface;
1613 TRACE_(d3d_caps)("(%p)-> (STUB) (Adptr:%d, DevType:(%u,%s), AdptFmt:(%u,%s), Use:(%u,%s,%s), ResTyp:(%x,%s), CheckFmt:(%u,%s))\n",
1614 This,
1615 Adapter,
1616 DeviceType, debug_d3ddevicetype(DeviceType),
1617 AdapterFormat, debug_d3dformat(AdapterFormat),
1618 Usage, debug_d3dusage(Usage), debug_d3dusagequery(Usage),
1619 RType, debug_d3dresourcetype(RType),
1620 CheckFormat, debug_d3dformat(CheckFormat));
1622 if (Adapter >= IWineD3D_GetAdapterCount(iface)) {
1623 return WINED3DERR_INVALIDCALL;
1626 /* TODO: Check support against more of the WINED3DUSAGE_QUERY_* constants
1627 * See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/IDirect3D9__CheckDeviceFormat.asp
1628 * and http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/D3DUSAGE_QUERY.asp */
1629 if (Usage & WINED3DUSAGE_QUERY_VERTEXTEXTURE) {
1630 TRACE_(d3d_caps)("[FAILED]\n");
1631 return WINED3DERR_NOTAVAILABLE; /* Enable when fully supported */
1634 if(Usage & WINED3DUSAGE_DEPTHSTENCIL) {
1635 switch (CheckFormat) {
1636 case WINED3DFMT_D16_LOCKABLE:
1637 case WINED3DFMT_D32:
1638 case WINED3DFMT_D15S1:
1639 case WINED3DFMT_D24S8:
1640 case WINED3DFMT_D24X8:
1641 case WINED3DFMT_D24X4S4:
1642 case WINED3DFMT_D16:
1643 case WINED3DFMT_L16:
1644 case WINED3DFMT_D32F_LOCKABLE:
1645 case WINED3DFMT_D24FS8:
1646 TRACE_(d3d_caps)("[OK]\n");
1647 return WINED3D_OK;
1648 default:
1649 TRACE_(d3d_caps)("[FAILED]\n");
1650 return WINED3DERR_NOTAVAILABLE;
1652 } else if(Usage & WINED3DUSAGE_RENDERTARGET) {
1653 switch (CheckFormat) {
1654 case WINED3DFMT_R8G8B8:
1655 case WINED3DFMT_A8R8G8B8:
1656 case WINED3DFMT_X8R8G8B8:
1657 case WINED3DFMT_R5G6B5:
1658 case WINED3DFMT_X1R5G5B5:
1659 case WINED3DFMT_A1R5G5B5:
1660 case WINED3DFMT_A4R4G4B4:
1661 case WINED3DFMT_R3G3B2:
1662 case WINED3DFMT_X4R4G4B4:
1663 case WINED3DFMT_A8B8G8R8:
1664 case WINED3DFMT_X8B8G8R8:
1665 case WINED3DFMT_P8:
1666 TRACE_(d3d_caps)("[OK]\n");
1667 return WINED3D_OK;
1668 default:
1669 TRACE_(d3d_caps)("[FAILED]\n");
1670 return WINED3DERR_NOTAVAILABLE;
1674 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
1675 switch (CheckFormat) {
1676 case WINED3DFMT_DXT1:
1677 case WINED3DFMT_DXT2:
1678 case WINED3DFMT_DXT3:
1679 case WINED3DFMT_DXT4:
1680 case WINED3DFMT_DXT5:
1681 TRACE_(d3d_caps)("[OK]\n");
1682 return WINED3D_OK;
1683 default:
1684 break; /* Avoid compiler warnings */
1688 if (GL_SUPPORT(ARB_TEXTURE_FLOAT)) {
1690 BOOL half_pixel_support = GL_SUPPORT(ARB_HALF_FLOAT_PIXEL);
1692 switch (CheckFormat) {
1693 case WINED3DFMT_R16F:
1694 case WINED3DFMT_A16B16G16R16F:
1695 if (!half_pixel_support) break;
1696 case WINED3DFMT_R32F:
1697 case WINED3DFMT_A32B32G32R32F:
1698 TRACE_(d3d_caps)("[OK]\n");
1699 return WINED3D_OK;
1700 default:
1701 break; /* Avoid compiler warnings */
1705 /* This format is nothing special and it is supported perfectly.
1706 * However, ati and nvidia driver on windows do not mark this format as
1707 * supported (tested with the dxCapsViewer) and pretending to
1708 * support this format uncovers a bug in Battlefield 1942 (fonts are missing)
1709 * So do the same as Windows drivers and pretend not to support it on dx8 and 9
1710 * Enable it on dx7. It will need additional checking on dx10 when we support it.
1712 if(This->dxVersion > 7 && CheckFormat == WINED3DFMT_R8G8B8) {
1713 TRACE_(d3d_caps)("[FAILED]\n");
1714 return WINED3DERR_NOTAVAILABLE;
1717 switch (CheckFormat) {
1719 /*****
1720 * supported: RGB(A) formats
1722 case WINED3DFMT_R8G8B8: /* Enable for dx7, blacklisted for 8 and 9 above */
1723 case WINED3DFMT_A8R8G8B8:
1724 case WINED3DFMT_X8R8G8B8:
1725 case WINED3DFMT_R5G6B5:
1726 case WINED3DFMT_X1R5G5B5:
1727 case WINED3DFMT_A1R5G5B5:
1728 case WINED3DFMT_A4R4G4B4:
1729 case WINED3DFMT_R3G3B2:
1730 case WINED3DFMT_A8:
1731 case WINED3DFMT_A8R3G3B2:
1732 case WINED3DFMT_X4R4G4B4:
1733 case WINED3DFMT_A8B8G8R8:
1734 case WINED3DFMT_X8B8G8R8:
1735 case WINED3DFMT_A2R10G10B10:
1736 case WINED3DFMT_A2B10G10R10:
1737 TRACE_(d3d_caps)("[OK]\n");
1738 return WINED3D_OK;
1740 /*****
1741 * supported: Palettized
1743 case WINED3DFMT_P8:
1744 TRACE_(d3d_caps)("[OK]\n");
1745 return WINED3D_OK;
1747 /*****
1748 * Supported: (Alpha)-Luminance
1750 case WINED3DFMT_L8:
1751 case WINED3DFMT_A8L8:
1752 case WINED3DFMT_A4L4:
1753 TRACE_(d3d_caps)("[OK]\n");
1754 return WINED3D_OK;
1756 /*****
1757 * Not supported for now: Bump mapping formats
1758 * Enable some because games often fail when they are not available
1759 * and are still playable even without bump mapping
1761 case WINED3DFMT_V8U8:
1762 case WINED3DFMT_V16U16:
1763 case WINED3DFMT_L6V5U5:
1764 case WINED3DFMT_X8L8V8U8:
1765 case WINED3DFMT_Q8W8V8U8:
1766 case WINED3DFMT_W11V11U10:
1767 case WINED3DFMT_A2W10V10U10:
1768 WARN_(d3d_caps)("[Not supported, but pretended to do]\n");
1769 return WINED3D_OK;
1771 /*****
1772 * DXTN Formats: Handled above
1773 * WINED3DFMT_DXT1
1774 * WINED3DFMT_DXT2
1775 * WINED3DFMT_DXT3
1776 * WINED3DFMT_DXT4
1777 * WINED3DFMT_DXT5
1780 /*****
1781 * Odd formats - not supported
1783 case WINED3DFMT_VERTEXDATA:
1784 case WINED3DFMT_INDEX16:
1785 case WINED3DFMT_INDEX32:
1786 case WINED3DFMT_Q16W16V16U16:
1787 TRACE_(d3d_caps)("[FAILED]\n"); /* Enable when implemented */
1788 return WINED3DERR_NOTAVAILABLE;
1790 /*****
1791 * Float formats: Not supported right now
1793 case WINED3DFMT_G16R16F:
1794 case WINED3DFMT_G32R32F:
1795 case WINED3DFMT_CxV8U8:
1796 TRACE_(d3d_caps)("[FAILED]\n"); /* Enable when implemented */
1797 return WINED3DERR_NOTAVAILABLE;
1799 /* Not supported */
1800 case WINED3DFMT_G16R16:
1801 case WINED3DFMT_A16B16G16R16:
1802 TRACE_(d3d_caps)("[FAILED]\n"); /* Enable when implemented */
1803 return WINED3DERR_NOTAVAILABLE;
1805 default:
1806 break;
1809 TRACE_(d3d_caps)("[FAILED]\n");
1810 return WINED3DERR_NOTAVAILABLE;
1813 static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormatConversion(IWineD3D *iface, UINT Adapter, WINED3DDEVTYPE DeviceType,
1814 WINED3DFORMAT SourceFormat, WINED3DFORMAT TargetFormat) {
1815 IWineD3DImpl *This = (IWineD3DImpl *)iface;
1817 FIXME_(d3d_caps)("(%p)-> (STUB) (Adptr:%d, DevType:(%u,%s), SrcFmt:(%u,%s), TgtFmt:(%u,%s))\n",
1818 This,
1819 Adapter,
1820 DeviceType, debug_d3ddevicetype(DeviceType),
1821 SourceFormat, debug_d3dformat(SourceFormat),
1822 TargetFormat, debug_d3dformat(TargetFormat));
1823 return WINED3D_OK;
1826 /* Note: d3d8 passes in a pointer to a D3DCAPS8 structure, which is a true
1827 subset of a D3DCAPS9 structure. However, it has to come via a void *
1828 as the d3d8 interface cannot import the d3d9 header */
1829 static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, WINED3DDEVTYPE DeviceType, WINED3DCAPS* pCaps) {
1831 IWineD3DImpl *This = (IWineD3DImpl *)iface;
1832 int vs_selected_mode;
1833 int ps_selected_mode;
1835 TRACE_(d3d_caps)("(%p)->(Adptr:%d, DevType: %x, pCaps: %p)\n", This, Adapter, DeviceType, pCaps);
1837 if (Adapter >= IWineD3D_GetAdapterCount(iface)) {
1838 return WINED3DERR_INVALIDCALL;
1841 /* FIXME: GL info should be per adapter */
1843 /* If we don't know the device settings, go query them now */
1844 if (!This->isGLInfoValid) {
1845 /* use the desktop window to fill gl caps */
1846 BOOL rc = IWineD3DImpl_FillGLCaps(iface, IWineD3DImpl_GetAdapterDisplay(iface, Adapter));
1848 /* We are running off a real context, save the values */
1849 if (rc) This->isGLInfoValid = TRUE;
1851 select_shader_mode(&This->gl_info, DeviceType, &ps_selected_mode, &vs_selected_mode);
1853 /* This function should *not* be modifying GL caps
1854 * TODO: move the functionality where it belongs */
1855 select_shader_max_constants(ps_selected_mode, vs_selected_mode, &This->gl_info);
1857 /* ------------------------------------------------
1858 The following fields apply to both d3d8 and d3d9
1859 ------------------------------------------------ */
1860 *pCaps->DeviceType = (DeviceType == WINED3DDEVTYPE_HAL) ? WINED3DDEVTYPE_HAL : WINED3DDEVTYPE_REF; /* Not quite true, but use h/w supported by opengl I suppose */
1861 *pCaps->AdapterOrdinal = Adapter;
1863 *pCaps->Caps = 0;
1864 *pCaps->Caps2 = WINED3DCAPS2_CANRENDERWINDOWED |
1865 WINED3DCAPS2_FULLSCREENGAMMA;
1866 *pCaps->Caps3 = 0;
1867 *pCaps->PresentationIntervals = D3DPRESENT_INTERVAL_IMMEDIATE;
1869 *pCaps->CursorCaps = 0;
1872 *pCaps->DevCaps = WINED3DDEVCAPS_FLOATTLVERTEX |
1873 WINED3DDEVCAPS_EXECUTESYSTEMMEMORY |
1874 WINED3DDEVCAPS_TLVERTEXSYSTEMMEMORY|
1875 WINED3DDEVCAPS_TLVERTEXVIDEOMEMORY |
1876 WINED3DDEVCAPS_DRAWPRIMTLVERTEX |
1877 WINED3DDEVCAPS_HWTRANSFORMANDLIGHT |
1878 WINED3DDEVCAPS_EXECUTEVIDEOMEMORY |
1879 WINED3DDEVCAPS_PUREDEVICE |
1880 WINED3DDEVCAPS_HWRASTERIZATION |
1881 WINED3DDEVCAPS_TEXTUREVIDEOMEMORY |
1882 WINED3DDEVCAPS_TEXTURESYSTEMMEMORY |
1883 WINED3DDEVCAPS_CANRENDERAFTERFLIP |
1884 WINED3DDEVCAPS_DRAWPRIMITIVES2 |
1885 WINED3DDEVCAPS_DRAWPRIMITIVES2EX;
1887 *pCaps->PrimitiveMiscCaps = D3DPMISCCAPS_CULLNONE |
1888 D3DPMISCCAPS_CULLCCW |
1889 D3DPMISCCAPS_CULLCW |
1890 D3DPMISCCAPS_COLORWRITEENABLE |
1891 D3DPMISCCAPS_CLIPTLVERTS |
1892 D3DPMISCCAPS_CLIPPLANESCALEDPOINTS |
1893 D3DPMISCCAPS_MASKZ |
1894 D3DPMISCCAPS_BLENDOP;
1895 /* TODO:
1896 D3DPMISCCAPS_NULLREFERENCE
1897 D3DPMISCCAPS_INDEPENDENTWRITEMASKS
1898 D3DPMISCCAPS_FOGANDSPECULARALPHA
1899 D3DPMISCCAPS_SEPARATEALPHABLEND
1900 D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS
1901 D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING
1902 D3DPMISCCAPS_FOGVERTEXCLAMPED */
1904 /* The caps below can be supported but aren't handled yet in utils.c 'd3dta_to_combiner_input', disable them until support is fixed */
1905 #if 0
1906 if (GL_SUPPORT(NV_REGISTER_COMBINERS))
1907 *pCaps->PrimitiveMiscCaps |= D3DPMISCCAPS_TSSARGTEMP;
1908 if (GL_SUPPORT(NV_REGISTER_COMBINERS2))
1909 *pCaps->PrimitiveMiscCaps |= D3DPMISCCAPS_PERSTAGECONSTANT;
1910 #endif
1912 *pCaps->RasterCaps = WINED3DPRASTERCAPS_DITHER |
1913 WINED3DPRASTERCAPS_PAT |
1914 WINED3DPRASTERCAPS_WFOG |
1915 WINED3DPRASTERCAPS_ZFOG |
1916 WINED3DPRASTERCAPS_FOGVERTEX |
1917 WINED3DPRASTERCAPS_FOGTABLE |
1918 WINED3DPRASTERCAPS_FOGRANGE |
1919 WINED3DPRASTERCAPS_STIPPLE |
1920 WINED3DPRASTERCAPS_SUBPIXEL |
1921 WINED3DPRASTERCAPS_ZTEST |
1922 WINED3DPRASTERCAPS_SCISSORTEST |
1923 WINED3DPRASTERCAPS_SLOPESCALEDEPTHBIAS |
1924 WINED3DPRASTERCAPS_DEPTHBIAS;
1926 if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC)) {
1927 *pCaps->RasterCaps |= WINED3DPRASTERCAPS_ANISOTROPY |
1928 WINED3DPRASTERCAPS_ZBIAS |
1929 WINED3DPRASTERCAPS_MIPMAPLODBIAS;
1931 /* FIXME Add:
1932 WINED3DPRASTERCAPS_COLORPERSPECTIVE
1933 WINED3DPRASTERCAPS_STRETCHBLTMULTISAMPLE
1934 WINED3DPRASTERCAPS_ANTIALIASEDGES
1935 WINED3DPRASTERCAPS_ZBUFFERLESSHSR
1936 WINED3DPRASTERCAPS_WBUFFER */
1938 *pCaps->ZCmpCaps = D3DPCMPCAPS_ALWAYS |
1939 D3DPCMPCAPS_EQUAL |
1940 D3DPCMPCAPS_GREATER |
1941 D3DPCMPCAPS_GREATEREQUAL |
1942 D3DPCMPCAPS_LESS |
1943 D3DPCMPCAPS_LESSEQUAL |
1944 D3DPCMPCAPS_NEVER |
1945 D3DPCMPCAPS_NOTEQUAL;
1947 *pCaps->SrcBlendCaps = D3DPBLENDCAPS_BLENDFACTOR |
1948 D3DPBLENDCAPS_BOTHINVSRCALPHA |
1949 D3DPBLENDCAPS_BOTHSRCALPHA |
1950 D3DPBLENDCAPS_DESTALPHA |
1951 D3DPBLENDCAPS_DESTCOLOR |
1952 D3DPBLENDCAPS_INVDESTALPHA |
1953 D3DPBLENDCAPS_INVDESTCOLOR |
1954 D3DPBLENDCAPS_INVSRCALPHA |
1955 D3DPBLENDCAPS_INVSRCCOLOR |
1956 D3DPBLENDCAPS_ONE |
1957 D3DPBLENDCAPS_SRCALPHA |
1958 D3DPBLENDCAPS_SRCALPHASAT |
1959 D3DPBLENDCAPS_SRCCOLOR |
1960 D3DPBLENDCAPS_ZERO;
1962 *pCaps->DestBlendCaps = D3DPBLENDCAPS_BLENDFACTOR |
1963 D3DPBLENDCAPS_BOTHINVSRCALPHA |
1964 D3DPBLENDCAPS_BOTHSRCALPHA |
1965 D3DPBLENDCAPS_DESTALPHA |
1966 D3DPBLENDCAPS_DESTCOLOR |
1967 D3DPBLENDCAPS_INVDESTALPHA |
1968 D3DPBLENDCAPS_INVDESTCOLOR |
1969 D3DPBLENDCAPS_INVSRCALPHA |
1970 D3DPBLENDCAPS_INVSRCCOLOR |
1971 D3DPBLENDCAPS_ONE |
1972 D3DPBLENDCAPS_SRCALPHA |
1973 D3DPBLENDCAPS_SRCALPHASAT |
1974 D3DPBLENDCAPS_SRCCOLOR |
1975 D3DPBLENDCAPS_ZERO;
1977 *pCaps->AlphaCmpCaps = D3DPCMPCAPS_ALWAYS |
1978 D3DPCMPCAPS_EQUAL |
1979 D3DPCMPCAPS_GREATER |
1980 D3DPCMPCAPS_GREATEREQUAL |
1981 D3DPCMPCAPS_LESS |
1982 D3DPCMPCAPS_LESSEQUAL |
1983 D3DPCMPCAPS_NEVER |
1984 D3DPCMPCAPS_NOTEQUAL;
1986 *pCaps->ShadeCaps = WINED3DPSHADECAPS_SPECULARGOURAUDRGB |
1987 WINED3DPSHADECAPS_COLORGOURAUDRGB |
1988 WINED3DPSHADECAPS_ALPHAFLATBLEND |
1989 WINED3DPSHADECAPS_ALPHAGOURAUDBLEND |
1990 WINED3DPSHADECAPS_COLORFLATRGB |
1991 WINED3DPSHADECAPS_FOGFLAT |
1992 WINED3DPSHADECAPS_FOGGOURAUD |
1993 WINED3DPSHADECAPS_SPECULARFLATRGB;
1995 *pCaps->TextureCaps = WINED3DPTEXTURECAPS_ALPHA |
1996 WINED3DPTEXTURECAPS_ALPHAPALETTE |
1997 WINED3DPTEXTURECAPS_BORDER |
1998 WINED3DPTEXTURECAPS_MIPMAP |
1999 WINED3DPTEXTURECAPS_PROJECTED |
2000 WINED3DPTEXTURECAPS_PERSPECTIVE |
2001 WINED3DPTEXTURECAPS_NONPOW2CONDITIONAL;
2003 if( GL_SUPPORT(EXT_TEXTURE3D)) {
2004 *pCaps->TextureCaps |= WINED3DPTEXTURECAPS_VOLUMEMAP |
2005 WINED3DPTEXTURECAPS_MIPVOLUMEMAP |
2006 WINED3DPTEXTURECAPS_VOLUMEMAP_POW2;
2009 if (GL_SUPPORT(ARB_TEXTURE_CUBE_MAP)) {
2010 *pCaps->TextureCaps |= WINED3DPTEXTURECAPS_CUBEMAP |
2011 WINED3DPTEXTURECAPS_MIPCUBEMAP |
2012 WINED3DPTEXTURECAPS_CUBEMAP_POW2;
2016 *pCaps->TextureFilterCaps = WINED3DPTFILTERCAPS_MAGFLINEAR |
2017 WINED3DPTFILTERCAPS_MAGFPOINT |
2018 WINED3DPTFILTERCAPS_MINFLINEAR |
2019 WINED3DPTFILTERCAPS_MINFPOINT |
2020 WINED3DPTFILTERCAPS_MIPFLINEAR |
2021 WINED3DPTFILTERCAPS_MIPFPOINT |
2022 WINED3DPTFILTERCAPS_LINEAR |
2023 WINED3DPTFILTERCAPS_LINEARMIPLINEAR |
2024 WINED3DPTFILTERCAPS_LINEARMIPNEAREST |
2025 WINED3DPTFILTERCAPS_MIPLINEAR |
2026 WINED3DPTFILTERCAPS_MIPNEAREST |
2027 WINED3DPTFILTERCAPS_NEAREST;
2029 if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC)) {
2030 *pCaps->TextureFilterCaps |= WINED3DPTFILTERCAPS_MAGFANISOTROPIC |
2031 WINED3DPTFILTERCAPS_MINFANISOTROPIC;
2034 if (GL_SUPPORT(ARB_TEXTURE_CUBE_MAP)) {
2035 *pCaps->CubeTextureFilterCaps = WINED3DPTFILTERCAPS_MAGFLINEAR |
2036 WINED3DPTFILTERCAPS_MAGFPOINT |
2037 WINED3DPTFILTERCAPS_MINFLINEAR |
2038 WINED3DPTFILTERCAPS_MINFPOINT |
2039 WINED3DPTFILTERCAPS_MIPFLINEAR |
2040 WINED3DPTFILTERCAPS_MIPFPOINT |
2041 WINED3DPTFILTERCAPS_LINEAR |
2042 WINED3DPTFILTERCAPS_LINEARMIPLINEAR |
2043 WINED3DPTFILTERCAPS_LINEARMIPNEAREST |
2044 WINED3DPTFILTERCAPS_MIPLINEAR |
2045 WINED3DPTFILTERCAPS_MIPNEAREST |
2046 WINED3DPTFILTERCAPS_NEAREST;
2048 if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC)) {
2049 *pCaps->CubeTextureFilterCaps |= WINED3DPTFILTERCAPS_MAGFANISOTROPIC |
2050 WINED3DPTFILTERCAPS_MINFANISOTROPIC;
2052 } else
2053 *pCaps->CubeTextureFilterCaps = 0;
2055 if (GL_SUPPORT(EXT_TEXTURE3D)) {
2056 *pCaps->VolumeTextureFilterCaps = WINED3DPTFILTERCAPS_MAGFLINEAR |
2057 WINED3DPTFILTERCAPS_MAGFPOINT |
2058 WINED3DPTFILTERCAPS_MINFLINEAR |
2059 WINED3DPTFILTERCAPS_MINFPOINT |
2060 WINED3DPTFILTERCAPS_MIPFLINEAR |
2061 WINED3DPTFILTERCAPS_MIPFPOINT |
2062 WINED3DPTFILTERCAPS_LINEAR |
2063 WINED3DPTFILTERCAPS_LINEARMIPLINEAR |
2064 WINED3DPTFILTERCAPS_LINEARMIPNEAREST |
2065 WINED3DPTFILTERCAPS_MIPLINEAR |
2066 WINED3DPTFILTERCAPS_MIPNEAREST |
2067 WINED3DPTFILTERCAPS_NEAREST;
2068 } else
2069 *pCaps->VolumeTextureFilterCaps = 0;
2071 *pCaps->TextureAddressCaps = D3DPTADDRESSCAPS_INDEPENDENTUV |
2072 D3DPTADDRESSCAPS_CLAMP |
2073 D3DPTADDRESSCAPS_WRAP;
2075 if (GL_SUPPORT(ARB_TEXTURE_BORDER_CLAMP)) {
2076 *pCaps->TextureAddressCaps |= D3DPTADDRESSCAPS_BORDER;
2078 if (GL_SUPPORT(ARB_TEXTURE_MIRRORED_REPEAT)) {
2079 *pCaps->TextureAddressCaps |= D3DPTADDRESSCAPS_MIRROR;
2081 if (GL_SUPPORT(ATI_TEXTURE_MIRROR_ONCE)) {
2082 *pCaps->TextureAddressCaps |= D3DPTADDRESSCAPS_MIRRORONCE;
2085 if (GL_SUPPORT(EXT_TEXTURE3D)) {
2086 *pCaps->VolumeTextureAddressCaps = D3DPTADDRESSCAPS_INDEPENDENTUV |
2087 D3DPTADDRESSCAPS_CLAMP |
2088 D3DPTADDRESSCAPS_WRAP;
2089 if (GL_SUPPORT(ARB_TEXTURE_BORDER_CLAMP)) {
2090 *pCaps->VolumeTextureAddressCaps |= D3DPTADDRESSCAPS_BORDER;
2092 if (GL_SUPPORT(ARB_TEXTURE_MIRRORED_REPEAT)) {
2093 *pCaps->VolumeTextureAddressCaps |= D3DPTADDRESSCAPS_MIRROR;
2095 if (GL_SUPPORT(ATI_TEXTURE_MIRROR_ONCE)) {
2096 *pCaps->VolumeTextureAddressCaps |= D3DPTADDRESSCAPS_MIRRORONCE;
2098 } else
2099 *pCaps->VolumeTextureAddressCaps = 0;
2101 *pCaps->LineCaps = D3DLINECAPS_TEXTURE |
2102 D3DLINECAPS_ZTEST;
2103 /* FIXME: Add
2104 D3DLINECAPS_BLEND
2105 D3DLINECAPS_ALPHACMP
2106 D3DLINECAPS_FOG */
2108 *pCaps->MaxTextureWidth = GL_LIMITS(texture_size);
2109 *pCaps->MaxTextureHeight = GL_LIMITS(texture_size);
2111 if(GL_SUPPORT(EXT_TEXTURE3D))
2112 *pCaps->MaxVolumeExtent = GL_LIMITS(texture3d_size);
2113 else
2114 *pCaps->MaxVolumeExtent = 0;
2116 *pCaps->MaxTextureRepeat = 32768;
2117 *pCaps->MaxTextureAspectRatio = GL_LIMITS(texture_size);
2118 *pCaps->MaxVertexW = 1.0;
2120 *pCaps->GuardBandLeft = 0;
2121 *pCaps->GuardBandTop = 0;
2122 *pCaps->GuardBandRight = 0;
2123 *pCaps->GuardBandBottom = 0;
2125 *pCaps->ExtentsAdjust = 0;
2127 *pCaps->StencilCaps = D3DSTENCILCAPS_DECRSAT |
2128 D3DSTENCILCAPS_INCRSAT |
2129 D3DSTENCILCAPS_INVERT |
2130 D3DSTENCILCAPS_KEEP |
2131 D3DSTENCILCAPS_REPLACE |
2132 D3DSTENCILCAPS_ZERO;
2133 if (GL_SUPPORT(EXT_STENCIL_WRAP)) {
2134 *pCaps->StencilCaps |= D3DSTENCILCAPS_DECR |
2135 D3DSTENCILCAPS_INCR;
2137 if ( This->dxVersion > 8 &&
2138 ( GL_SUPPORT(EXT_STENCIL_TWO_SIDE) ||
2139 GL_SUPPORT(ATI_SEPARATE_STENCIL) ) ) {
2140 *pCaps->StencilCaps |= D3DSTENCILCAPS_TWOSIDED;
2143 *pCaps->FVFCaps = D3DFVFCAPS_PSIZE | 0x0008; /* 8 texture coords */
2145 *pCaps->TextureOpCaps = D3DTEXOPCAPS_ADD |
2146 D3DTEXOPCAPS_ADDSIGNED |
2147 D3DTEXOPCAPS_ADDSIGNED2X |
2148 D3DTEXOPCAPS_MODULATE |
2149 D3DTEXOPCAPS_MODULATE2X |
2150 D3DTEXOPCAPS_MODULATE4X |
2151 D3DTEXOPCAPS_SELECTARG1 |
2152 D3DTEXOPCAPS_SELECTARG2 |
2153 D3DTEXOPCAPS_DISABLE;
2155 if (GL_SUPPORT(ARB_TEXTURE_ENV_COMBINE) ||
2156 GL_SUPPORT(EXT_TEXTURE_ENV_COMBINE) ||
2157 GL_SUPPORT(NV_TEXTURE_ENV_COMBINE4)) {
2158 *pCaps->TextureOpCaps |= D3DTEXOPCAPS_BLENDDIFFUSEALPHA |
2159 D3DTEXOPCAPS_BLENDTEXTUREALPHA |
2160 D3DTEXOPCAPS_BLENDFACTORALPHA |
2161 D3DTEXOPCAPS_BLENDCURRENTALPHA |
2162 D3DTEXOPCAPS_LERP |
2163 D3DTEXOPCAPS_SUBTRACT;
2165 if (GL_SUPPORT(NV_TEXTURE_ENV_COMBINE4)) {
2166 *pCaps->TextureOpCaps |= D3DTEXOPCAPS_ADDSMOOTH |
2167 D3DTEXOPCAPS_MULTIPLYADD |
2168 D3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR |
2169 D3DTEXOPCAPS_MODULATECOLOR_ADDALPHA |
2170 D3DTEXOPCAPS_BLENDTEXTUREALPHAPM;
2172 if (GL_SUPPORT(ARB_TEXTURE_ENV_DOT3))
2173 *pCaps->TextureOpCaps |= D3DTEXOPCAPS_DOTPRODUCT3;
2175 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2176 *pCaps->TextureOpCaps |= D3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR |
2177 D3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA;
2181 #if 0
2182 *pCaps->TextureOpCaps |= D3DTEXOPCAPS_BUMPENVMAP;
2183 /* FIXME: Add
2184 D3DTEXOPCAPS_BUMPENVMAPLUMINANCE
2185 D3DTEXOPCAPS_PREMODULATE */
2186 #endif
2188 *pCaps->MaxTextureBlendStages = GL_LIMITS(texture_stages);
2189 *pCaps->MaxSimultaneousTextures = GL_LIMITS(textures);
2190 *pCaps->MaxUserClipPlanes = GL_LIMITS(clipplanes);
2191 *pCaps->MaxActiveLights = GL_LIMITS(lights);
2195 #if 0 /* TODO: Blends support in drawprim */
2196 *pCaps->MaxVertexBlendMatrices = GL_LIMITS(blends);
2197 #else
2198 *pCaps->MaxVertexBlendMatrices = 0;
2199 #endif
2200 *pCaps->MaxVertexBlendMatrixIndex = 1;
2202 *pCaps->MaxAnisotropy = GL_LIMITS(anisotropy);
2203 *pCaps->MaxPointSize = GL_LIMITS(pointsize);
2206 *pCaps->VertexProcessingCaps = WINED3DVTXPCAPS_DIRECTIONALLIGHTS |
2207 WINED3DVTXPCAPS_MATERIALSOURCE7 |
2208 WINED3DVTXPCAPS_POSITIONALLIGHTS |
2209 WINED3DVTXPCAPS_LOCALVIEWER |
2210 WINED3DVTXPCAPS_VERTEXFOG |
2211 WINED3DVTXPCAPS_TEXGEN;
2212 /* FIXME: Add
2213 D3DVTXPCAPS_TWEENING, D3DVTXPCAPS_TEXGEN_SPHEREMAP */
2215 *pCaps->MaxPrimitiveCount = 0xFFFFF; /* For now set 2^20-1 which is used by most >=Geforce3/Radeon8500 cards */
2216 *pCaps->MaxVertexIndex = 0xFFFFF;
2217 *pCaps->MaxStreams = MAX_STREAMS;
2218 *pCaps->MaxStreamStride = 1024;
2220 if (vs_selected_mode == SHADER_GLSL) {
2221 /* Nvidia Geforce6/7 or Ati R4xx/R5xx cards with GLSL support, support VS 3.0 but older Nvidia/Ati
2222 models with GLSL support only support 2.0. In case of nvidia we can detect VS 2.0 support using
2223 vs_nv_version which is based on NV_vertex_program. For Ati cards there's no easy way, so for
2224 now only support 2.0/3.0 detection on Nvidia GeforceFX cards and default to 3.0 for everything else */
2225 if(This->gl_info.vs_nv_version == VS_VERSION_20)
2226 *pCaps->VertexShaderVersion = WINED3DVS_VERSION(2,0);
2227 else
2228 *pCaps->VertexShaderVersion = WINED3DVS_VERSION(3,0);
2229 TRACE_(d3d_caps)("Hardware vertex shader version 3.0 enabled (GLSL)\n");
2230 } else if (vs_selected_mode == SHADER_ARB) {
2231 *pCaps->VertexShaderVersion = WINED3DVS_VERSION(1,1);
2232 TRACE_(d3d_caps)("Hardware vertex shader version 1.1 enabled (ARB_PROGRAM)\n");
2233 } else if (vs_selected_mode == SHADER_SW) {
2234 *pCaps->VertexShaderVersion = WINED3DVS_VERSION(3,0);
2235 TRACE_(d3d_caps)("Software vertex shader version 3.0 enabled\n");
2236 } else {
2237 *pCaps->VertexShaderVersion = 0;
2238 TRACE_(d3d_caps)("Vertex shader functionality not available\n");
2241 *pCaps->MaxVertexShaderConst = GL_LIMITS(vshader_constantsF);
2243 if (ps_selected_mode == SHADER_GLSL) {
2244 /* See the comment about VS2.0/VS3.0 detection as we do the same here but then based on NV_fragment_program
2245 in case of GeforceFX cards. */
2246 if(This->gl_info.ps_nv_version == PS_VERSION_20)
2247 *pCaps->PixelShaderVersion = WINED3DPS_VERSION(2,0);
2248 else
2249 *pCaps->PixelShaderVersion = WINED3DPS_VERSION(3,0);
2250 /* FIXME: The following line is card dependent. -1.0 to 1.0 is a safe default clamp range for now */
2251 *pCaps->PixelShader1xMaxValue = 1.0;
2252 TRACE_(d3d_caps)("Hardware pixel shader version 3.0 enabled (GLSL)\n");
2253 } else if (ps_selected_mode == SHADER_ARB) {
2254 *pCaps->PixelShaderVersion = WINED3DPS_VERSION(1,4);
2255 *pCaps->PixelShader1xMaxValue = 1.0;
2256 TRACE_(d3d_caps)("Hardware pixel shader version 1.4 enabled (ARB_PROGRAM)\n");
2257 /* FIXME: Uncomment this when there is support for software Pixel Shader 3.0 and PS_SW is defined
2258 } else if (ps_selected_mode = SHADER_SW) {
2259 *pCaps->PixelShaderVersion = WINED3DPS_VERSION(3,0);
2260 *pCaps->PixelShader1xMaxValue = 1.0;
2261 TRACE_(d3d_caps)("Software pixel shader version 3.0 enabled\n"); */
2262 } else {
2263 *pCaps->PixelShaderVersion = 0;
2264 *pCaps->PixelShader1xMaxValue = 0.0;
2265 TRACE_(d3d_caps)("Pixel shader functionality not available\n");
2268 /* ------------------------------------------------
2269 The following fields apply to d3d9 only
2270 ------------------------------------------------ */
2271 if (This->dxVersion > 8) {
2272 FIXME("Caps support for directx9 is nonexistent at the moment!\n");
2273 *pCaps->DevCaps2 = 0;
2274 /* TODO: D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES and VS3.0 needs at least D3DDEVCAPS2_VERTEXELEMENTSCANSHARESTREAMOFFSET */
2275 *pCaps->MaxNpatchTessellationLevel = 0;
2276 *pCaps->MasterAdapterOrdinal = 0;
2277 *pCaps->AdapterOrdinalInGroup = 0;
2278 *pCaps->NumberOfAdaptersInGroup = 1;
2280 if(*pCaps->VertexShaderVersion >= WINED3DVS_VERSION(2,0)) {
2281 /* OpenGL supports all formats below, perhaps not always without conversion but it supports them.
2282 Further GLSL doesn't seem to have an official unsigned type as I'm not sure how we handle it
2283 don't advertise it yet. We might need to add some clamping in the shader engine to support it.
2284 TODO: D3DDTCAPS_USHORT2N, D3DDTCAPS_USHORT4N, D3DDTCAPS_UDEC3, D3DDTCAPS_DEC3N */
2285 *pCaps->DeclTypes = D3DDTCAPS_UBYTE4 |
2286 D3DDTCAPS_UBYTE4N |
2287 D3DDTCAPS_SHORT2N |
2288 D3DDTCAPS_SHORT4N |
2289 D3DDTCAPS_FLOAT16_2 |
2290 D3DDTCAPS_FLOAT16_4;
2292 } else
2293 *pCaps->DeclTypes = 0;
2295 #if 0 /* We don't properly support multiple render targets yet, so disable this for now */
2296 if (GL_SUPPORT(ARB_DRAWBUFFERS)) {
2297 *pCaps->NumSimultaneousRTs = GL_LIMITS(buffers);
2298 } else
2299 #endif
2300 *pCaps->NumSimultaneousRTs = 1;
2302 *pCaps->StretchRectFilterCaps = 0;
2303 *pCaps->VertexTextureFilterCaps = 0;
2305 if(*pCaps->VertexShaderVersion == WINED3DVS_VERSION(3,0)) {
2306 /* Where possible set the caps based on OpenGL extensions and if they aren't set (in case of software rendering)
2307 use the VS 3.0 from MSDN or else if there's OpenGL spec use a hardcoded value minimum VS3.0 value. */
2308 *pCaps->VS20Caps.Caps = D3DVS20CAPS_PREDICATION;
2309 *pCaps->VS20Caps.DynamicFlowControlDepth = D3DVS20_MAX_DYNAMICFLOWCONTROLDEPTH; /* VS 3.0 requires MAX_DYNAMICFLOWCONTROLDEPTH (24) */
2310 *pCaps->VS20Caps.NumTemps = max(32, This->gl_info.vs_arb_max_temps);
2311 *pCaps->VS20Caps.StaticFlowControlDepth = D3DVS20_MAX_STATICFLOWCONTROLDEPTH ; /* level of nesting in loops / if-statements; VS 3.0 requires MAX (4) */
2313 *pCaps->MaxVShaderInstructionsExecuted = 65535; /* VS 3.0 needs at least 65535, some cards even use 2^32-1 */
2314 *pCaps->MaxVertexShader30InstructionSlots = max(512, This->gl_info.vs_arb_max_instructions);
2315 } else if(*pCaps->VertexShaderVersion == WINED3DVS_VERSION(2,0)) {
2316 *pCaps->VS20Caps.Caps = 0;
2317 *pCaps->VS20Caps.DynamicFlowControlDepth = D3DVS20_MIN_DYNAMICFLOWCONTROLDEPTH;
2318 *pCaps->VS20Caps.NumTemps = max(12, This->gl_info.vs_arb_max_temps);
2319 *pCaps->VS20Caps.StaticFlowControlDepth = 1;
2321 *pCaps->MaxVShaderInstructionsExecuted = 65535;
2322 *pCaps->MaxVertexShader30InstructionSlots = 0;
2323 } else { /* VS 1.x */
2324 *pCaps->VS20Caps.Caps = 0;
2325 *pCaps->VS20Caps.DynamicFlowControlDepth = 0;
2326 *pCaps->VS20Caps.NumTemps = 0;
2327 *pCaps->VS20Caps.StaticFlowControlDepth = 0;
2329 *pCaps->MaxVShaderInstructionsExecuted = 0;
2330 *pCaps->MaxVertexShader30InstructionSlots = 0;
2333 if(*pCaps->PixelShaderVersion == WINED3DPS_VERSION(3,0)) {
2334 /* Where possible set the caps based on OpenGL extensions and if they aren't set (in case of software rendering)
2335 use the PS 3.0 from MSDN or else if there's OpenGL spec use a hardcoded value minimum PS 3.0 value. */
2337 /* Caps is more or less undocumented on MSDN but it appears to be used for PS20Caps based on results from R9600/FX5900/Geforce6800 cards from Windows */
2338 *pCaps->PS20Caps.Caps = D3DPS20CAPS_ARBITRARYSWIZZLE |
2339 D3DPS20CAPS_GRADIENTINSTRUCTIONS |
2340 D3DPS20CAPS_PREDICATION |
2341 D3DPS20CAPS_NODEPENDENTREADLIMIT |
2342 D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT;
2343 *pCaps->PS20Caps.DynamicFlowControlDepth = D3DPS20_MAX_DYNAMICFLOWCONTROLDEPTH; /* PS 3.0 requires MAX_DYNAMICFLOWCONTROLDEPTH (24) */
2344 *pCaps->PS20Caps.NumTemps = max(32, This->gl_info.ps_arb_max_temps);
2345 *pCaps->PS20Caps.StaticFlowControlDepth = D3DPS20_MAX_STATICFLOWCONTROLDEPTH; /* PS 3.0 requires MAX_STATICFLOWCONTROLDEPTH (4) */
2346 *pCaps->PS20Caps.NumInstructionSlots = D3DPS20_MAX_NUMINSTRUCTIONSLOTS; /* PS 3.0 requires MAX_NUMINSTRUCTIONSLOTS (512) */
2348 *pCaps->MaxPShaderInstructionsExecuted = 65535;
2349 *pCaps->MaxPixelShader30InstructionSlots = max(D3DMIN30SHADERINSTRUCTIONS, This->gl_info.ps_arb_max_instructions);
2350 } else if(*pCaps->PixelShaderVersion == WINED3DPS_VERSION(2,0)) {
2351 /* Below we assume PS2.0 specs, not extended 2.0a(GeforceFX)/2.0b(Radeon R3xx) ones */
2352 *pCaps->PS20Caps.Caps = 0;
2353 *pCaps->PS20Caps.DynamicFlowControlDepth = 0; /* D3DVS20_MIN_DYNAMICFLOWCONTROLDEPTH = 0 */
2354 *pCaps->PS20Caps.NumTemps = max(12, This->gl_info.ps_arb_max_temps);
2355 *pCaps->PS20Caps.StaticFlowControlDepth = D3DPS20_MIN_STATICFLOWCONTROLDEPTH; /* Minumum: 1 */
2356 *pCaps->PS20Caps.NumInstructionSlots = D3DPS20_MIN_NUMINSTRUCTIONSLOTS; /* Minimum number (64 ALU + 32 Texture), a GeforceFX uses 512 */
2358 *pCaps->MaxPShaderInstructionsExecuted = 512; /* Minimum value, a GeforceFX uses 1024 */
2359 *pCaps->MaxPixelShader30InstructionSlots = 0;
2360 } else { /* PS 1.x */
2361 *pCaps->PS20Caps.Caps = 0;
2362 *pCaps->PS20Caps.DynamicFlowControlDepth = 0;
2363 *pCaps->PS20Caps.NumTemps = 0;
2364 *pCaps->PS20Caps.StaticFlowControlDepth = 0;
2365 *pCaps->PS20Caps.NumInstructionSlots = 0;
2367 *pCaps->MaxPShaderInstructionsExecuted = 0;
2368 *pCaps->MaxPixelShader30InstructionSlots = 0;
2372 return WINED3D_OK;
2376 /* Note due to structure differences between dx8 and dx9 D3DPRESENT_PARAMETERS,
2377 and fields being inserted in the middle, a new structure is used in place */
2378 static HRESULT WINAPI IWineD3DImpl_CreateDevice(IWineD3D *iface, UINT Adapter, WINED3DDEVTYPE DeviceType, HWND hFocusWindow,
2379 DWORD BehaviourFlags, IWineD3DDevice** ppReturnedDeviceInterface,
2380 IUnknown *parent) {
2382 IWineD3DDeviceImpl *object = NULL;
2383 IWineD3DImpl *This = (IWineD3DImpl *)iface;
2384 HDC hDC;
2385 HRESULT temp_result;
2387 /* Validate the adapter number */
2388 if (Adapter >= IWineD3D_GetAdapterCount(iface)) {
2389 return WINED3DERR_INVALIDCALL;
2392 /* Create a WineD3DDevice object */
2393 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DDeviceImpl));
2394 *ppReturnedDeviceInterface = (IWineD3DDevice *)object;
2395 TRACE("Created WineD3DDevice object @ %p\n", object);
2396 if (NULL == object) {
2397 return WINED3DERR_OUTOFVIDEOMEMORY;
2400 /* Set up initial COM information */
2401 object->lpVtbl = &IWineD3DDevice_Vtbl;
2402 object->ref = 1;
2403 object->wineD3D = iface;
2404 IWineD3D_AddRef(object->wineD3D);
2405 object->parent = parent;
2407 /* Set the state up as invalid until the device is fully created */
2408 object->state = WINED3DERR_DRIVERINTERNALERROR;
2410 TRACE("(%p)->(Adptr:%d, DevType: %x, FocusHwnd: %p, BehFlags: %x, RetDevInt: %p)\n", This, Adapter, DeviceType,
2411 hFocusWindow, BehaviourFlags, ppReturnedDeviceInterface);
2413 /* Save the creation parameters */
2414 object->createParms.AdapterOrdinal = Adapter;
2415 object->createParms.DeviceType = DeviceType;
2416 object->createParms.hFocusWindow = hFocusWindow;
2417 object->createParms.BehaviorFlags = BehaviourFlags;
2419 /* Initialize other useful values */
2420 object->adapterNo = Adapter;
2421 object->devType = DeviceType;
2423 TRACE("(%p) : Creating stateblock\n", This);
2424 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2425 if (WINED3D_OK != IWineD3DDevice_CreateStateBlock((IWineD3DDevice *)object,
2426 WINED3DSBT_INIT,
2427 (IWineD3DStateBlock **)&object->stateBlock,
2428 NULL) || NULL == object->stateBlock) { /* Note: No parent needed for initial internal stateblock */
2429 WARN("Failed to create stateblock\n");
2430 goto create_device_error;
2432 TRACE("(%p) : Created stateblock (%p)\n", This, object->stateBlock);
2433 object->updateStateBlock = object->stateBlock;
2434 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)object->updateStateBlock);
2435 /* Setup surfaces for the backbuffer, frontbuffer and depthstencil buffer */
2437 /* Setup some defaults for creating the implicit swapchain */
2438 ENTER_GL();
2439 /* FIXME: GL info should be per adapter */
2440 IWineD3DImpl_FillGLCaps(iface, IWineD3DImpl_GetAdapterDisplay(iface, Adapter));
2441 LEAVE_GL();
2442 select_shader_mode(&This->gl_info, DeviceType, &object->ps_selected_mode, &object->vs_selected_mode);
2443 if (object->ps_selected_mode == SHADER_GLSL || object->vs_selected_mode == SHADER_GLSL) {
2444 object->shader_backend = &glsl_shader_backend;
2445 } else if (object->ps_selected_mode == SHADER_ARB || object->vs_selected_mode == SHADER_ARB) {
2446 object->shader_backend = &arb_program_shader_backend;
2447 } else {
2448 object->shader_backend = &none_shader_backend;
2451 /* This function should *not* be modifying GL caps
2452 * TODO: move the functionality where it belongs */
2453 select_shader_max_constants(object->ps_selected_mode, object->vs_selected_mode, &This->gl_info);
2455 temp_result = allocate_shader_constants(object->updateStateBlock);
2456 if (WINED3D_OK != temp_result)
2457 return temp_result;
2459 /* set the state of the device to valid */
2460 object->state = WINED3D_OK;
2462 /* Get the initial screen setup for ddraw */
2463 object->ddraw_width = GetSystemMetrics(SM_CXSCREEN);
2464 object->ddraw_height = GetSystemMetrics(SM_CYSCREEN);
2465 hDC = CreateDCA("DISPLAY", NULL, NULL, NULL);
2466 object->ddraw_format = pixelformat_for_depth(GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES));
2467 DeleteDC(hDC);
2469 return WINED3D_OK;
2470 create_device_error:
2472 /* Set the device state to error */
2473 object->state = WINED3DERR_DRIVERINTERNALERROR;
2475 if (object->updateStateBlock != NULL) {
2476 IWineD3DStateBlock_Release((IWineD3DStateBlock *)object->updateStateBlock);
2477 object->updateStateBlock = NULL;
2479 if (object->stateBlock != NULL) {
2480 IWineD3DStateBlock_Release((IWineD3DStateBlock *)object->stateBlock);
2481 object->stateBlock = NULL;
2483 if (object->renderTarget != NULL) {
2484 IWineD3DSurface_Release(object->renderTarget);
2485 object->renderTarget = NULL;
2487 if (object->stencilBufferTarget != NULL) {
2488 IWineD3DSurface_Release(object->stencilBufferTarget);
2489 object->stencilBufferTarget = NULL;
2491 HeapFree(GetProcessHeap(), 0, object);
2492 *ppReturnedDeviceInterface = NULL;
2493 return WINED3DERR_INVALIDCALL;
2497 static HRESULT WINAPI IWineD3DImpl_GetParent(IWineD3D *iface, IUnknown **pParent) {
2498 IWineD3DImpl *This = (IWineD3DImpl *)iface;
2499 IUnknown_AddRef(This->parent);
2500 *pParent = This->parent;
2501 return WINED3D_OK;
2504 /**********************************************************
2505 * IWineD3D VTbl follows
2506 **********************************************************/
2508 const IWineD3DVtbl IWineD3D_Vtbl =
2510 /* IUnknown */
2511 IWineD3DImpl_QueryInterface,
2512 IWineD3DImpl_AddRef,
2513 IWineD3DImpl_Release,
2514 /* IWineD3D */
2515 IWineD3DImpl_GetParent,
2516 IWineD3DImpl_GetAdapterCount,
2517 IWineD3DImpl_RegisterSoftwareDevice,
2518 IWineD3DImpl_GetAdapterMonitor,
2519 IWineD3DImpl_GetAdapterModeCount,
2520 IWineD3DImpl_EnumAdapterModes,
2521 IWineD3DImpl_GetAdapterDisplayMode,
2522 IWineD3DImpl_GetAdapterIdentifier,
2523 IWineD3DImpl_CheckDeviceMultiSampleType,
2524 IWineD3DImpl_CheckDepthStencilMatch,
2525 IWineD3DImpl_CheckDeviceType,
2526 IWineD3DImpl_CheckDeviceFormat,
2527 IWineD3DImpl_CheckDeviceFormatConversion,
2528 IWineD3DImpl_GetDeviceCaps,
2529 IWineD3DImpl_CreateDevice